PyMetaAnalysis 0.4.0__tar.gz → 0.6.0__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 (136) hide show
  1. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.github/workflows/ci.yml +1 -1
  2. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.github/workflows/pages.yml +1 -2
  3. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.github/workflows/release.yml +7 -3
  4. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/.gitignore +1 -0
  5. pymetaanalysis-0.6.0/CHANGELOG.md +204 -0
  6. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/CITATION.cff +2 -2
  7. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/PKG-INFO +15 -4
  8. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/README.md +13 -3
  9. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/adr/0002-statistical-policy.md +15 -6
  10. pymetaanalysis-0.6.0/docs/adr/0004-hartung-knapp-prediction-intervals.md +46 -0
  11. pymetaanalysis-0.6.0/docs/adr/0005-mantel-haenszel-risk-difference.md +65 -0
  12. pymetaanalysis-0.6.0/docs/adr/0006-peto-odds-ratio.md +87 -0
  13. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/development.md +2 -2
  14. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/binary-outcomes.md +33 -5
  15. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/input-data.md +18 -2
  16. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/meta-regression.md +4 -0
  17. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/method-selection.md +70 -12
  18. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/provenance-reporting.md +12 -0
  19. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/r-interoperability.md +34 -5
  20. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/sensitivity-analysis.md +15 -7
  21. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/zero-events.md +43 -6
  22. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/index.md +7 -5
  23. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/installation.md +1 -1
  24. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/limitations.md +15 -6
  25. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/methods/statistical-methods.md +152 -26
  26. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/reference/api.md +45 -17
  27. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/reference/report-schema.md +2 -1
  28. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/reference/results.md +56 -8
  29. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/releasing.md +18 -14
  30. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/validation.md +51 -18
  31. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/mkdocs.yml +3 -0
  32. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/pyproject.toml +3 -1
  33. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/__init__.py +2 -0
  34. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/_version.py +1 -1
  35. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/api.py +65 -17
  36. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/binary_api.py +126 -30
  37. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/continuous_api.py +37 -16
  38. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/data.py +40 -0
  39. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/design_matrix.py +80 -21
  40. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/effect_sizes/binary.py +154 -19
  41. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/effect_sizes/continuous.py +34 -4
  42. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/__init__.py +3 -0
  43. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/inverse_variance.py +22 -6
  44. pymetaanalysis-0.6.0/src/meta_analyze/estimators/mantel_haenszel.py +183 -0
  45. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/meta_regression.py +117 -34
  46. pymetaanalysis-0.6.0/src/meta_analyze/estimators/peto.py +154 -0
  47. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/estimators/tau2.py +42 -20
  48. pymetaanalysis-0.6.0/src/meta_analyze/heterogeneity.py +285 -0
  49. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/_utils.py +10 -0
  50. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/forest.py +24 -5
  51. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/subgroup_forest.py +32 -0
  52. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_api.py +19 -6
  53. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_collinearity.py +3 -22
  54. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_results.py +48 -0
  55. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_sensitivity.py +14 -38
  56. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/reporting.py +50 -21
  57. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/results.py +170 -0
  58. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/sensitivity.py +115 -33
  59. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/subgroups.py +61 -12
  60. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/README.md +29 -9
  61. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/binary_metafor.json +72 -1
  62. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_binary_metafor.R +97 -17
  63. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_generic_metafor.R +32 -8
  64. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_influence_metafor.R +22 -8
  65. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_metafor.R +83 -2
  66. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_workflow_metafor.R +10 -0
  67. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generic_metafor.json +27 -1
  68. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_influence_metafor.json +327 -0
  69. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_metafor.json +205 -0
  70. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/workflow_metafor.json +6 -0
  71. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_api.py +236 -0
  72. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_binary.py +339 -1
  73. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_continuous.py +41 -0
  74. pymetaanalysis-0.6.0/tests/test_estimators.py +412 -0
  75. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_funnel_plot.py +1 -1
  76. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_meta_regression.py +79 -0
  77. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_numerical_stability.py +128 -0
  78. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_plotting.py +11 -0
  79. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_properties.py +189 -0
  80. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_r_references.py +254 -6
  81. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_influence.py +65 -22
  82. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_plotting.py +1 -1
  83. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_sensitivity.py +25 -0
  84. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_release_readiness.py +39 -0
  85. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_reporting.py +47 -4
  86. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_sensitivity.py +108 -6
  87. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_subgroups.py +120 -13
  88. pymetaanalysis-0.4.0/CHANGELOG.md +0 -108
  89. pymetaanalysis-0.4.0/src/meta_analyze/estimators/mantel_haenszel.py +0 -101
  90. pymetaanalysis-0.4.0/src/meta_analyze/heterogeneity.py +0 -99
  91. pymetaanalysis-0.4.0/tests/test_estimators.py +0 -147
  92. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/CONTRIBUTING.md +0 -0
  93. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/LICENSE +0 -0
  94. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/SECURITY.md +0 -0
  95. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/benchmarks/README.md +0 -0
  96. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/benchmarks/benchmark_core.py +0 -0
  97. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/adr/0001-optional-matplotlib.md +0 -0
  98. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/adr/0003-meta-regression-prediction-intervals.md +0 -0
  99. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/citation.md +0 -0
  100. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/getting-started.md +0 -0
  101. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/continuous-outcomes.md +0 -0
  102. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/generic-effects.md +0 -0
  103. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/guides/plotting.md +0 -0
  104. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/docs/stylesheets/extra.css +0 -0
  105. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/examples/README.md +0 -0
  106. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/examples/meta_regression.ipynb +0 -0
  107. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/examples/quickstart.ipynb +0 -0
  108. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/config.py +0 -0
  109. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/effect_sizes/__init__.py +0 -0
  110. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/exceptions.py +0 -0
  111. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/__init__.py +0 -0
  112. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/funnel.py +0 -0
  113. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/plotting/regression.py +0 -0
  114. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/provenance.py +0 -0
  115. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/py.typed +0 -0
  116. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/src/meta_analyze/regression_contrasts.py +0 -0
  117. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/binary_input.csv +0 -0
  118. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/binary_sparse_input.csv +0 -0
  119. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/continuous_input.csv +0 -0
  120. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/continuous_metafor.json +0 -0
  121. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_continuous_metafor.R +0 -0
  122. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_collinearity_metafor.R +0 -0
  123. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generate_meta_regression_contrasts_metafor.R +0 -0
  124. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/generic_input.csv +0 -0
  125. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_boundary_input.csv +0 -0
  126. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_collinearity_metafor.json +0 -0
  127. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_contrasts_metafor.json +0 -0
  128. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/meta_regression_input.csv +0 -0
  129. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/reference/workflow_input.csv +0 -0
  130. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_documentation.py +0 -0
  131. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_reference_results.py +0 -0
  132. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_collinearity.py +0 -0
  133. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tests/test_regression_contrasts.py +0 -0
  134. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tools/check_release.py +0 -0
  135. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tools/execute_notebooks.py +0 -0
  136. {pymetaanalysis-0.4.0 → pymetaanalysis-0.6.0}/tools/inspect_distribution.py +0 -0
