Widen supported Python versions to 3.9-3.12 - #2
Merged
Conversation
pyproject.toml: requires-python ">=3.9,<3.10" -> ">=3.9,<3.13" (Python 3.9 alone is EOL as of October 2025). Added trove classifiers for 3.10, 3.11, 3.12. No dependency versions changed -- numpy/scipy/tensorflow/ gpflow/tfp/tf-keras/setuptools<81 are exactly as pinned before. 3.13+ is not attempted: GPflow requires numpy<2 in every release (including the latest 2.11.1), and no numpy 1.x publishes a cp313 wheel -- an upstream constraint, not a consequence of our pinning. TensorFlow's newest release also has no cp314 wheels. Python 3.12 is therefore the hard ceiling until GPflow supports numpy 2. .github/workflows/ci.yml: split into a `lint` job (ruff, once, on 3.9) and a `test` job running the full default suite across a 3.9/3.10/3.11/ 3.12 matrix (fail-fast: false, so one version's failure doesn't hide the others' results). Still no Julia in CI; `pytest -q`'s own `-m 'not vle'` addopts keeps deselecting the Julia-backed tests. .readthedocs.yaml: build tool Python 3.9 -> 3.12 (the top of the newly supported range), so autodoc's real import of the TF-backed stack exercises the newest interpreter rather than the oldest. environment.yml intentionally NOT touched yet -- that decision is deferred until Stage 3's Python 3.12 reproduction rerun confirms (or doesn't) that the dev/reproduction environment can safely move there. Verified on the existing Python 3.9 dev env: pytest -q (204 passed, 2 deselected, unchanged), ruff clean, and pyproject.toml round-trips through tomli with the intended requires-python/classifiers. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs/installation.md: the "Frozen dependency stack" admonition now states Python 3.9-3.12 explicitly (was silently implying 3.9-only via "Python 3.9, NumPy 1.26, ..."). Added a dedicated "Why not Python 3.13+?" admonition: GPflow requires numpy<2 in every release including the latest, no NumPy 1.x publishes a Python 3.13 wheel, and TensorFlow has no Python 3.14 wheels either -- stated as an upstream constraint this package cannot work around, with no timeline promised. README.md: added the same "Supports Python 3.9-3.12" statement (with a pointer to docs/installation.md for the full explanation) next to the pip install instructions, where previously there was no Python-version statement at all. CHANGELOG.md: [Unreleased] now describes the widened requires-python, the verification performed (full suite + regression pins on all four versions, no dependency version changed), the CI matrix, and the RTD Python bump -- no version number or date invented. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…n rerun environment.yml: python=3.9 -> python=3.12, now that Stage 3's from- scratch paper/full_reproduction.py rerun on 3.12 has confirmed the science holds (see paper/REPRODUCTION.md's new section). Every other pin is unchanged. Header comment explains the decision and how to get a python=3.9 env instead, for anyone who specifically wants the interpreter the archived published results were produced on. docs/installation.md: updated the "conda env create" comment to match. paper/REPRODUCTION.md: adds "Cross-Python-version check: the same rerun on Python 3.12" -- a from-scratch ~28-minute full_reproduction.py run compared against the existing Python 3.9 fresh-run numbers: - Iterations 1-2's max entropy match the 3.9 run to 6+ significant figures (1.4576908 vs 1.4577; 1.2470073 vs 1.2470) -- striking, given no bitwise-reproducibility guarantee exists across interpreters. - From iteration 3 on the two runs' design trajectories diverge, as expected: each iteration's posterior-predictive diagnostic draws from TensorFlow's ambient, unseeded RNG (mixture.py's documented non-reproducibility applies across interpreters, same as within one). - R-hat/ESS at iteration 15: 1.00527/1.00736/1.00879 and 1468.06/2424.94/653.15 (3.12) vs 1.00523/1.00730/1.00879 and 1468.29/2428.09/653.15 (3.9) -- both comfortably converged. - Hyperparameter posterior: same lengthscale_2 > lengthscale_1 ordering; mean/median within ~0.1% of the 3.9 run. - Test RMSE: 4.385 -> 0.856 (iter 1 -> 15, ~5.1x), matching the 3.9 run's ~4.9x and the paper's own ~6.5x reduction. - Both Wilson and surrogate McCabe-Thiele columns converged, tracking each other within 0.027 (liquid) / 0.014 (vapor) mole fraction at every stage -- inside the existing 0.03/0.014 tolerance band. Conclusion: Python 3.12 gives statistically equivalent science to Python 3.9. Run artifacts stayed in the gitignored results_remaked/, per usual; not committed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Widens supported Python versions from
>=3.9,<3.10to>=3.9,<3.13, verified withreal runs on every claimed version plus a full from-scratch ~28-minute stochastic
reproduction rerun on 3.12. No dependency version changed and no tolerance or
reference/baseline file was touched — see the guardrails section below.
Stage 2: verification table (version × check)
Each version installed into a fresh conda env (
conda create -n ... python=X.Y pip,then
pip install -e ".[dev]"), never reusing another version's env.pytest -qtest_matches_synthetic_baseline(atol=1e-10)pytest -q tests/regressionbits_for_gapsJulia-free/TF-lazy)AnisotropicSE())setuptools.__version__(the<81bound)Every version resolved the exact same pinned stack (numpy 1.26.4, scipy 1.13.1,
tensorflow/tensorflow-macos 2.16.2, gpflow 2.9.2, tensorflow-probability 0.24.0,
tf-keras 2.16.0) from
pip install -e ".[dev]"alone — no version-specific dependencyresolution surprises. All four temporary conda envs (
bfg-py310,bfg-py311,bfg-py312) were removed after use; only the pre-existingbits_for_gaps(3.9) devenv remains.
Stage 3: reproduction on Python 3.12
In the
bfg-py312env withpip install -e ".[dev,vle]"andPYTHON_JULIACALL_HANDLE_SIGNALS=yes:pytest -m vle: 2 passed — Julia/Clapeyron work fine on 3.12.python paper/reproduce.py: all 11 figures regenerated frompaper/data/in~66 seconds wall-clock. Spot-checked two rendered PNGs (the Wilson McCabe-Thiele
diagram and the HMC trace plot) — both render correctly, R-hat ≈ 1.005–1.009 on the
trace plot.
python paper/full_reproduction.py(the 15-iteration adaptive HMC + acquisitionloop, from scratch, no archived data as input): completed in 0.47 h (28 min),
inside the documented ~25–30 min range. Compared against the existing Python 3.9
fresh-run numbers already recorded in
paper/REPRODUCTION.md(full write-up addedin this PR, "Cross-Python-version check" section):
Iterations 1–2's max entropy matched to 6+ significant figures — striking,
given no bitwise-reproducibility guarantee exists across interpreters. From
iteration 3 on, the two runs' design trajectories diverge, as expected: each
iteration's posterior-predictive diagnostic draws from TensorFlow's ambient,
unseeded RNG (already documented as non-reproducible in
mixture.py's moduledocstring — this is the same non-reproducibility that already separates two
independent runs within one Python version, not something new to 3.12). Despite
that divergence, every statistical conclusion holds: R-hat/ESS stay comfortably
converged, the hyperparameter-posterior ordering (
lengthscale_2>lengthscale_1) is preserved, entropy still decays and crosses zero in the sameiteration range, test RMSE still drops by a comparable factor, and both McCabe-
Thiele columns still converge and track each other within the same tolerance band
already used elsewhere in this repo (0.03/0.014).
Conclusion: Python 3.12 gives statistically equivalent science to Python 3.9.
Run artifacts stayed in the gitignored
results_remaked/; nothing was committed.environment.ymldecisionMoved to Python 3.12 (from 3.9), since Stage 3's rerun came out clean on every
axis above. The dev/reproduction environment now uses the top of the newly-supported
range, so day-to-day development and the
paper/reproduce.py/paper/full_reproduction.pyscripts exercise the newest supported interpreter bydefault. The file's header comment explains the decision and gives the one-line
change (
python=3.12→python=3.9) for anyone who specifically wants theinterpreter the archived published results (
paper/data/,paper/reference/) wereoriginally produced on — every other pin in the file is unaffected either way.
No dependency version changed; no tolerance or reference file touched
numpy,scipy,tensorflow/tensorflow-macos,gpflow,tensorflow-probability,tf-keras, and thesetuptools<81bound are byte-for-byte identical to what wason
main. Confirmed in the built wheel'sRequires-Distmetadata (see Stage 5below) and by diffing
pyproject.toml'sdependencieslist.tests/integration/data/synthetic_baseline.jsonandpaper/reference/*.jsonwerenot modified (
git diff main -- tests/integration/data paper/referenceis empty) —every version's
test_matches_synthetic_baselineandtests/regressionrun passedagainst the existing files, at the existing tolerances.
paper/data/andpaper/reference/contents untouched.Why Python 3.13+ is not supported (upstream constraint)
bits_for_gapsdepends on GPflow, and GPflow requiresnumpy<2in every releaseit has ever published, including the latest (2.11.1). No NumPy 1.x release
publishes a Python 3.13 wheel — the first NumPy version that does is 2.1.0. So GPflow
(and therefore this package) cannot run on Python 3.13 at all, no matter what this
package's own pins say. TensorFlow's newest release (2.21.0) also publishes no Python
3.14 wheels. Python 3.12 is the hard ceiling until GPflow adds NumPy 2 support
upstream — no timeline is promised or implied. Documented in
docs/installation.md(a dedicated "Why not Python 3.13+?" admonition),README.md,and
CHANGELOG.md.Stage 5: final gates
pytest -q: 204 passed, 2 deselected on both 3.9 and 3.12 (re-verified afterevery commit on this branch).
pytest -m vle: 2 passed on 3.9.ruff check .: clean.sphinx-build -W docs docs/_build/html(clean rebuild): clean, no warnings/errors.python -m build+twine check dist/*: both sdist and wheel PASSED. Wheelmetadata confirms
Requires-Python: <3.13,>=3.9and everyRequires-Distpinunchanged (
numpy<2,>=1.26,scipy<1.14,>=1.13,gpflow==2.9.2,tensorflow-probability==0.24.0,tf-keras==2.16.0,tensorflow(-macos)==2.16.2,setuptools<81).dist//build/removed after inspection.Files changed
pyproject.toml:requires-pythonwidened; classifiers for 3.10/3.11/3.12 added..github/workflows/ci.yml: split into alintjob (ruff, once) and atestjobmatrixed across Python 3.9–3.12.
.readthedocs.yaml: build Python 3.9 → 3.12.environment.yml:python=3.9→python=3.12(see decision above).docs/installation.md,README.md,CHANGELOG.md: document the widened supportand the 3.13+ upstream-constraint explanation.
paper/REPRODUCTION.md: new "Cross-Python-version check" section with the Stage 3numbers above.
🤖 Generated with Claude Code