pystatistics 2.3.0__tar.gz → 3.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (555) hide show
  1. pystatistics-3.0.1/.release/CHECKLIST.md +84 -0
  2. pystatistics-3.0.1/.release/release.py +312 -0
  3. {pystatistics-2.3.0 → pystatistics-3.0.1}/CHANGELOG.md +177 -0
  4. {pystatistics-2.3.0 → pystatistics-3.0.1}/CLAUDE.md +87 -0
  5. {pystatistics-2.3.0 → pystatistics-3.0.1}/PKG-INFO +168 -359
  6. pystatistics-3.0.1/README.md +459 -0
  7. {pystatistics-2.3.0 → pystatistics-3.0.1}/pyproject.toml +2 -8
  8. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/__init__.py +1 -1
  9. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/backends/gpu_pirls.py +86 -3
  10. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/__init__.py +0 -2
  11. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/_em_batched.py +9 -8
  12. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/_em_batched_np.py +5 -117
  13. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/_em_batched_torch.py +5 -111
  14. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/em.py +5 -5
  15. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/mcar_test.py +7 -310
  16. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/gam/test_gam.py +33 -1
  17. pystatistics-2.3.0/.release/CHECKLIST.md +0 -38
  18. pystatistics-2.3.0/.release/release.py +0 -439
  19. pystatistics-2.3.0/README.md +0 -648
  20. pystatistics-2.3.0/pystatistics/nonparametric_mcar/__init__.py +0 -45
  21. pystatistics-2.3.0/pystatistics/nonparametric_mcar/hsic.py +0 -237
  22. pystatistics-2.3.0/pystatistics/nonparametric_mcar/missmech.py +0 -254
  23. pystatistics-2.3.0/pystatistics/nonparametric_mcar/propensity.py +0 -285
  24. pystatistics-2.3.0/pystatistics/nonparametric_mcar/result.py +0 -67
  25. pystatistics-2.3.0/tests/mvnmle/test_mom_mcar.py +0 -169
  26. pystatistics-2.3.0/tests/nonparametric_mcar/test_hsic.py +0 -112
  27. pystatistics-2.3.0/tests/nonparametric_mcar/test_missmech.py +0 -110
  28. pystatistics-2.3.0/tests/nonparametric_mcar/test_propensity.py +0 -145
  29. pystatistics-2.3.0/tests/timeseries/__init__.py +0 -0
  30. {pystatistics-2.3.0 → pystatistics-3.0.1}/.github/workflows/publish.yml +0 -0
  31. {pystatistics-2.3.0 → pystatistics-3.0.1}/.github/workflows/trigger-docs-rebuild.yml +0 -0
  32. {pystatistics-2.3.0 → pystatistics-3.0.1}/.gitignore +0 -0
  33. {pystatistics-2.3.0 → pystatistics-3.0.1}/.release/UNRELEASED.md +0 -0
  34. {pystatistics-2.3.0 → pystatistics-3.0.1}/LICENSE +0 -0
  35. {pystatistics-2.3.0 → pystatistics-3.0.1}/benchmarks/mvnmle_bench.py +0 -0
  36. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/DESIGN.md +0 -0
  37. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/Forge.md +0 -0
  38. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/GPU_BACKEND_NOTES.md +0 -0
  39. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/Makefile +0 -0
  40. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/PYSTATSBIO_CONTEXT.md +0 -0
  41. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/ROADMAP.md +0 -0
  42. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/_static/custom.css +0 -0
  43. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/anova.rst +0 -0
  44. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/conf.py +0 -0
  45. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/core.rst +0 -0
  46. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/descriptive.rst +0 -0
  47. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/hypothesis.rst +0 -0
  48. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/index.rst +0 -0
  49. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/mixed.rst +0 -0
  50. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/montecarlo.rst +0 -0
  51. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/mvnmle.rst +0 -0
  52. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/regression.rst +0 -0
  53. {pystatistics-2.3.0 → pystatistics-3.0.1}/docs/survival.rst +0 -0
  54. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/GPU_BACKEND_CONVENTION.md +0 -0
  55. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/__init__.py +0 -0
  56. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/_common.py +0 -0
  57. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/_contrasts.py +0 -0
  58. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/_levene.py +0 -0
  59. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/_posthoc.py +0 -0
  60. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/_repeated.py +0 -0
  61. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/_ss.py +0 -0
  62. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/design.py +0 -0
  63. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/solution.py +0 -0
  64. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/anova/solvers.py +0 -0
  65. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/__init__.py +0 -0
  66. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/capabilities.py +0 -0
  67. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/__init__.py +0 -0
  68. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/device.py +0 -0
  69. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/linalg/__init__.py +0 -0
  70. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/linalg/batched.py +0 -0
  71. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/linalg/cholesky.py +0 -0
  72. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/linalg/determinant.py +0 -0
  73. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/linalg/qr.py +0 -0
  74. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/linalg/solve.py +0 -0
  75. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/linalg/svd.py +0 -0
  76. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/optimization/__init__.py +0 -0
  77. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/optimization/convergence.py +0 -0
  78. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/precision.py +0 -0
  79. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/timing.py +0 -0
  80. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/compute/tolerances.py +0 -0
  81. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/datasource.py +0 -0
  82. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/exceptions.py +0 -0
  83. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/protocols.py +0 -0
  84. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/result.py +0 -0
  85. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/core/validation.py +0 -0
  86. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/__init__.py +0 -0
  87. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/_missing.py +0 -0
  88. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/_quantile_types.py +0 -0
  89. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/backends/__init__.py +0 -0
  90. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/backends/cpu.py +0 -0
  91. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/backends/gpu.py +0 -0
  92. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/design.py +0 -0
  93. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/solution.py +0 -0
  94. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/descriptive/solvers.py +0 -0
  95. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/__init__.py +0 -0
  96. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/_basis.py +0 -0
  97. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/_common.py +0 -0
  98. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/_fit.py +0 -0
  99. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/_gam.py +0 -0
  100. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/_gcv.py +0 -0
  101. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/_smooth.py +0 -0
  102. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/backends/__init__.py +0 -0
  103. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/backends/_gpu_family.py +0 -0
  104. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/gam/solution.py +0 -0
  105. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/__init__.py +0 -0
  106. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/_common.py +0 -0
  107. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/_design_factories.py +0 -0
  108. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/_p_adjust.py +0 -0
  109. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/__init__.py +0 -0
  110. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/_chisq_test.py +0 -0
  111. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/_fisher_test.py +0 -0
  112. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/_ks_test.py +0 -0
  113. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/_prop_test.py +0 -0
  114. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/_t_test.py +0 -0
  115. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/_var_test.py +0 -0
  116. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/_wilcox_test.py +0 -0
  117. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/cpu.py +0 -0
  118. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/backends/gpu.py +0 -0
  119. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/design.py +0 -0
  120. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/solution.py +0 -0
  121. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/hypothesis/solvers.py +0 -0
  122. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/__init__.py +0 -0
  123. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/_common.py +0 -0
  124. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/_deviance.py +0 -0
  125. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/_pirls.py +0 -0
  126. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/_pls.py +0 -0
  127. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/_random_effects.py +0 -0
  128. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/_satterthwaite.py +0 -0
  129. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/design.py +0 -0
  130. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/solution.py +0 -0
  131. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mixed/solvers.py +0 -0
  132. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/__init__.py +0 -0
  133. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/_ci.py +0 -0
  134. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/_common.py +0 -0
  135. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/_influence.py +0 -0
  136. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/backends/__init__.py +0 -0
  137. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/backends/cpu.py +0 -0
  138. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/backends/gpu.py +0 -0
  139. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/design.py +0 -0
  140. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/solution.py +0 -0
  141. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/montecarlo/solvers.py +0 -0
  142. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multinomial/__init__.py +0 -0
  143. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multinomial/_common.py +0 -0
  144. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multinomial/_likelihood.py +0 -0
  145. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multinomial/_solver.py +0 -0
  146. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multinomial/backends/__init__.py +0 -0
  147. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multinomial/backends/gpu_likelihood.py +0 -0
  148. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multinomial/solution.py +0 -0
  149. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multivariate/__init__.py +0 -0
  150. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multivariate/_common.py +0 -0
  151. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multivariate/_factor.py +0 -0
  152. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multivariate/_pca.py +0 -0
  153. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multivariate/_rotation.py +0 -0
  154. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multivariate/backends/__init__.py +0 -0
  155. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/multivariate/backends/gpu_pca.py +0 -0
  156. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_monotone.py +0 -0
  157. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_objectives/__init__.py +0 -0
  158. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_objectives/base.py +0 -0
  159. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_objectives/cpu.py +0 -0
  160. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_objectives/gpu_fp32.py +0 -0
  161. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_objectives/gpu_fp64.py +0 -0
  162. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_objectives/parameterizations.py +0 -0
  163. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/_utils.py +0 -0
  164. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/__init__.py +0 -0
  165. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/_em_batched_patterns.py +0 -0
  166. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/_squarem.py +0 -0
  167. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/cpu.py +0 -0
  168. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/backends/gpu.py +0 -0
  169. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/datasets.py +0 -0
  170. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/design.py +0 -0
  171. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/patterns.py +0 -0
  172. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/solution.py +0 -0
  173. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/mvnmle/solvers.py +0 -0
  174. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/ordinal/__init__.py +0 -0
  175. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/ordinal/_common.py +0 -0
  176. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/ordinal/_likelihood.py +0 -0
  177. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/ordinal/_solver.py +0 -0
  178. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/ordinal/backends/__init__.py +0 -0
  179. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/ordinal/backends/gpu_likelihood.py +0 -0
  180. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/ordinal/solution.py +0 -0
  181. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/py.typed +0 -0
  182. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/__init__.py +0 -0
  183. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/_formatting.py +0 -0
  184. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/_glm.py +0 -0
  185. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/_linear.py +0 -0
  186. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/_nb_theta.py +0 -0
  187. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/backends/__init__.py +0 -0
  188. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/backends/cpu.py +0 -0
  189. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/backends/cpu_glm.py +0 -0
  190. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/backends/gpu.py +0 -0
  191. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/backends/gpu_glm.py +0 -0
  192. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/design.py +0 -0
  193. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/families.py +0 -0
  194. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/solution.py +0 -0
  195. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/regression/solvers.py +0 -0
  196. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/__init__.py +0 -0
  197. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/_common.py +0 -0
  198. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/_cox.py +0 -0
  199. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/_discrete.py +0 -0
  200. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/_km.py +0 -0
  201. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/_logrank.py +0 -0
  202. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/backends/__init__.py +0 -0
  203. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/backends/cpu.py +0 -0
  204. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/backends/gpu.py +0 -0
  205. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/design.py +0 -0
  206. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/solution.py +0 -0
  207. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/survival/solvers.py +0 -0
  208. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/__init__.py +0 -0
  209. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_acf.py +0 -0
  210. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_arima_batch.py +0 -0
  211. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_arima_factored.py +0 -0
  212. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_arima_fit.py +0 -0
  213. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_arima_forecast.py +0 -0
  214. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_arima_kalman.py +0 -0
  215. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_arima_likelihood.py +0 -0
  216. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_arima_order.py +0 -0
  217. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_common.py +0 -0
  218. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_decomposition.py +0 -0
  219. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_differencing.py +0 -0
  220. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_ets_fit.py +0 -0
  221. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_ets_forecast.py +0 -0
  222. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_ets_models.py +0 -0
  223. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_stationarity.py +0 -0
  224. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/_whittle.py +0 -0
  225. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/backends/__init__.py +0 -0
  226. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/backends/whittle_batch_gpu.py +0 -0
  227. {pystatistics-2.3.0 → pystatistics-3.0.1}/pystatistics/timeseries/backends/whittle_gpu.py +0 -0
  228. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/__init__.py +0 -0
  229. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/conftest.py +0 -0
  230. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_contrasts.py +0 -0
  231. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_design.py +0 -0
  232. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_factorial.py +0 -0
  233. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_levene.py +0 -0
  234. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_oneway.py +0 -0
  235. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_posthoc.py +0 -0
  236. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_r_validation.py +0 -0
  237. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/anova/test_repeated_measures.py +0 -0
  238. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/benchmark_gpu.py +0 -0
  239. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/conftest.py +0 -0
  240. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/core/test_datasource.py +0 -0
  241. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/core/test_exceptions.py +0 -0
  242. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/core/test_result.py +0 -0
  243. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/core/test_validation.py +0 -0
  244. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/__init__.py +0 -0
  245. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/conftest.py +0 -0
  246. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_cor.py +0 -0
  247. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_cov.py +0 -0
  248. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_describe.py +0 -0
  249. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_gpu.py +0 -0
  250. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_missing.py +0 -0
  251. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_moments.py +0 -0
  252. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_quantile.py +0 -0
  253. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/descriptive/test_r_validation.py +0 -0
  254. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_ancova_meta.json +0 -0
  255. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_ancova_r_results.json +0 -0
  256. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_bonferroni_meta.json +0 -0
  257. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_bonferroni_r_results.json +0 -0
  258. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_eta_meta.json +0 -0
  259. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_eta_r_results.json +0 -0
  260. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_levene_meta.json +0 -0
  261. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_levene_r_results.json +0 -0
  262. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_oneway_balanced_meta.json +0 -0
  263. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_oneway_balanced_r_results.json +0 -0
  264. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_oneway_unbalanced_meta.json +0 -0
  265. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_oneway_unbalanced_r_results.json +0 -0
  266. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_rm_mixed_meta.json +0 -0
  267. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_rm_mixed_r_results.json +0 -0
  268. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_rm_within_meta.json +0 -0
  269. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_rm_within_r_results.json +0 -0
  270. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_tukey_meta.json +0 -0
  271. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_tukey_r_results.json +0 -0
  272. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_twoway_balanced_meta.json +0 -0
  273. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_twoway_balanced_r_results.json +0 -0
  274. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_twoway_unbalanced_meta.json +0 -0
  275. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/anova_twoway_unbalanced_r_results.json +0 -0
  276. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/basic_100x3.csv +0 -0
  277. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/basic_100x3_meta.json +0 -0
  278. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/basic_100x3_r_results.json +0 -0
  279. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/collinear_almost.csv +0 -0
  280. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/collinear_almost_meta.json +0 -0
  281. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/collinear_almost_r_results.json +0 -0
  282. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_basic_100x5.csv +0 -0
  283. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_basic_100x5_meta.json +0 -0
  284. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_basic_100x5_r_results.json +0 -0
  285. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_constant_column.csv +0 -0
  286. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_constant_column_meta.json +0 -0
  287. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_constant_column_r_results.json +0 -0
  288. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_extreme_values.csv +0 -0
  289. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_extreme_values_meta.json +0 -0
  290. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_extreme_values_r_results.json +0 -0
  291. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_large_1000x10.csv +0 -0
  292. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_large_1000x10_meta.json +0 -0
  293. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_large_1000x10_r_results.json +0 -0
  294. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_nan_columnwise.csv +0 -0
  295. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_nan_columnwise_meta.json +0 -0
  296. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_nan_columnwise_r_results.json +0 -0
  297. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_nan_scattered.csv +0 -0
  298. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_nan_scattered_meta.json +0 -0
  299. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_nan_scattered_r_results.json +0 -0
  300. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_negative_correlation.csv +0 -0
  301. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_negative_correlation_meta.json +0 -0
  302. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_negative_correlation_r_results.json +0 -0
  303. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_perfect_correlation.csv +0 -0
  304. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_perfect_correlation_meta.json +0 -0
  305. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_perfect_correlation_r_results.json +0 -0
  306. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_single_column.csv +0 -0
  307. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_single_column_meta.json +0 -0
  308. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_single_column_r_results.json +0 -0
  309. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_ties.csv +0 -0
  310. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_ties_meta.json +0 -0
  311. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/desc_ties_r_results.json +0 -0
  312. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/different_scales.csv +0 -0
  313. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/different_scales_meta.json +0 -0
  314. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/different_scales_r_results.json +0 -0
  315. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_anova_fixtures.py +0 -0
  316. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_descriptive_fixtures.py +0 -0
  317. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_fixtures.py +0 -0
  318. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_glm_fixtures.py +0 -0
  319. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_hypothesis_fixtures.py +0 -0
  320. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_mixed_fixtures.py +0 -0
  321. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_montecarlo_fixtures.py +0 -0
  322. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/generate_survival_fixtures.py +0 -0
  323. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_balanced.csv +0 -0
  324. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_balanced_meta.json +0 -0
  325. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_balanced_r_results.json +0 -0
  326. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_basic.csv +0 -0
  327. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_basic_meta.json +0 -0
  328. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_basic_r_results.json +0 -0
  329. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_large.csv +0 -0
  330. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_large_meta.json +0 -0
  331. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_large_r_results.json +0 -0
  332. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_separated.csv +0 -0
  333. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_separated_meta.json +0 -0
  334. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_binomial_separated_r_results.json +0 -0
  335. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_gaussian_basic.csv +0 -0
  336. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_gaussian_basic_meta.json +0 -0
  337. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_gaussian_basic_r_results.json +0 -0
  338. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_gaussian_large.csv +0 -0
  339. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_gaussian_large_meta.json +0 -0
  340. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_gaussian_large_r_results.json +0 -0
  341. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_basic.csv +0 -0
  342. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_basic_meta.json +0 -0
  343. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_basic_r_results.json +0 -0
  344. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_large_counts.csv +0 -0
  345. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_large_counts_meta.json +0 -0
  346. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_large_counts_r_results.json +0 -0
  347. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_zeros.csv +0 -0
  348. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_zeros_meta.json +0 -0
  349. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/glm_poisson_zeros_r_results.json +0 -0
  350. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/high_noise.csv +0 -0
  351. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/high_noise_meta.json +0 -0
  352. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/high_noise_r_results.json +0 -0
  353. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_2x2_yates_meta.json +0 -0
  354. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_2x2_yates_r_results.json +0 -0
  355. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_3x3_meta.json +0 -0
  356. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_3x3_r_results.json +0 -0
  357. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_gof_meta.json +0 -0
  358. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_gof_r_results.json +0 -0
  359. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_gof_unequal_meta.json +0 -0
  360. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_chisq_gof_unequal_r_results.json +0 -0
  361. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_fisher_2x2_less_meta.json +0 -0
  362. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_fisher_2x2_less_r_results.json +0 -0
  363. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_fisher_2x2_meta.json +0 -0
  364. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_fisher_2x2_r_results.json +0 -0
  365. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_fisher_3x3_meta.json +0 -0
  366. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_fisher_3x3_r_results.json +0 -0
  367. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_ks_onesample_norm_meta.json +0 -0
  368. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_ks_onesample_norm_r_results.json +0 -0
  369. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_ks_twosample_meta.json +0 -0
  370. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_ks_twosample_r_results.json +0 -0
  371. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_prop_onesample_meta.json +0 -0
  372. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_prop_onesample_r_results.json +0 -0
  373. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_prop_twosample_meta.json +0 -0
  374. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_prop_twosample_r_results.json +0 -0
  375. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_onesample_meta.json +0 -0
  376. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_onesample_r_results.json +0 -0
  377. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_paired_meta.json +0 -0
  378. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_paired_r_results.json +0 -0
  379. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_pooled_meta.json +0 -0
  380. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_pooled_r_results.json +0 -0
  381. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_welch_meta.json +0 -0
  382. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_t_welch_r_results.json +0 -0
  383. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_var_basic_meta.json +0 -0
  384. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_var_basic_r_results.json +0 -0
  385. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_wilcox_ranksum_meta.json +0 -0
  386. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_wilcox_ranksum_r_results.json +0 -0
  387. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_wilcox_signed_meta.json +0 -0
  388. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/htest_wilcox_signed_r_results.json +0 -0
  389. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/ill_conditioned.csv +0 -0
  390. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/ill_conditioned_meta.json +0 -0
  391. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/ill_conditioned_r_results.json +0 -0
  392. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/large_coeffs.csv +0 -0
  393. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/large_coeffs_meta.json +0 -0
  394. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/large_coeffs_r_results.json +0 -0
  395. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_ci_90_meta.json +0 -0
  396. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_ci_90_r_results.json +0 -0
  397. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_ci_normal_meta.json +0 -0
  398. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_ci_normal_r_results.json +0 -0
  399. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_ci_skewed_meta.json +0 -0
  400. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_ci_skewed_r_results.json +0 -0
  401. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_mean_balanced_meta.json +0 -0
  402. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_mean_balanced_r_results.json +0 -0
  403. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_mean_ordinary_meta.json +0 -0
  404. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_mean_ordinary_r_results.json +0 -0
  405. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_median_meta.json +0 -0
  406. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_median_r_results.json +0 -0
  407. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_variance_meta.json +0 -0
  408. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_boot_variance_r_results.json +0 -0
  409. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_perm_greater_meta.json +0 -0
  410. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_perm_greater_r_results.json +0 -0
  411. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_perm_not_significant_meta.json +0 -0
  412. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_perm_not_significant_r_results.json +0 -0
  413. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_perm_significant_meta.json +0 -0
  414. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mc_perm_significant_r_results.json +0 -0
  415. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/glmm_binomial.csv +0 -0
  416. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/glmm_poisson.csv +0 -0
  417. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/lmm_crossed.csv +0 -0
  418. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/lmm_intercept.csv +0 -0
  419. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/lmm_ml.csv +0 -0
  420. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/lmm_no_effect.csv +0 -0
  421. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/lmm_slope.csv +0 -0
  422. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/mixed_meta.json +0 -0
  423. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/mixed/mixed_r_results.json +0 -0
  424. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/near_square.csv +0 -0
  425. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/near_square_meta.json +0 -0
  426. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/near_square_r_results.json +0 -0
  427. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/no_intercept.csv +0 -0
  428. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/no_intercept_meta.json +0 -0
  429. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/no_intercept_r_results.json +0 -0
  430. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_anova_validation.R +0 -0
  431. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_descriptive_validation.R +0 -0
  432. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_glm_validation.R +0 -0
  433. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_hypothesis_validation.R +0 -0
  434. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_mixed_validation.R +0 -0
  435. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_montecarlo_validation.R +0 -0
  436. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_survival_validation.R +0 -0
  437. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_r_validation.R +0 -0
  438. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/run_validation.sh +0 -0
  439. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/small_noise.csv +0 -0
  440. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/small_noise_meta.json +0 -0
  441. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/small_noise_r_results.json +0 -0
  442. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_breslow_meta.json +0 -0
  443. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_breslow_r_results.json +0 -0
  444. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_single_meta.json +0 -0
  445. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_single_r_results.json +0 -0
  446. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_ties_meta.json +0 -0
  447. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_ties_r_results.json +0 -0
  448. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_two_cov_meta.json +0 -0
  449. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_cox_two_cov_r_results.json +0 -0
  450. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_basic_meta.json +0 -0
  451. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_basic_r_results.json +0 -0
  452. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_heavy_cens_meta.json +0 -0
  453. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_heavy_cens_r_results.json +0 -0
  454. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_loglog_ci_meta.json +0 -0
  455. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_loglog_ci_r_results.json +0 -0
  456. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_no_cens_meta.json +0 -0
  457. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_no_cens_r_results.json +0 -0
  458. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_plain_ci_meta.json +0 -0
  459. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_plain_ci_r_results.json +0 -0
  460. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_ties_meta.json +0 -0
  461. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_km_ties_r_results.json +0 -0
  462. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_lr_peto_meta.json +0 -0
  463. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_lr_peto_r_results.json +0 -0
  464. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_lr_three_group_meta.json +0 -0
  465. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_lr_three_group_r_results.json +0 -0
  466. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_lr_two_group_meta.json +0 -0
  467. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/surv_lr_two_group_r_results.json +0 -0
  468. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/tall_skinny.csv +0 -0
  469. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/tall_skinny_meta.json +0 -0
  470. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/tall_skinny_r_results.json +0 -0
  471. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/fixtures/validate_against_r.py +0 -0
  472. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/gam/__init__.py +0 -0
  473. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/__init__.py +0 -0
  474. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/conftest.py +0 -0
  475. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_chisq_test.py +0 -0
  476. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_design_split.py +0 -0
  477. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_fisher_test.py +0 -0
  478. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_gpu.py +0 -0
  479. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_ks_test.py +0 -0
  480. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_p_adjust.py +0 -0
  481. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_prop_test.py +0 -0
  482. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_r_validation.py +0 -0
  483. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_t_test.py +0 -0
  484. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_var_test.py +0 -0
  485. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/hypothesis/test_wilcox_test.py +0 -0
  486. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/__init__.py +0 -0
  487. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/conftest.py +0 -0
  488. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_glmm.py +0 -0
  489. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_lmm_crossed.py +0 -0
  490. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_lmm_intercept.py +0 -0
  491. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_lmm_nested.py +0 -0
  492. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_lmm_slope.py +0 -0
  493. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_pls.py +0 -0
  494. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_r_validation.py +0 -0
  495. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_random_effects.py +0 -0
  496. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mixed/test_satterthwaite.py +0 -0
  497. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/__init__.py +0 -0
  498. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/conftest.py +0 -0
  499. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/test_batched_solver.py +0 -0
  500. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/test_boot_ci.py +0 -0
  501. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/test_bootstrap.py +0 -0
  502. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/test_gpu.py +0 -0
  503. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/test_influence.py +0 -0
  504. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/test_permutation.py +0 -0
  505. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/montecarlo/test_r_validation.py +0 -0
  506. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/multinomial/__init__.py +0 -0
  507. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/multinomial/test_multinom.py +0 -0
  508. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/multivariate/__init__.py +0 -0
  509. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/multivariate/test_multivariate.py +0 -0
  510. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/apple_em_reference.json +0 -0
  511. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/apple_reference.json +0 -0
  512. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/generate_em_fixtures.R +0 -0
  513. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/little_mcar_apple.json +0 -0
  514. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/little_mcar_complete.json +0 -0
  515. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/little_mcar_extreme.json +0 -0
  516. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/little_mcar_missvals.json +0 -0
  517. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/little_mcar_simple_mcar.json +0 -0
  518. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/little_mcar_summary.json +0 -0
  519. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/missvals_em_reference.json +0 -0
  520. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/missvals_reference.json +0 -0
  521. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/references/small_test_reference.json +0 -0
  522. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/test_em.py +0 -0
  523. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/test_gpu.py +0 -0
  524. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/test_mcar.py +0 -0
  525. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/test_mlest.py +0 -0
  526. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/test_monotone.py +0 -0
  527. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/test_no_silent_fallback.py +0 -0
  528. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/mvnmle/test_squarem.py +0 -0
  529. {pystatistics-2.3.0/tests/nonparametric_mcar → pystatistics-3.0.1/tests/ordinal}/__init__.py +0 -0
  530. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/ordinal/test_ordinal.py +0 -0
  531. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/benchmark.py +0 -0
  532. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/benchmark.r +0 -0
  533. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/conftest.py +0 -0
  534. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_fit.py +0 -0
  535. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_gamma_nb.py +0 -0
  536. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_glm.py +0 -0
  537. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_glm_gpu.py +0 -0
  538. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_glm_r_validation.py +0 -0
  539. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_module_split.py +0 -0
  540. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_r_validation.py +0 -0
  541. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/regression/test_stress_gpu.py +0 -0
  542. {pystatistics-2.3.0/tests/ordinal → pystatistics-3.0.1/tests/survival}/__init__.py +0 -0
  543. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/survival/conftest.py +0 -0
  544. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/survival/test_coxph.py +0 -0
  545. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/survival/test_discrete_time.py +0 -0
  546. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/survival/test_gpu.py +0 -0
  547. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/survival/test_kaplan_meier.py +0 -0
  548. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/survival/test_logrank.py +0 -0
  549. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/survival/test_r_validation.py +0 -0
  550. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/test_code_quality.py +0 -0
  551. {pystatistics-2.3.0/tests/survival → pystatistics-3.0.1/tests/timeseries}/__init__.py +0 -0
  552. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/timeseries/test_acf_stationarity.py +0 -0
  553. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/timeseries/test_arima.py +0 -0
  554. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/timeseries/test_decomposition.py +0 -0
  555. {pystatistics-2.3.0 → pystatistics-3.0.1}/tests/timeseries/test_ets.py +0 -0