@@ -22,7 +22,7 @@ jobs:
22
22
  strategy:
23
23
  fail-fast: false
24
24
  matrix:
25
- python-version: ["3.10", "3.11", "3.12", "3.13"]
25
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
26
26
 
27
27
  steps:
28
28
  - name: Check out repository
@@ -8,7 +8,7 @@ on:
8
8
 
9
9
  concurrency:
10
10
  group: pages
11
- cancel-in-progress: true
11
+ cancel-in-progress: false
12
12
 
13
13
  jobs:
14
14
  build:
@@ -17,7 +17,6 @@ jobs:
17
17
  timeout-minutes: 10
18
18
  permissions:
19
19
  contents: read
20
- pages: write
21
20
 
22
21
  steps:
23
22
  - name: Check out repository
@@ -35,14 +35,17 @@ jobs:
35
35
  cache: pip
36
36
  cache-dependency-path: pyproject.toml
37
37
 
38
- - name: Install build tools
38
+ - name: Install release dependencies
39
39
  run: |
40
40
  python -m pip install --upgrade pip
41
- python -m pip install build twine
41
+ python -m pip install ".[test]" build twine
42
42
 
43
43
  - name: Validate release metadata
44
44
  run: python tools/check_release.py --tag "$GITHUB_REF_NAME"
45
45
 
46
+ - name: Run tests with branch coverage
47
+ run: python -m pytest --cov=meta_analyze --cov-branch --cov-report=term-missing
48
+
46
49
  - name: Build distributions
47
50
  run: python -m build
48
51
 
@@ -91,7 +94,8 @@ jobs:
91
94
  path: dist/
92
95
 
93
96
  - name: Publish to PyPI
94
- uses: pypa/gh-action-pypi-publish@release/v1
97
+ # release/v1.14, pinned because this step holds the PyPI OIDC permission.
98
+ uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247
95
99
 
96
100
  github-release:
97
101
  name: Create GitHub Release
@@ -1,5 +1,6 @@
1
1
  # Local design notes are intentionally not part of the published project.
2
2
  /DESIGN.md
3
+ /articles/
3
4
 
4
5
  # Python environments and generated files
5
6
  /.venv/
