From 9ec9622200ba068a7c7908fc23401152682482de Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 16 Sep 2026 23:29:57 +0000 Subject: [PATCH] Cover CPython 3.14 and the sub-interpreter backend in CI The sub-interpreter backend needs 3.14+, and nothing in the matrix ran it: unit tests stopped at 3.13 and the only free-threaded job was 3.13t, which cannot create a cell at all. Add 3.14 to the unit matrix, and a `sub-interpreter cells / py3.14t` job that runs the backend suite on a free-threaded build. That job asserts up front that the interpreter really is a free-threaded 3.14 before running any tests. Every sub-interpreter test skips itself when the build cannot run it -- which is correct for the 3.11-3.13 matrix, but it means a runner that silently resolved to an older Python would skip everything and report the job green having tested nothing. Failing loudly is the difference between a job that covers the backend and a job that looks like it does. Dependency installation follows the existing 3.13t job: install without the runtime deps that may not have free-threaded wheels, then re-add the pure-Python ones the import path needs. Nothing in this job's scope needs real crypto, and the suite's stub covers it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Fs1hTtmF4Hm9h617AG9Gse --- .github/workflows/ci.yml | 36 +++++++++++++++++++++++++++++++++++- CHANGELOG.md | 7 +++++++ pyproject.toml | 1 + 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b58adeb..682cedb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, ubuntu-24.04] - python-version: ["3.11", "3.12", "3.13"] + python-version: ["3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -101,6 +101,40 @@ jobs: continue-on-error: true run: pytest -q tests/test_matrix_hardening.py -m "race and no_gil" + tests-subinterpreter: + name: sub-interpreter cells / py3.14t + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.14t" + - name: Install dependencies + # Same shape as the 3.13t job: install without the runtime deps that + # may not have free-threaded wheels yet, then re-add the pure-Python + # ones the import path needs. The suite's crypto stub (tests/conftest.py) + # covers the rest, and nothing in this job's scope needs real crypto. + run: | + python -m pip install -e . --no-deps + python -m pip install pytest pyyaml platformdirs + - name: Verify this build actually has sub-interpreters + # Every sub-interpreter test skips itself when the build cannot run it. + # That is right for the 3.11-3.13 matrix, but it means this job would + # report green on a runner that silently resolved to an older Python + # while testing nothing. Fail loudly instead. + run: | + python - <<'PY' + import sys + from pyisolate.runtime import subinterpreter as s + assert s.is_available(), f"no concurrent.interpreters on {sys.version}" + assert not sys._is_gil_enabled(), "expected a free-threaded build" + print("ok:", sys.version) + PY + - name: Run the sub-interpreter backend suite + run: pytest -q tests/test_subinterpreter_backend.py tests/test_supervisor.py + - name: Validate the no-GIL readiness axis on 3.14t + run: pytest -q tests/test_nogil.py + tests-soak: name: soak / 2k spawn-kill cycles if: github.event_name == 'schedule' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b5c73a..8ab2d57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,13 @@ guarantees; **no release should be treated as a hardened security boundary**. - `pyisolate[operator]` optional-dependency group for the Kubernetes operator. ### Changed +- CI covers CPython 3.14: the unit matrix gains `3.14`, and a new + `sub-interpreter cells / py3.14t` job runs the sub-interpreter backend on a + free-threaded build. That job asserts the interpreter really is a + free-threaded 3.14 before running anything, because every sub-interpreter + test skips itself when the build cannot run it -- correct for the 3.11-3.13 + matrix, but it would otherwise let the job report green having tested + nothing. - `backend="subinterpreter"` is renamed to `backend="thread"`, which is what it has always run, and the `subinterpreter` name now selects the real sub-interpreter backend. `DEPRECATED_BACKEND_ALIASES` is exported alongside diff --git a/pyproject.toml b/pyproject.toml index 6a99980..17500ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Security", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Systems Administration",