chore(python): relax the floor to >=3.11, measured, with a CI leg to keep it true - #301
Merged
Conversation
…keep it true requires-python was >=3.14.4 — the interpreter the author develops on, not one the code needs, and new enough to silently bar contributors (#283). Measured by running the full suite down the versions: 3.13, 3.12, 3.11 pass identically (2,788/1); 3.10 fails collection on typing.assert_never (3.11+), the one concrete binding constraint. Floor set to >=3.11, dev pin stays 3.14.4, ci.yml's test job becomes a 3.11+3.14 matrix (same status context, so both legs gate the merge), mypy targets the floor, and tests/test_python_floor.py pins the decision: one floor everywhere, the binding feature still imported, the CI leg present, the docs stating it.
This was referenced Aug 16, 2026
Merged
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.
Closes #283
requires-python = ">=3.14.4"said "the interpreter I develop on", not "the interpreter thecode needs" — and 3.14 is new enough that contributors who lack it fail to build and leave
without opening an issue.
The measurement (the decision's evidence, per the issue):
ImportError: cannot import name 'assert_never' from 'typing'Decision: nothing requires 3.14. The floor is set to
>=3.11— the lowest version thesuite passes on — with
typing.assert_never(3.11+) as the one concrete binding constraint.Development stays pinned to 3.14.4 via
.python-version.What changes
requires-python = ">=3.11"in all six distributions;uv.lockre-resolved.ci.yml'stestjob becomes a 3.11 + 3.14 matrix, so the floor stays a measured claim.Both legs stay inside the
testjob on purpose: the matrix fans out the required statuscontext rather than renaming it, so every leg gates the merge — the same lesson the job's
own comments record for mypy (ci: gate on mypy, so #266's ungating cannot quietly come undone #268).
python_version = "3.11"— check against the floor, not the dev pin.floor gets a clear message rather than a confusing resolver error" — low floor, stated
plainly).
tests/test_python_floor.py(red first) pins the decision's four halves: one floor in everydistribution, the binding feature still imported (if
assert_neverever disappears, thefloor can drop — re-measure), the CI leg present, and the docs stating it.
Gates:
pytest2,798 passed / 1 skipped on both 3.14 and 3.11;ruffandmypyclean.