@@ -0,0 +1,204 @@
1
+ # Changelog
2
+
3
+ All notable changes to PyMetaAnalysis will be documented in this file.
4
+
5
+ Changes planned for the next release accumulate under `Unreleased`.
6
+
7
+ ## Unreleased
8
+
9
+ ## 0.6.0 - 2026-08-13
10
+
11
+ ### Added
12
+
13
+ - common-effect Peto one-step odds-ratio pooling, including Peto-specific
14
+ study estimates, O-minus-E heterogeneity, explicit approximation warnings,
15
+ provenance/report metadata, and independent R `metafor` references;
16
+ - common-effect Mantel-Haenszel risk-difference pooling with the
17
+ Sato-Greenland-Robins sampling variance, explicit method metadata,
18
+ sparse-table policy integration, and independent R `metafor` references.
19
+
20
+ ### Fixed
21
+
22
+ - isolated builds temporarily cap Hatchling below 1.32 so the release
23
+ workflow continues to produce Core Metadata 2.4 accepted by Twine 6.2;
24
+ the cap can be removed once Twine validates Metadata 2.5.
25
+
26
+ ## 0.5.0 - 2026-07-25
27
+
28
+ ### Added
29
+
30
+ - random-effects inverse-variance results now provide opt-in Q-profile
31
+ confidence intervals for tau-squared, tau, I-squared, and H-squared, with an
32
+ explicit formal-empty-set flag at the constrained `[0, 0]` boundary.
33
+
34
+ ### Changed
35
+
36
+ - sensitivity and influence workflows now borrow internal fitted buffers during
37
+ refits instead of repeatedly materializing public defensive copies;
38
+ - Meta-regression stores its classic coefficient covariance alongside the
39
+ selected inference covariance and reuses one shared precision-geometry
40
+ implementation across fitting and diagnostics.
41
+ - independent `metafor` fixtures now cover categorical and multivariable
42
+ influence diagnostics, no-intercept Riley prediction intervals, and explicit
43
+ Mantel-Haenszel pooling correction; iterative failure paths have direct
44
+ regression tests.
45
+
46
+ ### Fixed
47
+
48
+ - inverse-variance means, heterogeneity statistics, and pooling and
49
+ meta-regression tau-squared equations now use overflow-safe relative-weight
50
+ calculations at the supported float64 boundary;
51
+ - subnormal variances and non-finite derived effects now raise explicit domain
52
+ errors instead of leaking runtime warnings or returning invalid results;
53
+ - binary OR, RD, and Mantel-Haenszel arithmetic now avoids intermediate
54
+ overflow for very large finite counts;
55
+ - the sensitivity guide no longer incorrectly states that Meta-regression
56
+ Cook's distance and DFBETAS are unavailable.
57
+ - subgroup-differences tests now use classic model variances independently of
58
+ Hartung-Knapp confidence-interval adjustments;
59
+ - leave-one-out and cumulative workflows now retain or skip, respectively,
60
+ reduced Mantel-Haenszel fits that are not estimable instead of aborting the
61
+ complete sensitivity analysis;
62
+ - forest and subgroup-forest plots now reject non-positive displayed
63
+ coordinates before enabling a logarithmic axis;
64
+ - uncorrected risk-ratio analyses now accept a zero non-event cell when the
65
+ study effect and sampling variance remain well defined.
66
+ - Hartung-Knapp random-effects prediction intervals now use the selected
67
+ adjusted pooled-mean variance and are recorded as `HK-PR`, matching
68
+ `metafor` Riley predictions;
69
+ - random-effects subgroup analyses now retain single-study subgroups through
70
+ an explicit, warned common-effect fallback instead of failing the complete
71
+ analysis;
72
+ - tagged releases now rerun the full branch-coverage test suite before
73
+ distributions can be built and published.
74
+ - tau-squared methods and SMD variance conventions now use `None` as the
75
+ context-sensitive default, so explicitly inapplicable settings raise domain
76
+ errors instead of being silently ignored;
77
+ - duplicate study labels now add a row-position warning while preserving
78
+ `row_id` as the unique audit key;
79
+ - report JSON now serializes `pd.NaT` study labels as `null` rather than the
80
+ string `"NaT"`.
81
+ - Meta-regression with `missing="drop"` now determines complete-row exclusions
82
+ before validating moderator values, so invalid values in already excluded
83
+ rows cannot abort the analysis;
84
+ - cumulative analysis now rejects ambiguous string `order` selectors that
85
+ exist in both source data and study results;
86
+ - empty inputs now report that at least one study row is required, and binary
87
+ zero-cell errors identify when `correction_scope="none"` disables an
88
+ otherwise positive correction.
89
+ - iterative tau-squared estimators now mark only an exact constrained zero as
90
+ a boundary solution, rather than treating every positive root below `atol`
91
+ as zero;
92
+ - the exported pooling and Meta-regression tau-squared estimators now reject
93
+ insufficient study or residual degrees of freedom with domain-specific
94
+ errors;
95
+ - the Mantel-Haenszel estimator now rejects empty and zero-total strata before
96
+ division, preventing NaN propagation and misleading variance diagnostics.
97
+ - prediction-interval metadata is now `None` when too few studies prevent an
98
+ interval from being calculated;
99
+ - categorical moderator encoding no longer conflates booleans, integers, and
100
+ floating-point values through Python's cross-type numeric equality;
101
+ - CI now covers Python 3.14, Pages deployments are not cancelled mid-flight,
102
+ and the credential-bearing PyPI publisher action is pinned to an immutable
103
+ commit.
104
+
105
+ ## 0.4.0 - 2026-07-23
106
+
107
+ ### Added
108
+
109
+ - leave-one-out Meta-regression refits with model-level diagnostics,
110
+ coefficient changes, explicit unidentifiable-deletion records, and preserved
111
+ provenance.
112
+ - exact Meta-regression externally standardized residuals, Cook's distances,
113
+ DFBETAS, transparent screening thresholds, and fixed-version R `metafor`
114
+ cross-software fixtures.
115
+ - Meta-regression term VIF, moderator-level GVIF/GSIF, and weighted,
116
+ column-scaled condition diagnostics with variance-decomposition proportions,
117
+ heuristic-only flags, and R `metafor` cross-software fixtures.
118
+ - explicit named Meta-regression linear contrasts with nonzero null values,
119
+ individual z/t inference, joint chi-squared/F tests, labeled coefficient
120
+ matrices, and R `metafor` cross-software fixtures.
121
+ - opt-in Riley Meta-regression true-effect prediction intervals using
122
+ `t_(k-p-1)`, with explicit residual-df validation, preserved refit
123
+ configuration, and fixed-version R `metafor` boundary references.
124
+
125
+ ## 0.3.0 - 2026-07-22
126
+
127
+ ### Added
128
+
129
+ - pandas-first `meta_regression()` for numeric, explicitly encoded categorical,
130
+ and multiple study-level moderators;
131
+ - common- and mixed-effects weighted regression with generalized DL, PM, and
132
+ REML residual tau-squared estimators;
133
+ - normal, Hartung-Knapp, and safeguarded Hartung-Knapp coefficient inference,
134
+ distribution-explicit moderator tests, residual heterogeneity, pseudo-R²,
135
+ prediction, provenance, and structured reports;
136
+ - optional weighted bubble plots for intercept-containing Meta-regression fits
137
+ with exactly one numeric moderator;
138
+ - independent R `metafor` fixtures covering numeric, categorical,
139
+ multivariable, zero-tau-squared, missing-row, and small-sample cases;
140
+ - an executable Meta-regression notebook plus a multivariable performance
141
+ baseline and expanded property, numerical-stability, and warning tests.
142
+
143
+ ### Changed
144
+
145
+ - report schema 1.2 adds the `meta_regression` report type.
146
+
147
+ ## 0.2.1 - 2026-07-17
148
+
149
+ ### Fixed
150
+
151
+ - README documentation and repository links use absolute URLs so they resolve
152
+ correctly when the project description is rendered on PyPI.
153
+
154
+ ## 0.2.0 - 2026-07-16
155
+
156
+ ### Added
157
+
158
+ - generic `meta_analysis()` accepts either sampling variances or standard
159
+ errors, with explicit validation and auditable conversion provenance.
160
+
161
+ ### Changed
162
+
163
+ - package author metadata identifies the project maintainer directly.
164
+
165
+ ### Fixed
166
+
167
+ - GitHub Release creation receives explicit repository context in tag-driven
168
+ release jobs.
169
+
170
+ ## 0.1.0 - 2026-07-15
171
+
172
+ ### Added
173
+
174
+ - pandas-first generic, binary, and continuous study-level meta-analysis APIs;
175
+ - common-effect and random-effects inverse-variance models;
176
+ - common-effect Mantel-Haenszel OR/RR pooling;
177
+ - REML, Paule-Mandel, and DerSimonian-Laird tau-squared estimators;
178
+ - normal, Hartung-Knapp, and safeguarded Hartung-Knapp confidence intervals;
179
+ - HTS random-effects prediction intervals;
180
+ - subgroup, leave-one-out, and cumulative workflows;
181
+ - optional Matplotlib forest, subgroup forest, and funnel plots;
182
+ - immutable results, diagnostics, provenance, Methods text, and JSON/Markdown
183
+ reports;
184
+ - R `metafor` cross-software fixtures, property tests, and numerical edge-case
185
+ coverage;
186
+ - explicit RD zero-variance boundary policy and heterogeneity-definition
187
+ reporting;
188
+ - complete MkDocs user, methods, API, validation, limitation, and development
189
+ documentation;
190
+ - R `meta`/`metafor` terminology and parameter mappings;
191
+ - machine-readable citation metadata and an executable end-to-end notebook;
192
+ - GitHub Pages and PyPI Trusted Publishing release workflows;
193
+ - release metadata, distribution-content, notebook-execution, and performance
194
+ baseline tooling.
195
+
196
+ ### Changed
197
+
198
+ - independent external statistical review is documented as a recommended
199
+ validation activity rather than a release requirement;
200
+ - report schema 1.1 records `heterogeneity.i2_method`;
201
+ - random-effects I-squared/H-squared use tau-squared and typical within-study
202
+ variance, while common-effect/MH analyses retain Q-based definitions;
203
+ - random-effects summaries provide method-selection notes for small-study and
204
+ positive-heterogeneity cases.
@@ -8,8 +8,8 @@ authors:
8
8
  - family-names: Ding
