Skip to content

chore: raise the Python floor to 3.14, and record why it moved back up - #546

Merged
eaitbrahim merged 1 commit into
mainfrom
chore-python-314-floor
Aug 24, 2026
Merged

chore: raise the Python floor to 3.14, and record why it moved back up#546
eaitbrahim merged 1 commit into
mainfrom
chore-python-314-floor

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

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

What it unblocks — both verified, not assumed

ruff can target py314. It could not before, and ruff.toml recorded exactly why: 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, which the metadata then invited. Raising the floor removes every interpreter that cannot 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 — follow_imports = "skip" plus follow_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 matrix rather than a scalar so a second supported version is one list entry, and so the required status context stays test either 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 from requires-python instead 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 readme matched "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 the 3.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_exists asserted assert_never was 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.md and 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 · mypy python_version and 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.lock

Gates

  • ruff check keel tests packages — All checks passed
  • mypy — no issues in 359 source files
  • pytest -q4665 passed, 3 skipped
  • uv lock --check — current

Note

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.md now says so explicitly and invites the issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NyeggYtojNXCTHeD3JHxb6

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
@eaitbrahim
eaitbrahim merged commit 2d3934f into main Aug 24, 2026
4 of 6 checks passed
@eaitbrahim
eaitbrahim deleted the chore-python-314-floor branch August 24, 2026 10:05
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