@@ -0,0 +1,84 @@
1
+ # Release Checklist
2
+
3
+ > `release.py` only automates the version bump in `pyproject.toml` and
4
+ > `<package>/__init__.py`. Everything else is by hand — on purpose.
5
+ > The CHANGELOG entry in particular is authorship work, not mechanical:
6
+ > `UNRELEASED.md` is written in internal voice, `CHANGELOG.md` is public.
7
+
8
+ ## Release flow
9
+
10
+ 1. **Sanity check:** `python .release/release.py --status`
11
+
12
+ 2. **Write the `CHANGELOG.md` entry by hand.** Open `UNRELEASED.md` for
13
+ reference, then translate it into user-facing prose at the top of
14
+ `CHANGELOG.md` under `## X.Y.Z`. Do NOT copy verbatim. Strip:
15
+ - internal rule numbers (e.g. "Rule 9", "Rule 10")
16
+ - internal project names
17
+ - test counts / coverage numbers / process rationale
18
+ - references to `CLAUDE.md` by name or implication
19
+
20
+ Keep:
21
+ - API additions / removals
22
+ - behaviour changes a user would notice
23
+ - bug fixes (in terms of the user-visible symptom)
24
+ - performance numbers (with shape context)
25
+
26
+ 3. **Update `README.md` "What's New".** Same translation rules as the
27
+ CHANGELOG. The README should lead with library identity; the changelog
28
+ lives near the bottom.
29
+
30
+ 4. **Bump versions:** `python .release/release.py --bump X.Y.Z` — this
31
+ only touches `pyproject.toml` and `<package>/__init__.py`.
32
+
33
+ 5. **Review:** `git diff`
34
+
35
+ 6. **Commit and tag:**
36
+ ```
37
+ git add pyproject.toml <package>/__init__.py CHANGELOG.md README.md
38
+ git commit -m "Release X.Y.Z"
39
+ git tag vX.Y.Z
40
+ git push origin <branch>
41
+ git push origin vX.Y.Z
42
+ ```
43
+
44
+ 7. **Reset UNRELEASED.md** — only now, after the release commit is in:
45
+ ```
46
+ python .release/release.py --reset-unreleased
47
+ git add .release/UNRELEASED.md
48
+ git commit -m "Reset UNRELEASED.md for next cycle"
49
+ git push
50
+ ```
51
+
52
+ 8. **Publish to PyPI via GitHub release:**
53
+ ```
54
+ gh release create vX.Y.Z --title 'vX.Y.Z' --notes-file CHANGELOG.md
55
+ ```
56
+ This triggers `publish.yml` → PyPI.
57
+
58
+ 9. **Verify:** `pip install <package>==X.Y.Z`
59
+
60
+ ## Why there is no `--commit` mode
61
+
62
+ A previous version of this script had a `--commit` flag that did the
63
+ changelog prepend, the UNRELEASED reset, and the git commit/tag/push in
64
+ one shot. Two problems:
65
+
66
+ - It copied `UNRELEASED.md` verbatim into `CHANGELOG.md`. `UNRELEASED.md`
67
+ is written in internal developer voice; `CHANGELOG.md` is read by
68
+ strangers on PyPI. That's a Rule-10 audience violation, and the
69
+ automation made it the path of least resistance.
70
+ - It coupled the mechanical bump with the human authorship steps, so
71
+ there was no natural point to review the translation before the
72
+ commit went out.
73
+
74
+ Doing the authorship by hand, then using the script only for the literal
75
+ version strings, is slower on paper and safer in practice.
76
+
77
+ ## Historical foot-guns
78
+
79
+ - **v1.6.1 (2026-ish):** release commit missed unstaged source edits
80
+ because only tracked files were staged. Mitigation: always run
81
+ `git status` before `git commit` and confirm the diff contains every
82
+ file the release should ship.
83
+ - **Multiple PyPI publish failures:** every one has been a missed manual
84
+ step from this list. Work top to bottom; do not skip.
@@ -0,0 +1,312 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Release utility for pystatistics / pystatsbio.
4
+
5
+ This script ONLY automates the mechanical, judgement-free parts of a
6
+ release. Everything that needs human authorship — in particular, the
7
+ public-facing CHANGELOG.md entry — is left to you.
8
+
9
+ Why: UNRELEASED.md is written in internal developer voice (rule numbers,
10
+ project names, test counts, development rationale). CHANGELOG.md is a
11
+ public file read by strangers on PyPI. Copying one into the other is a
12
+ Rule-10 violation. The translation must be done by hand.
13
+
14
+ Usage:
15
+ python .release/release.py --status # show version state + unreleased summary
16
+ python .release/release.py --check X.Y.Z # dry-run: validate the bump
17
+ python .release/release.py --bump X.Y.Z # bump pyproject.toml + __init__.py
18
+ python .release/release.py --reset-unreleased # wipe UNRELEASED.md to template
19
+ (only after CHANGELOG entry is written)
20
+
21
+ What this script does:
22
+ --bump:
23
+ 1. Validates new version > current version
24
+ 2. Writes new version to pyproject.toml
25
+ 3. Writes new version to <package>/__init__.py
26
+
27
+ --reset-unreleased:
28
+ 1. Overwrites UNRELEASED.md with the empty template
29
+
30
+ What this script does NOT do (you must do these yourself):
31
+ - Write the CHANGELOG.md entry. Translate UNRELEASED.md into
32
+ user-facing prose by hand. Do not copy verbatim.
33
+ - Update the README "What's New" section.
34
+ - git add / commit / tag / push.
35
+ - gh release create.
36
+
37
+ Typical flow:
38
+ 1. `--status` (sanity check)
39
+ 2. Write the CHANGELOG.md entry by hand. (translation)
40
+ 3. Update README.md "What's New" by hand. (translation)
41
+ 4. `--bump X.Y.Z` (mechanical)
42
+ 5. `git diff` (review)
43
+ 6. git add / commit / tag / push (manual)
44
+ 7. `--reset-unreleased` (only after commit)
45
+ 8. Commit the reset, then `gh release create`.
46
+ """
47
+
48
+ from __future__ import annotations
49
+
50
+ import re
51
+ import sys
52
+ import textwrap
53
+ from pathlib import Path
54
+
55
+ REPO_ROOT = Path(__file__).resolve().parent.parent
56
+ RELEASE_DIR = REPO_ROOT / ".release"
57
+ UNRELEASED_PATH = RELEASE_DIR / "UNRELEASED.md"
58
+
59
+
60
+ # ---------------------------------------------------------------------------
61
+ # Discovery
62
+ # ---------------------------------------------------------------------------
63
+
64
+ def find_package() -> str:
65
+ """Find the Python package directory (has __init__.py with __version__)."""
66
+ for d in sorted(REPO_ROOT.iterdir()):
67
+ if d.is_dir() and (d / "__init__.py").exists():
68
+ init_text = (d / "__init__.py").read_text()
69
+ if "__version__" in init_text:
70
+ return d.name
71
+ raise FileNotFoundError("Cannot find package with __version__ in __init__.py")
72
+
73
+
74
+ def get_current_version() -> str:
75
+ toml = (REPO_ROOT / "pyproject.toml").read_text()
76
+ m = re.search(r'^version\s*=\s*"([^"]+)"', toml, re.MULTILINE)
77
+ if not m:
78
+ raise ValueError("Cannot find version in pyproject.toml")
79
+ return m.group(1)
80
+
81
+
82
+ def get_init_version(package: str) -> str:
83
+ init = (REPO_ROOT / package / "__init__.py").read_text()
84
+ m = re.search(r'__version__\s*=\s*"([^"]+)"', init)
85
+ if not m:
86
+ raise ValueError(f"Cannot find __version__ in {package}/__init__.py")
87
+ return m.group(1)
88
+
89
+
90
+ def get_changelog_version() -> str | None:
91
+ changelog = REPO_ROOT / "CHANGELOG.md"
92
+ if not changelog.exists():
93
+ return None
94
+ text = changelog.read_text()
95
+ m = re.search(r'^## (\d+\.\d+\.\d+)', text, re.MULTILINE)
96
+ return m.group(1) if m else None
97
+
98
+
99
+ # ---------------------------------------------------------------------------
100
+ # UNRELEASED.md
101
+ # ---------------------------------------------------------------------------
102
+
103
+ EMPTY_UNRELEASED = textwrap.dedent("""\
104
+ # Unreleased Changes
105
+
106
+ > This file tracks all changes since the last stable release.
107
+ > Updated by whoever makes a change, on whatever machine.
108
+ > Synced via git so all sessions (Mac, Linux, etc.) see the same state.
109
+ >
110
+ > When ready to release, run: `python .release/release.py --status`
111
+ > and follow the manual release flow in the script docstring.
112
+
113
+ ## Changes
114
+
115
+ *(empty — no unreleased changes yet)*
116
+ """)
117
+
118
+
119
+ def get_unreleased_content() -> str:
120
+ if not UNRELEASED_PATH.exists():
121
+ return ""
122
+ text = UNRELEASED_PATH.read_text()
123
+ m = re.search(r'^## Changes\s*\n(.*)\Z', text, re.MULTILINE | re.DOTALL)
124
+ if not m:
125
+ return ""
126
+ content = m.group(1).strip()
127
+ if not content or content == "*(empty — no unreleased changes yet)*":
128
+ return ""
129
+ return content
130
+
131
+
132
+ def reset_unreleased() -> None:
133
+ UNRELEASED_PATH.write_text(EMPTY_UNRELEASED)
134
+
135
+
136
+ # ---------------------------------------------------------------------------
137
+ # Version bumping
138
+ # ---------------------------------------------------------------------------
139
+
140
+ def bump_pyproject(new_version: str) -> None:
141
+ path = REPO_ROOT / "pyproject.toml"
142
+ text = path.read_text()
143
+ text = re.sub(
144
+ r'^(version\s*=\s*)"[^"]+"',
145
+ rf'\g<1>"{new_version}"',
146
+ text,
147
+ count=1,
148
+ flags=re.MULTILINE,
149
+ )
150
+ path.write_text(text)
151
+
152
+
153
+ def bump_init(package: str, new_version: str) -> None:
154
+ path = REPO_ROOT / package / "__init__.py"
155
+ text = path.read_text()
156
+ text = re.sub(
157
+ r'(__version__\s*=\s*)"[^"]+"',
158
+ rf'\g<1>"{new_version}"',
159
+ text,
160
+ count=1,
161
+ )
162
+ path.write_text(text)
163
+
164
+
165
+ def parse_version(v: str) -> tuple[int, ...]:
166
+ return tuple(int(x) for x in v.split("."))
167
+
168
+
169
+ def validate_version(new: str, current: str) -> None:
170
+ try:
171
+ new_t = parse_version(new)
172
+ cur_t = parse_version(current)
173
+ except (ValueError, AttributeError) as e:
174
+ raise ValueError(f"Invalid version format: {e}") from e
175
+
176
+ if new_t <= cur_t:
177
+ raise ValueError(
178
+ f"New version {new} must be greater than current {current}"
179
+ )
180
+
181
+
182
+ # ---------------------------------------------------------------------------
183
+ # Commands
184
+ # ---------------------------------------------------------------------------
185
+
186
+ def cmd_status() -> None:
187
+ package = find_package()
188
+ v_toml = get_current_version()
189
+ v_init = get_init_version(package)
190
+ v_log = get_changelog_version()
191
+ unreleased = get_unreleased_content()
192
+
193
+ print(f"Package: {package}")
194
+ print(f"pyproject: {v_toml}")
195
+ print(f"__init__: {v_init}")
196
+ print(f"CHANGELOG: {v_log or '(none)'}")
197
+
198
+ if v_toml != v_init:
199
+ print(f"\n WARNING: pyproject ({v_toml}) != __init__ ({v_init})")
200
+ if v_log and v_toml != v_log:
201
+ print(f"\n WARNING: pyproject ({v_toml}) != CHANGELOG ({v_log})")
202
+
203
+ print("\nUnreleased changes (internal voice — do NOT paste into CHANGELOG.md):")
204
+ if unreleased:
205
+ lines = unreleased.split("\n")
206
+ for line in lines[:12]:
207
+ print(f" {line}")
208
+ if len(lines) > 12:
209
+ print(f" ... ({len(lines) - 12} more lines)")
210
+ else:
211
+ print(" (none)")
212
+
213
+
214
+ def cmd_check(new_version: str) -> None:
215
+ package = find_package()
216
+ current = get_current_version()
217
+ validate_version(new_version, current)
218
+
219
+ print(f"Package: {package}")
220
+ print(f"Current: {current}")
221
+ print(f"New: {new_version}")
222
+ print("\nWould update (only these two files):")
223
+ print(f" pyproject.toml: {current} → {new_version}")
224
+ print(f" {package}/__init__.py: {current} → {new_version}")
225
+ print("\nThis script will NOT touch CHANGELOG.md, README.md, UNRELEASED.md, or git.")
226
+
227
+
228
+ def cmd_bump(new_version: str) -> None:
229
+ package = find_package()
230
+ current = get_current_version()
231
+ validate_version(new_version, current)
232
+
233
+ print(f"Bumping {package} {current} → {new_version}\n")
234
+
235
+ bump_pyproject(new_version)
236
+ print(f" ✓ pyproject.toml → {new_version}")
237
+
238
+ bump_init(package, new_version)
239
+ print(f" ✓ {package}/__init__.py → {new_version}")
240
+
241
+ print(f"\n{'='*50}")
242
+ print(f" Version bumped to {new_version}")
243
+ print(f"{'='*50}")
244
+ print("\nRemaining steps (all manual):")
245
+ print(" 1. Verify CHANGELOG.md has a hand-written entry for this version")
246
+ print(" (do NOT paste UNRELEASED.md verbatim — translate to user-facing prose).")
247
+ print(" 2. Verify README.md 'What's New' reflects the same user-facing summary.")
248
+ print(" 3. git diff # review")
249
+ print(f" 4. git add pyproject.toml {package}/__init__.py CHANGELOG.md README.md")
250
+ print(f" 5. git commit -m 'Release {new_version}'")
251
+ print(f" 6. git tag v{new_version}")
252
+ print(f" 7. git push origin <branch> && git push origin v{new_version}")
253
+ print(" 8. python .release/release.py --reset-unreleased")
254
+ print(" git add .release/UNRELEASED.md && git commit -m 'Reset UNRELEASED.md'")
255
+ print(" git push")
256
+ print(f" 9. gh release create v{new_version} --title 'v{new_version}' --notes-file CHANGELOG.md")
257
+ print(f" 10. Verify: pip install {package}=={new_version}")
258
+
259
+
260
+ def cmd_reset_unreleased() -> None:
261
+ reset_unreleased()
262
+ print(f" ✓ {UNRELEASED_PATH.relative_to(REPO_ROOT)} reset to empty template")
263
+ print("\nRemember to commit the reset:")
264
+ print(" git add .release/UNRELEASED.md")
265
+ print(" git commit -m 'Reset UNRELEASED.md for next cycle'")
266
+ print(" git push")
267
+
268
+
269
+ # ---------------------------------------------------------------------------
270
+ # Main
271
+ # ---------------------------------------------------------------------------
272
+
273
+ USAGE = """\
274
+ Usage:
275
+ python .release/release.py --status # show version state
276
+ python .release/release.py --check X.Y.Z # dry-run: validate the bump
277
+ python .release/release.py --bump X.Y.Z # bump pyproject.toml + __init__.py
278
+ python .release/release.py --reset-unreleased # wipe UNRELEASED.md to template
279
+
280
+ See the module docstring for the full manual release flow.
281
+ """
282
+
283
+
284
+ def main() -> None:
285
+ if len(sys.argv) < 2:
286
+ print(USAGE)
287
+ sys.exit(1)
288
+
289
+ arg = sys.argv[1]
290
+
291
+ if arg == "--status":
292
+ cmd_status()
293
+ elif arg == "--check":
294
+ if len(sys.argv) < 3:
295
+ print("Usage: python .release/release.py --check X.Y.Z")
296
+ sys.exit(1)
297
+ cmd_check(sys.argv[2])
298
+ elif arg == "--bump":
299
+ if len(sys.argv) < 3:
300
+ print("Usage: python .release/release.py --bump X.Y.Z")
301
+ sys.exit(1)
302
+ cmd_bump(sys.argv[2])
303
+ elif arg == "--reset-unreleased":
304
+ cmd_reset_unreleased()
305
+ else:
306
+ print(f"Unknown command: {arg}\n")
307
+ print(USAGE)
308
+ sys.exit(1)
309
+
310
+
311
+ if __name__ == "__main__":
312
+ main()
@@ -1,5 +1,182 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.1
4
+
5
+ Metadata and documentation polish. No API changes.
6
+
7
+ - **Development Status classifier updated.** `pyproject.toml` now
8
+ declares `Development Status :: 5 - Production/Stable` (previously
9
+ `3 - Alpha`). This only affects the PyPI classifier — no runtime
10
+ behaviour changes.
11
+
12
+ - **Stale optional-dependency extra removed.** The
13
+ `[nonparametric_mcar]` extra has been removed from `pyproject.toml`.
14
+ The subpackage it referenced was removed in 3.0.0, but the extra had
15
+ remained listed on PyPI. `pip install pystatistics[nonparametric_mcar]`
16
+ will now fail with an "extra not provided" message instead of
17
+ silently installing a dependency for a subpackage that does not exist.
18
+
19
+ - **README restructured.** The README now leads with the library's
20
+ design philosophy and module table, with the changelog near the
21
+ bottom. A first-time reader on PyPI sees what PyStatistics is before
22
+ seeing what has changed release-to-release.
23
+
24
+ ## 3.0.0
25
+
26
+ ### BREAKING: Removed MoM MCAR test and the entire `nonparametric_mcar` subpackage
27
+
28
+ `pystatistics.mvnmle.mom_mcar_test` and the full
29
+ `pystatistics.nonparametric_mcar` subpackage (propensity / HSIC /
30
+ MissMech + their shared `NonparametricMCARResult`) have been removed.
31
+ These were added in 2.2.0 and 2.3.0 respectively, specifically in
32
+ service of Lacuna's missingness-mechanism cache, NOT as general-
33
+ purpose statistical methods. That was a scope-boundary mistake on
34
+ pystatistics's part: we're a general-purpose statistics library, and
35
+ these tests are project-specific feature-extraction helpers.
36
+
37
+ **What remains in pystatistics:**
38
+ - `pystatistics.mvnmle.little_mcar_test` — the canonical Little (1988)
39
+ MLE-plug-in test. Textbook, general-purpose, stays.
40
+ - `MCARTestResult` dataclass — retained (downstream packages that
41
+ implement their own MCAR variants can and do reuse it).
42
+ - All of `mlest`, the EM / SQUAREM machinery, `analyze_patterns`,
43
+ `PatternInfo`, etc. — unchanged.
44
+
45
+ **Where the removed tests live now:** the cache-scale variants have
46
+ moved into Lacuna as `lacuna.analysis.mcar`:
47
+
48
+ - `lacuna.analysis.mcar.mom_mcar_test` (method-of-moments plug-in)
49
+ - `lacuna.analysis.mcar.propensity_mcar_test` (RF/GBM + analytical or
50
+ permutation null)
51
+ - `lacuna.analysis.mcar.hsic_mcar_test` (Gretton gamma or permutation null)
52
+ - `lacuna.analysis.mcar.missmech_mcar_test` (Jamshidian-Jalal-style)
53
+ - `lacuna.analysis.mcar.NonparametricMCARResult`
54
+
55
+ All the 2.3.0/2.4.0 performance work that was in-flight in this file
56
+ (analytical AUC p-value for propensity, HGB default, Gretton gamma
57
+ null for HSIC, vectorised MissMech permutation, etc.) moved with the
58
+ code. Downstream: Lacuna's cache build is unaffected — it now imports
59
+ from `lacuna.analysis.mcar` instead of `pystatistics.nonparametric_mcar`.
60
+
61
+ **Migration for external users (if any):**
62
+ - `from pystatistics.mvnmle import mom_mcar_test` →
63
+ `from lacuna.analysis.mcar import mom_mcar_test` (if using Lacuna).
64
+ Alternatively, the MoM algorithm is ~100 LOC of pairwise-deletion
65
+ moments + per-pattern chi-square and is straightforward to inline
66
+ if you don't want a Lacuna dependency.
67
+ - `from pystatistics.nonparametric_mcar import *` →
68
+ `from lacuna.analysis.mcar import *`.
69
+
70
+ **Why a major bump (3.0.0):** public API surface shrunk; imports that
71
+ worked in 2.x now fail. Even though our active user population is
72
+ small (internal), the convention matters — breaking removals are
73
+ semver-major.
74
+
75
+ **Dropped files:**
76
+ - `pystatistics/nonparametric_mcar/` (subpackage, 5 files)
77
+ - `pystatistics/mvnmle/mcar_test.py` lost `mom_mcar_test`,
78
+ `_resolve_mom_backend`, `_pairwise_deletion_moments`, and the
79
+ `_MOM_GPU_WORTH_IT_THRESHOLD` constant. `little_mcar_test` and
80
+ `MCARTestResult` remain.
81
+ - `pyproject.toml` lost the `nonparametric_mcar` optional extra.
82
+ - `tests/mvnmle/test_mom_mcar.py` and `tests/nonparametric_mcar/`.
83
+
84
+ (The dead batched MCAR chi-square machinery that this removal left
85
+ stranded has also been cleaned up — see the "Dead-code cleanup"
86
+ section below.)
87
+
88
+ ### Fixed flaky GAM GPU FP64 `total_edf` test
89
+
90
+ `tests/gam/test_gam.py::TestGAMGPU::test_gpu_fp64_matches_cpu_fitted_and_gcv`
91
+ had been flaking intermittently since 1.8.0. Measured CPU/GPU drift on
92
+ the `sine_data` fixture:
93
+
94
+ - `fitted_values` max abs diff: ~7e-8 (machine precision)
95
+ - `deviance` relative diff: ~1e-7
96
+ - `gcv` relative diff: ~3e-5
97
+ - `total_edf` relative diff: **~1.4e-3** (narrowly failing the 1e-3 bar)
98
+
99
+ Diagnosis: the primary fit statistics (fitted_values, deviance, GCV)
100
+ sit at the GCV-minimising λ, i.e. at a local minimum of `GCV(λ)`, so
101
+ they are insensitive to the tiny λ-drift the L-BFGS-B outer search
102
+ lands on across CPU/GPU. `total_edf`, however, passes through a trace
103
+ of `(X'WX + λ·S)⁻¹·X'WX`, which is LINEAR in λ near the optimum. With
104
+ the penalised normal-equation matrix at cond ≈ 1e16-17 the EDF trace
105
+ moves O(10⁻³) per O(10⁻⁶) λ shift — structurally more sensitive than
106
+ the fit statistics that a 1e-4 tolerance gated.
107
+
108
+ Fix: tolerance widened from `rel=1e-3` to `rel=5e-3` on `total_edf`
109
+ only. The other three assertions (fitted_values, deviance, GCV) keep
110
+ their 1e-4 margin. Test comment updated with the λ-sensitivity
111
+ analysis so future maintainers don't re-tighten it without
112
+ understanding why it's at 5e-3.
113
+
114
+ ### Fixed GAM GPU smooth-term chi-squared bug (null-space absorption)
115
+
116
+ Surfaced while tightening the `total_edf` tolerance above: the chi-
117
+ squared statistic reported in `smooth_terms` was diverging ~8×
118
+ between CPU and GPU backends — CPU ≈ 19, GPU ≈ 156 on the
119
+ `sine_data` fixture — despite fitted values agreeing to FP64
120
+ precision. This was a latent correctness bug in the GPU backend
121
+ going back to whenever the GAM GPU path was first written.
122
+
123
+ Root cause: the penalised normal matrix `A = X'WX + Σ λⱼ Sⱼ` has
124
+ condition number up to ~1e17 when λ is small — the penalty does not
125
+ fully eliminate the design matrix's null space (the constant / linear
126
+ directions in the spline basis's null space). On such `A`,
127
+ `torch.linalg.solve` (LU on device) and `np.linalg.cholesky`
128
+ (CPU reference path) converge to the same `X·β` (fitted values) but
129
+ pick DIFFERENT null-space-representative `β` (coefficients).
130
+ Concretely on `sine_data`: fitted values agreed to 7e-8 but
131
+ coefficients were shifted by a constant ±1.73 between the parametric
132
+ intercept and every smooth basis coefficient — exactly the null-space
133
+ direction the penalty fails to constrain. Since `smooth_terms.chi_sq`
134
+ is computed directly from `β` (via `β_j'·β_j / scale`), the null-
135
+ space shift broke it despite the rest of the fit being numerically
136
+ sound.
137
+
138
+ Fix: the GPU backend now canonicalises the final `β` by re-solving
139
+ `A·β = b` via numpy's Cholesky-with-LU-fallback — the same logic
140
+ the CPU path uses in `_pirls_step`. This lives in a new
141
+ `_canonicalise_beta` method; `fit_fixed` and `edf_per_term` both call
142
+ it after their P-IRLS loops converge. In-loop P-IRLS still uses
143
+ torch's fast LU on device (null-space ambiguity doesn't matter
144
+ there — only the resulting `μ` drives convergence). The D2H
145
+ round-trip for the final solve is ~100 µs on a p×p matrix with p
146
+ typically ≤ 80; the dominant GPU work (the n×p GEMM in each P-IRLS
147
+ step) stays on device.
148
+
149
+ Test: `TestGAMGPU::test_gpu_fp64_matches_cpu_fitted_and_gcv` gained
150
+ coefficient-level assertions (`rtol=1e-3, atol=1e-4`) and chi-squared
151
+ agreement (`rel=1e-3`) so this regression is caught if it returns.
152
+ Measured post-fix: coef max abs diff drops from 1.73 to 9e-5;
153
+ chi_sq rel diff drops from ~8× to 1.6e-5.
154
+
155
+ ### Dead-code cleanup
156
+
157
+ While removing ``mom_mcar_test``, noticed that the batched MCAR
158
+ chi-square machinery (``chi_square_mcar_batched_np`` and
159
+ ``chi_square_mcar_batched_torch`` in ``backends/_em_batched_{np,torch}.py``,
160
+ re-exported via the shim at ``backends/_em_batched.py``) was only ever
161
+ called from ``mom_mcar_test``. Those functions are now gone; shim
162
+ dropped their re-exports; backend file docstrings updated to record
163
+ the removal. Net: `_em_batched_np.py` went from 416 → 300 lines and
164
+ `_em_batched_torch.py` from 381 → 271 lines, and `backends/_em_batched.py`
165
+ lost two of its eleven shim exports.
166
+
167
+ ### Process change
168
+
169
+ Added **Rule 9 "Cross-Project Scope Boundary"** to
170
+ `CLAUDE.md`. Future Claude Code sessions working on pystatistics must
171
+ not modify sibling projects (Lacuna, pystatsbio, etc.) without
172
+ explicit per-session user authorisation. Functionality needed by
173
+ another project belongs in that project until demonstrably general.
174
+ This removal is the retroactive correction of previous boundary
175
+ crossings. The same rule was added to Lacuna's and pystatsbio's
176
+ CLAUDE.md files (§8 and §9 respectively, numbered by where the rule
177
+ fit in each file's existing structure).
178
+
179
+
3
180
  ## 2.3.0
4
181
 
5
182
  - **New subpackage `pystatistics.nonparametric_mcar`** for distribution-
@@ -218,6 +218,93 @@ file, that's a process failure.
218
218
 
219
219
  ---
220
220
 
221
+ ## 9. Cross-Project Scope Boundary — Stay in the Project You Were Invited Into
222
+
223
+ A Claude Code session is invoked on one project. It does not have a licence to edit
224
+ any other project visible on disk. Seeing sibling repos in `/mnt/projects/` does not
225
+ constitute an invitation to modify them.
226
+
227
+ **Rules:**
228
+ - Never modify source, tests, configs, or documentation in a sibling project (any
229
+ repo outside the current one) on your own initiative.
230
+ - When you believe a change belongs in a sibling project — "this belongs upstream",
231
+ "this helper is more general than the current project", "I should fix a bug in
232
+ their API" — stop and raise it with the user. Describe what you'd change, where,
233
+ and why. Wait for explicit authorisation before editing the sibling repo.
234
+ - "Explicit authorisation" means the user said, in the current session, something
235
+ like "yes, also modify project X". It is NOT a precedent from a prior session. It
236
+ is NOT "the user probably wouldn't mind". It is NOT inferred from the fact that
237
+ the user depends on project X.
238
+
239
+ **Corollary — Scope Creep Is a Design Decision, Not a Technical One:**
240
+ Pushing project-A-specific functionality into general-purpose project B because it's
241
+ technically convenient dilutes project B's identity, breaks the expectations of other
242
+ downstream consumers, and forces project B to carry maintenance burden for a use case
243
+ it was never meant to serve. "Project A needs X, and X involves statistics, therefore
244
+ X belongs in pystatistics" is not a valid reasoning chain. X belongs in project A
245
+ until (a) multiple sibling projects demonstrably need it AND (b) a decision has been
246
+ made to promote it — either into an existing general-purpose library or into a new
247
+ dedicated sibling.
248
+
249
+ **What to do when you think a sibling needs a change:**
250
+ 1. Implement the helper inside your OWN project first. It lives there until proven
251
+ general.
252
+ 2. Surface the "belongs upstream" thought to the user explicitly. Propose the
253
+ migration as a separate task. Do not pre-emptively modify the sibling repo.
254
+ 3. If the user authorises the migration, treat it as its own first-class task with
255
+ its own review, tests, and release cadence — not as a side-effect of the
256
+ originating feature.
257
+
258
+ ---
259
+
260
+ ## 10. Audience Awareness for Public-Facing Files
261
+
262
+ Before modifying any public-facing file (`README.md`, `pyproject.toml`,
263
+ user-facing documentation, the PyPI description), explicitly identify the
264
+ audience: **a stranger on the internet who has never seen this codebase.**
265
+ That person has no knowledge of `CLAUDE.md`, internal project names,
266
+ development rationale, rule numbers, or implementation history. They need
267
+ to know what the library does, how to install it, and how to use it —
268
+ nothing else.
269
+
270
+ **The test:** *would a first-time user finding this on PyPI find this
271
+ useful or confusing?* If confusing, omit it.
272
+
273
+ **Rules (all specific instances of the principle above):**
274
+
275
+ - **Changelog entries must not reference internal development artifacts.**
276
+ Entries in `README.md`, `CHANGELOG.md`, or any public-facing document must
277
+ never reference `CLAUDE.md`, internal rule numbers, internal project
278
+ names, development process, or test counts. Acceptable content:
279
+ user-facing behaviour changes, API additions/removals, bug fixes, and
280
+ performance numbers.
281
+
282
+ Example of what must **not** appear in a public changelog:
283
+ > "a new Cross-Project Scope Boundary rule (Rule 9) has been added to
284
+ > CLAUDE.md"
285
+
286
+ - **Do not document `CLAUDE.md` changes in `README.md`.** When updating
287
+ `CLAUDE.md`, do not document those changes in `README.md` or any other
288
+ public-facing file. `CLAUDE.md` is internal developer guidance; `README.md`
289
+ reflects the public API, installation, and usage. `README.md` must never
290
+ reference `CLAUDE.md` by name or by implication.
291
+
292
+ - **`README.md` is a user document, not a changelog mirror.** When updating
293
+ `README.md` from `CHANGELOG.md` or release notes, do not copy entries
294
+ verbatim or structurally. Translate them: extract only user-facing
295
+ behaviour changes, rewrite in present tense describing the library's
296
+ current state, and omit internal process details (references to
297
+ `CLAUDE.md`, rule numbers, internal project names, test counts,
298
+ development rationale). A user reading the README should understand what
299
+ the library does today — not the history of how it got there.
300
+
301
+ **Corollary — The Internal Audience Already Has CLAUDE.md:**
302
+ Rationale that belongs in `CLAUDE.md` does not need to be duplicated into
303
+ public-facing files to "motivate" a change for users. Users do not need to
304
+ be sold on the rule behind the change — only told what changed.
305
+
306
+ ---
307
+
221
308
  ## Meta-Rule
222
309
 
223
310
  If any of these rules feel inconvenient, that feeling is the point. These rules exist