9
9
  given-names: Zhaobo
10
10
  email: ding.zb@yahoo.com
11
- version: 0.4.0
12
- date-released: 2026-07-23
11
+ version: 0.6.0
12
+ date-released: 2026-08-13
13
13
  repository-code: https://github.com/ZhaoboDing/PyMetaAnalysis
14
14
  url: https://zhaoboding.github.io/PyMetaAnalysis/
15
15
  license: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyMetaAnalysis
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Summary: A pandas-first, auditable meta-analysis library for Python
5
5
  Project-URL: Documentation, https://zhaoboding.github.io/PyMetaAnalysis/
6
6
  Project-URL: Source, https://github.com/ZhaoboDing/PyMetaAnalysis
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
21
22
  Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
22
23
  Requires-Python: >=3.10
23
24
  Requires-Dist: numpy>=1.24
@@ -132,14 +133,17 @@ not individual-level or causal effects.
132
133
  | Input | Effects | Pooling/models |
133
134
  | --- | --- | --- |
134
135
  | Effect + sampling variance or standard error | Generic | Common/random inverse variance |
135
- | Two-group events + totals | OR, RR, RD | Common MH OR/RR; common/random IV |
136
+ | Two-group events + totals | OR, RR, RD | Common MH; common Peto OR; common/random IV |
136
137
  | Two-group means + SDs + sizes | MD, Hedges' g | Common/random inverse variance |
