Skip to content

Add Python 3.15 support - #843

Open
ilgrad wants to merge 1 commit into
igerber:mainfrom
ilgrad:feat/python-3.15
Open

ilgrad wants to merge 1 commit into
igerber:mainfrom
ilgrad:feat/python-3.15

Conversation

@ilgrad

@ilgrad ilgrad commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Adds Python 3.15 to the supported range, following the pattern of #284 (Python 3.14).

CPython 3.15.0 is final, but diff-diff 3.12.0 declares requires-python = ">=3.9,<3.15". On 3.15 (checked with pip 26.2.1 and uv 0.13.0):

  • pip install diff-diff skips every release from 2.3.2 on, since each one carries an upper cap, and silently installs 2.3.1, the last release without one. pip install diff-diff==3.12.0 fails: "Ignored the following versions that require a different python version: ... 3.12.0 Requires-Python >=3.9,<3.15".
  • uv pip install diff-diff ignores the upper bound and selects 3.12.0, but there is no cp315 wheel, so it builds the sdist, which needs a Rust toolchain.

Changes

  • pyproject.toml: requires-python <3.15 -> <3.16, add the Programming Language :: Python :: 3.15 classifier.
  • build-wheels.yml (used by publish.yml and release-build-check.yml): build cp315 wheels on Linux x86_64 / aarch64 (/opt/python/cp315-cp315 ships in the current manylinux_2_28 images), macOS arm64 and Windows.
  • rust-test.yml: add 3.15 to the python-tests matrix (all four OSes); move the Pure Python Fallback job from 3.14 to 3.15, as Add Python 3.14 support #284 moved it from 3.13 to 3.14.
  • docs-tests.yml: the doc-snippets job follows the fallback job to 3.15 (its comment says it mirrors that job); the two comments naming 3.14 are updated.
  • release-build-check.yml, README.md, the rust/Cargo.toml comment: the supported range now reads 3.9-3.15.
  • changelog.d/20261011-python-3-15.md (### Added).

No Rust dependency change: PyO3 0.29 supports 3.15 (0.29.0: "Support Python 3.15.0b1", PyO3/pyo3#6014), and with no committed Cargo.lock, pyo3 = "0.29" resolves to 0.29.3. The extension is not built for abi3, so per-version wheels stay the model and PYO3_USE_ABI3_FORWARD_COMPATIBILITY is not needed for 3.15. numpy 2.5.4, scipy 1.18.1, pandas 3.0.6 and scikit-learn 1.9.1 publish cp315 wheels, so the CI install steps need no source builds.

Not changed: the Lint workflow stays on 3.14 (tool pins, not the support surface); no free-threaded (3.15t) wheels or CI legs, since the project builds none for 3.14t either.

Methodology references (required if estimator / math changes)

  • Method name(s): N/A, no estimator or math changes.
  • Paper / source link(s): N/A
  • Any intentional deviations from the source (and why): N/A

Validation

  • Tests added/updated: none; the existing suite run on 3.15 and on 3.14 for comparison.
  • Local runs, Linux x86_64 (Fedora 44), the rust-test.yml Linux steps reproduced in a fresh venv per interpreter: maturin build --release --features extension-module,openblas, install the wheel, run from a copy of tests/ outside the source tree. Dependencies resolved to numpy 2.5.4, pandas 3.0.6, scipy 1.18.1, scikit-learn 1.9.1, pytest 9.1.1, pytest-xdist 3.8.0, maturin 1.15.0, Rust 1.99.0, PyO3 0.29.3.
Run CPython 3.15.0 CPython 3.14.7
pytest tests/test_rust_backend.py -m '' 200 passed 200 passed
DIFF_DIFF_BACKEND=rust pytest tests/ --ignore=tests/test_doc_snippets.py -n 4 --dist worksteal -m '' 12398 passed, 2141 skipped 12398 passed, 2141 skipped
Pure Python fallback: PYTHONPATH=. DIFF_DIFF_BACKEND=python pytest tests/ --ignore=tests/test_rust_backend.py --ignore=tests/test_doc_snippets.py -n 4 --dist worksteal 14336 passed, 358 skipped 14336 passed, 358 skipped
Doc snippets: PYTHONPATH=. DIFF_DIFF_BACKEND=python pytest tests/test_doc_snippets.py 161 passed, 7 skipped 161 passed, 7 skipped

No failures. Per-test outcomes are identical on 3.15 and 3.14 (compared test by test from the JUnit XML), and so are the warning categories. The skips are the isolated-install and missing-fixture skips (openai_review.py not in the checkout, R / Stata golden files, matplotlib not installed), the same on both. The 3.14 runs use this branch, whose Python and Rust sources are identical to main.

  • Release path: the build-linux loop of build-wheels.yml, run in quay.io/pypa/manylinux_2_28_x86_64 for cp314 and cp315, builds both manylinux_2_28_x86_64 wheels; the cp315 wheel installs into a 3.15.0 venv with HAS_RUST_BACKEND == True, and tests/test_rust_backend.py gives 200 passed.

  • Backtest / simulation / notebook evidence (if applicable): N/A

  • Not run: macOS, Windows and aarch64 (CI covers them); the Rust unit tests (cargo test, a job with no Python matrix, unchanged here); the Lint workflow (no Python source changed); the notebooks and mmm-interop workflows.

CI has not run yet: the fork's workflow runs are waiting for a maintainer's approval, and the test jobs also need the ready-for-ci label.

Security / privacy

  • Confirm no secrets/PII in this PR: Yes

Changelog

  • changelog.d/ fragment added (or N/A - no user-visible change): changelog.d/20261011-python-3-15.md

CPython 3.15.0 is final, but requires-python capped the package at <3.15:
pip on 3.15 falls back to diff-diff 2.3.1, and uv builds the sdist. Raise
the cap, add the classifier, build cp315 wheels on every platform and add
3.15 to the Rust-backend CI matrix; the pure-Python fallback and the doc
snippets move to 3.15 as they moved to 3.14 in igerber#284. PyO3 0.29 already
supports 3.15.
@ilgrad
ilgrad requested a review from igerber as a code owner October 11, 2026 20:05

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant