chore: raise the Python floor to 3.14, and record why it moved back up - #546
Merged
Conversation
Reverses #283. That decision was measured and correct at the time, so this commit is careful to record what changed rather than just flip a number -- tests/test_python_floor.py's docstring carries the whole argument. What #283 measured still stands: 3.13, 3.12 and 3.11 all pass identically to 3.14, and nothing in this code needs 3.14. `assert_never` (3.11+) was the one binding feature, and 3.10 still fails collection on it. So this is a POLICY floor, not a measured one, and the docstring says so in those words -- the two must not be confused by whoever revisits it. Two things changed around the measurement: - Users stopped supplying the interpreter. #283 predates the signed desktop bundle (D5) and scripts/install.sh, both of which bootstrap their own environment. The floor now reaches contributors and packagers, not everyone who installs -- a far smaller group, and one that can install a Python. - 3.14 was days old when #283 was decided. It is packaged now. And it unblocks two things that were blocked ON the old floor, both verified here rather than assumed: - ruff can target py314. It could not before: under py314 against a >=3.11 floor, `ruff format` rewrote `except (A, B, C):` into PEP 758's unparenthesised form, a SyntaxError on 3.11-3.13. Raising the floor removes the interpreter that could not parse it, so the hazard is gone rather than tolerated. `ruff check` is clean at py314 with no new UP violations. - The `numpy.*` mypy override is deleted. numpy's bundled stubs use PEP 695 `type` statements that a python_version="3.11" run cannot parse, so the workspace silenced the transitive crawl instead of raising the floor. mypy now passes clean without it -- 359 source files. CI collapses to one leg. Two legs existed to test the two ends of a span that no longer exists; it stays a matrix rather than a scalar so a second version is one list entry. Three places stated the floor by literal and now derive it: the installer gate in tests/test_install_script.py, the CI leg, and the docs. The docs assertion was tightened after it FALSE-PASSED -- `"3.14" in readme` matched "any Python 3.11+ (the repo develops on 3.14)", so the stated floor stayed wrong while the test stayed green. It now requires the `3.14+` form. The `assert_never` binding-feature test is deleted with no successor, which is the point: a policy floor has no binding feature, and asserting one would state a reason that is not the reason. Superseded floors are left cited in CONTRIBUTING.md and the docstrings on purpose, and the docs test deliberately does not scan for them -- a scan would punish the record-keeping this project asks for. Gates: ruff clean; mypy clean, 359 files; 4665 passed, 3 skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NyeggYtojNXCTHeD3JHxb6
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.
Support only Python 3.14 and above.
This reverses #283, which was a measured decision, so the change is careful to record what shifted rather than just flip a number. The whole argument lives in
tests/test_python_floor.py's docstring, which is the file that exists to keep this honest.The measurement from #283 still stands
3.13, 3.12 and 3.11 all pass identically to 3.14. Nothing in this code needs 3.14.
assert_never(3.11+) was the one binding feature, and 3.10 still fails collection on it.So this is a policy floor, not a measured one, and the docstring says so in those words. The two must not be confused by whoever revisits this.
What changed around the measurement
scripts/install.sh, both of which bootstrap their own environment. The floor now reaches contributors and packagers rather than everyone who installs — a far smaller group, and one that can install a Python.What it unblocks — both verified, not assumed
ruffcan targetpy314. It could not before, andruff.tomlrecorded exactly why: underpy314against a>=3.11floor,ruff formatrewroteexcept (A, B, C):into PEP 758's unparenthesised form — a SyntaxError on 3.11–3.13, which the metadata then invited. Raising the floor removes every interpreter that cannot parse it, so the hazard is gone rather than tolerated.ruff checkis clean atpy314with no newUPviolations.The
numpy.*mypy override is deleted. numpy's bundled stubs use PEP 695typestatements that apython_version = "3.11"run cannot parse, so the workspace silenced the transitive crawl —follow_imports = "skip"plusfollow_imports_for_stubs— rather than raise the floor every package pins. mypy now passes clean without it, 359 source files.CI collapses to one leg
Two legs existed to test the two ends of a span that no longer exists. It stays a
matrixrather than a scalar so a second supported version is one list entry, and so the required status context staystesteither way.Three literals became derivations
The installer gate (
tests/test_install_script.py), the CI leg, and the docs check all now derive the floor fromrequires-pythoninstead of repeating it. Raising or lowering it again is one edit plus the docstring.The docs assertion was tightened because it false-passed.
"3.14" in readmematched "any Python 3.11+ (the repo develops on 3.14)" — the development pin satisfied the test while the stated floor stayed wrong. It now requires the3.14+form. The Arabic mirror is checked for the version alone, because "3.14 فما فوق" is better Arabic than transliterating the English token.One test deleted with no successor
test_the_binding_feature_that_sets_the_floor_still_existsassertedassert_neverwas still imported. That was right for a measured floor of 3.11 and is meaningless at 3.14 — it binds nothing. A policy floor has no binding feature, and asserting one would state a reason that is not the reason. The absence is deliberate and the docstring says so.Superseded floors stay cited in
CONTRIBUTING.mdand in the docstrings on purpose, and the docs test deliberately does not scan for them — a scan would punish exactly the record-keeping the contribution guide asks for.Files
8 ×
requires-python·ruff.toml· mypypython_versionand the numpy override ·ci.yml·release.yml·scripts/install.sh·packaging/macos_app.sh· README, README.ar, CONTRIBUTING,docs/desktop-install.md,docs/launch.md· 4 test files ·uv.lockGates
ruff check keel tests packages— All checks passedmypy— no issues in 359 source filespytest -q— 4665 passed, 3 skippeduv lock --check— currentNote
If the floor blocks a contributor, that is the argument that would lower it again — and there is no feature standing in the way.
CONTRIBUTING.mdnow says so explicitly and invites the issue.🤖 Generated with Claude Code
https://claude.ai/code/session_01NyeggYtojNXCTHeD3JHxb6