137
138
  | Effect + variance/SE + moderators | Generic | Common/mixed Meta-regression |
138
139
 
139
140
  Random-effects inverse-variance models support REML (default), Paule-Mandel,
140
141
  and DerSimonian-Laird tau-squared estimators. Mean confidence intervals support
141
142
  the normal default plus unmodified and safeguarded Hartung-Knapp variants.
142
- Eligible random-effects fits include an HTS prediction interval.
143
+ Eligible random-effects fits include an HTS prediction interval under normal
144
+ inference and an HK-PR interval under either Hartung-Knapp variant. Call
145
+ `result.tau2_confidence_interval()` for a Q-profile interval around
146
+ heterogeneity.
143
147
 
144
148
  Generic analyses accept exactly one of `variance=` or `standard_error=`.
145
149
  Standard errors are squared internally and the conversion is recorded in the
@@ -149,6 +153,12 @@ Sparse binary behavior is explicit: study-level and Mantel-Haenszel continuity
149
153
  corrections are separate, relative-effect double-zero/double-all rows remain
150
154
  visible as exclusions, and RD exposes
151
155
  `rd_zero_variance="correct" | "exclude"`.
156
+ Peto OR uses raw tables for pooling and a separate one-step study estimator;
157
+ it always reports a caution that its approximation is intended for rare
158
+ outcomes, similar within-study arm sizes, and effects that are not large.
159
+ Common-effect MH risk differences use the Sato-Greenland-Robins sampling
160
+ variance; random-effects binary analyses continue to use inverse-variance
161
+ pooling.
152
162
 
153
163
  ## Inspect and report
154
164
 
@@ -157,6 +167,7 @@ result.estimate
157
167
  result.display_estimate
158
168
  result.ci
159
169
  result.tau2
170
+ tau2_interval = result.tau2_confidence_interval()
160
171
  result.i2
161
172
  result.i2_method
162
173
  result.diagnostics
@@ -247,7 +258,7 @@ python -m mkdocs serve
247
258
 
248
259
  The test suite combines hand calculations, statistical invariants, numerical
249
260
  edge cases, and committed R `metafor` reference fixtures. CI covers Python
250
- 3.10–3.13, declared dependency lower bounds, strict typing/linting, docs, and
261
+ 3.10–3.14, declared dependency lower bounds, strict typing/linting, docs, and
251
262
  distribution builds.
252
263
 
253
264
  This is independent cross-software validation, not a formal external
@@ -83,14 +83,17 @@ not individual-level or causal effects.
83
83
  | Input | Effects | Pooling/models |
84
84
  | --- | --- | --- |
85
85
  | Effect + sampling variance or standard error | Generic | Common/random inverse variance |
86
- | Two-group events + totals | OR, RR, RD | Common MH OR/RR; common/random IV |
86
+ | Two-group events + totals | OR, RR, RD | Common MH; common Peto OR; common/random IV |
87
87
  | Two-group means + SDs + sizes | MD, Hedges' g | Common/random inverse variance |
88
88
  | Effect + variance/SE + moderators | Generic | Common/mixed Meta-regression |
89
89
 
90
90
  Random-effects inverse-variance models support REML (default), Paule-Mandel,
91
91
  and DerSimonian-Laird tau-squared estimators. Mean confidence intervals support
92
92
  the normal default plus unmodified and safeguarded Hartung-Knapp variants.
93
- Eligible random-effects fits include an HTS prediction interval.
93
+ Eligible random-effects fits include an HTS prediction interval under normal
94
+ inference and an HK-PR interval under either Hartung-Knapp variant. Call
95
+ `result.tau2_confidence_interval()` for a Q-profile interval around
96
+ heterogeneity.
94
97
 
95
98
  Generic analyses accept exactly one of `variance=` or `standard_error=`.
96
99
  Standard errors are squared internally and the conversion is recorded in the
@@ -100,6 +103,12 @@ Sparse binary behavior is explicit: study-level and Mantel-Haenszel continuity
100
103
  corrections are separate, relative-effect double-zero/double-all rows remain
101
104
  visible as exclusions, and RD exposes
102
105
  `rd_zero_variance="correct" | "exclude"`.
106
+ Peto OR uses raw tables for pooling and a separate one-step study estimator;
107
+ it always reports a caution that its approximation is intended for rare
108
+ outcomes, similar within-study arm sizes, and effects that are not large.
109
+ Common-effect MH risk differences use the Sato-Greenland-Robins sampling
110
+ variance; random-effects binary analyses continue to use inverse-variance
111
+ pooling.
103
112
 
104
113
  ## Inspect and report
105
114
 
@@ -108,6 +117,7 @@ result.estimate
108
117
  result.display_estimate
109
118
  result.ci
110
119
  result.tau2
120
+ tau2_interval = result.tau2_confidence_interval()
111
121
  result.i2
112
122
  result.i2_method
113
123
  result.diagnostics
@@ -198,7 +208,7 @@ python -m mkdocs serve
198
208
 
199
209
  The test suite combines hand calculations, statistical invariants, numerical
200
210
  edge cases, and committed R `metafor` reference fixtures. CI covers Python
201
- 3.10–3.13, declared dependency lower bounds, strict typing/linting, docs, and
211
+ 3.10–3.14, declared dependency lower bounds, strict typing/linting, docs, and
202
212
  distribution builds.
203
213
 
204
214
  This is independent cross-software validation, not a formal external
@@ -2,6 +2,12 @@
2
2
 
3
3
  - Status: Accepted
4
4
  - Date: 2026-07-15
5
+ - Amendment: the prediction-interval variance decision is superseded by
6
+ [ADR 0004](0004-hartung-knapp-prediction-intervals.md).
7
+ - Amendment: the decision to defer Mantel-Haenszel risk differences is
8
+ superseded by [ADR 0005](0005-mantel-haenszel-risk-difference.md).
9
+ - Amendment: the decision to defer Peto pooling is superseded by
10
+ [ADR 0006](0006-peto-odds-ratio.md).
5
11
 
6
12
  ## Context
7
13
 
@@ -42,13 +48,15 @@ option, and a provenance transformation.
42
48
  Mantel-Haenszel pooling remains a common-effect estimator for OR and RR. It
43
49
  uses raw tables by default and has a correction setting separate from the one
44
50
  used for individual-study effects. Random-effects Mantel-Haenszel, RD
45
- Mantel-Haenszel, and Peto pooling are outside the current scope.
51
+ Mantel-Haenszel, and Peto pooling were outside the scope of this original
52
+ decision; ADRs 0005 and 0006 supersede the latter two deferrals.
46
53
 
47
54
  ### Heterogeneity
48
55
 
49
56
  Cochran's Q, degrees of freedom, and p-value always use common-effect inverse-
50
57
  variance weights. Common-effect and Mantel-Haenszel analyses use Q-based
51
- I-squared and H-squared.
58
+ I-squared and H-squared. ADR 0006 adds Peto's estimator-specific Q while
59
+ retaining those Q-based inconsistency transformations.
52
60
 
53
61
  Random-effects analyses use:
54
62
 
@@ -65,10 +73,11 @@ percentage in human-readable output.
65
73
 
66
74
  ### Prediction intervals
67
75
 
68
- Random-effects inverse-variance models use the Higgins-Thompson-Spiegelhalter
69
- prediction interval with `k - 2` degrees of freedom and the classic variance
70
- of the pooled mean. It is unavailable below three studies. With three or four
71
- studies it is calculated with an explicit uncertainty warning.
76
+ The original decision used the Higgins-Thompson-Spiegelhalter prediction
77
+ interval with `k - 2` degrees of freedom and the classic variance of the
78
+ pooled mean for every confidence-interval method. ADR 0004 replaces that
79
+ variance rule for Hartung-Knapp fits while retaining the study-count boundary
80
+ and small-sample warning.
72
81
 
73
82
  ## Validation
74
83
 
@@ -0,0 +1,46 @@
1
+ # ADR 0004: Hartung-Knapp prediction intervals
2
+
3
+ - Status: Accepted
4
+ - Date: 2026-07-24
5
+
6
+ ## Context
7
+
8
+ ADR 0002 applied the classic pooled-mean variance to every `k - 2`
9
+ random-effects prediction interval. That kept the interval independent of
10
+ `ci_method`, but it diverged from `metafor` Riley predictions and the
11
+ Hartung-Knapp Partlett-Riley option in R `meta`. Both use the covariance
12
+ selected for mean inference inside the prediction variance.
13
+
14
+ This difference was material when the unmodified Hartung-Knapp variance was
15
+ below or above the classic variance. The result metadata still identified the
16
+ interval as `HTS`, so callers could not discover the difference from method
17
+ configuration alone.
18
+
19
+ ## Decision
20
+
21
+ Random-effects inverse-variance prediction intervals retain the `k - 2`
22
+ critical value and three-study minimum:
23
+
24
+ ```text
25
+ mu_hat +/- t_(k - 2, 1 - alpha/2)
26
+ * sqrt(tau^2 + Var_selected(mu_hat))
27
+ ```
28
+
29
+ - normal inference uses the classic pooled-mean variance and records `HTS`;
30
+ - `hartung_knapp` uses its unmodified adjusted variance and records `HK-PR`;
31
+ - `hartung_knapp_adhoc` uses its lower-bounded adjusted variance and records
32
+ `HK-PR`.
33
+
34
+ Committed values are generated directly from
35
+ `metafor::predict(fit, predtype="Riley")` for all three inference choices.
36
+ Prediction intervals remain unavailable below three included studies and
37
+ retain the explicit warning with three or four studies.
38
+
39
+ ## Consequences
40
+
41
+ - prediction intervals and mean intervals use a coherent selected covariance;
42
+ - HK and safeguarded HK prediction intervals can differ from the normal HTS
43
+ interval even when tau-squared and the pooled estimate are unchanged;
44
+ - `result.method.prediction_interval_method` distinguishes `HTS` from
45
+ `HK-PR`;
46
+ - this decision supersedes only the prediction-variance paragraph of ADR 0002.
@@ -0,0 +1,65 @@
1
+ # ADR 0005: Mantel-Haenszel risk difference
2
+
3
+ - Status: Accepted
4
+ - Date: 2026-08-13
5
+ - Supersedes: the RD exclusion from the Mantel-Haenszel scope in
6
+ [ADR 0002](0002-statistical-policy.md)
7
+
8
+ ## Context
9
+
10
+ ADR 0002 limited Mantel-Haenszel pooling to common-effect odds ratios and risk
11
+ ratios while the risk-difference estimator and its variance convention were
12
+ still undecided. This left inverse variance as the only pooling method for RD,
13
+ although conventional R implementations provide a common-effect MH RD.
14
+
15
+ The point estimator is straightforward, but several variance estimators have
16
+ appeared in the literature. The selected rule must work under both large-
17
+ stratum and sparse-data limiting models, preserve treatment/control symmetry,
18
+ and remain explicit in reports and cross-software validation.
19
+
20
+ ## Decision
21
+
22
+ PyMetaAnalysis supports `measure="RD", method="MH", model="common"`. With
23
+ treatment total `n1_i`, control total `n0_i`, total `N_i`, and
24
+ `w_i = n1_i n0_i / N_i`, the estimate is:
25
+
26
+ ```text
27
+ RD_i = a_i / n1_i - c_i / n0_i
28
+ RD_MH = sum(w_i RD_i) / sum(w_i)
29
+ ```
30
+
31
+ The normal confidence interval uses the Sato-Greenland-Robins sampling
32
+ variance. The resolved method options record
33
+ `mh_rd_variance="Sato-Greenland-Robins"`.
34
+
35
+ Raw tables are used for MH pooling by default. `mh_continuity_correction` and
36
+ `mh_correction_scope` remain the only settings that alter MH pooling tables;
37
+ the separate study-effect correction continues to control displayed study
38
+ uncertainty and the inverse-variance heterogeneity calculation. The existing
39
+ `rd_zero_variance` policy determines whether boundary studies enter all
40
+ synthesis calculations. A non-positive pooled Sato variance raises a domain
41
+ error instead of silently adding a correction.
42
+
43
+ Random-effects MH remains unsupported. Random-effects RD continues to use
44
+ inverse-variance pooling with an explicit tau-squared estimator.
45
+
46
+ ## Validation
47
+
48
+ - direct formula tests cover the estimate, Sato variance, weights, and normal
49
+ interval;
50
+ - treatment/control swaps negate the estimate and mirror its interval without
51
+ changing the standard error;
52
+ - row reordering and common count scaling preserve the expected invariants;
53
+ - extreme finite counts exercise the overflow-safe scaled implementation;
54
+ - boundary-policy, explicit-correction, subgroup, leave-one-out, and
55
+ cumulative paths are covered; and
56
+ - fixed-version `metafor::rma.mh(measure="RD")` fixtures cover ordinary,
57
+ sparse, and explicitly corrected tables.
58
+
59
+ ## Consequences
60
+
61
+ - common-effect OR, RR, and RD all support MH or inverse-variance pooling;
62
+ - study-table MH weights for RD are proportional to `n1_i n0_i / N_i`;
63
+ - the selected RD variance convention is recoverable from method metadata and
64
+ generated reports; and
65
+ - documentation must continue to distinguish MH RD from random-effects IV RD.
@@ -0,0 +1,87 @@
1
+ # ADR 0006: Peto one-step odds ratio
2
+
3
+ - Status: Accepted
4
+ - Date: 2026-08-13
5
+ - Supersedes: the Peto deferral in
6
+ [ADR 0002](0002-statistical-policy.md)
7
+
8
+ ## Context
9
+
10
+ Peto's one-step method is a conventional common-effect estimator for binary
11
+ outcomes and is particularly associated with rare-event meta-analysis. It is
12
+ not interchangeable with an ordinary inverse-variance odds ratio: it derives
13
+ both the study contribution and pooled estimate from observed-minus-expected
14
+ events and hypergeometric information.
15
+
16
+ The approximation can be biased when treatment and control group sizes differ
17
+ substantially within studies, effects are large, or events are not rare. Its
18
+ zero-cell behavior also differs from ordinary log odds ratios, so pooling and
19
+ display corrections must not be conflated.
20
+
21
+ ## Decision
22
+
23
+ PyMetaAnalysis supports `measure="OR", method="Peto", model="common"` with
24
+ `ci_method="normal"`. `"peto_one_step"` is an accepted alias and the resolved
25
+ pooling method is `"peto"`.
26
+
27
+ For stratum `i`, let `O_i = a_i`, `m_i = a_i + c_i`, treatment and control
28
+ totals be `n1_i` and `n0_i`, and `N_i = n1_i + n0_i`. Define:
29
+
30
+ ```text
31
+ E_i = m_i n1_i / N_i
32
+ V_i = m_i (N_i - m_i) n1_i n0_i / (N_i^2 (N_i - 1))
33
+ ```
34
+
35
+ The individual and pooled model-scale estimates are:
36
+
37
+ ```text
38
+ y_i = (O_i - E_i) / V_i
39
+ Var(y_i) = 1 / V_i
40
+ y_Peto = sum(O_i - E_i) / sum(V_i)
41
+ Var(y_Peto) = 1 / sum(V_i)
42
+ ```
43
+
44
+ Pooling always uses raw 2-by-2 tables. The existing
45
+ `continuity_correction` and `correction_scope` settings affect only displayed
46
+ study estimates and variances; there is no Peto pooling correction parameter.
47
+ Double-zero and double-all rows are excluded before every synthesis
48
+ calculation because they contain no relative-effect information.
49
+
50
+ Peto heterogeneity uses the fitted pooled coefficient and the same
51
+ observed-minus-expected contributions:
52
+
53
+ ```text
54
+ Q = sum(((O_i - E_i) - y_Peto V_i)^2 / V_i)
55
+ ```
56
+
57
+ Q-based I-squared and H-squared follow the project's common-effect
58
+ conventions. Method options record `peto_pooling_tables="raw"` and
59
+ `peto_heterogeneity="O-minus-E"`. Every Peto result carries an approximation
60
+ warning naming the rare-outcome, balanced-arm, and modest-effect conditions.
61
+
62
+ Random-effects Peto and Peto RR/RD are unsupported. Users requesting those
63
+ estimands must select an implemented inverse-variance or Mantel-Haenszel
64
+ combination explicitly.
65
+
66
+ ## Validation
67
+
68
+ - direct formula tests cover study estimates, pooled estimate, variance,
69
+ weights, confidence interval, and Peto Q;
70
+ - treatment/control swapping reverses and exponentiates the log-OR limits as
71
+ expected, while row order leaves the fit unchanged;
72
+ - count scaling and extreme finite-count tests exercise overflow-safe
73
+ arithmetic;
74
+ - sparse tables verify that study-level correction does not alter raw Peto
75
+ pooling and that double-zero/double-all rows are excluded; and
76
+ - fixed-version `metafor::escalc(measure="PETO")` and `metafor::rma.peto()`
77
+ fixtures cover ordinary and sparse datasets.
78
+
79
+ ## Consequences
80
+
81
+ - common-effect binary OR now offers MH, Peto, and inverse-variance pooling;
82
+ - Peto results remain on the log-OR model scale and use exponentiated display
83
+ values like other OR results;
84
+ - sensitivity, subgroup, provenance, reporting, and plotting workflows reuse
85
+ the same public result contracts; and
86
+ - documentation and reports must preserve the Peto applicability warning
87
+ rather than presenting it as a general sparse-data default.
@@ -11,7 +11,7 @@ cd PyMetaAnalysis
11
11
  python -m pip install -e ".[test,dev,docs,plot]"
12
12
  ```
13
13
 
14
- Use a supported Python version (3.10–3.13). Keep changes focused and preserve
14
+ Use a supported Python version (3.10–3.14). Keep changes focused and preserve
15
15
  unrelated worktree modifications.
16
16
 
17
17
  ## Run checks
@@ -31,7 +31,7 @@ python -m build
31
31
  python tools/inspect_distribution.py dist
32
32
  ```
33
33
 
34
- The CI matrix also tests Python 3.10–3.13 and declared dependency lower bounds.
34
+ The CI matrix also tests Python 3.10–3.14 and declared dependency lower bounds.
35
35
  Install the `notebook` extra before running the notebook executor.
36
36
 
37
37
  ## Statistical changes