ci: test against Python 3.13 and 3.14 - #310
Conversation
The classifiers stopped at 3.12 and so did the matrix, while both internal consumers are already past it: the monorepo `engine` and `shadow-office` each declare `requires-python = "~=3.14.0"` and pin `sql-compare==0.2.0`. The library is consumed on 3.14 and tested on neither 3.13 nor 3.14. `requires-python = ">=3.10"` is an installability floor, not a support claim, and it stays unbounded on purpose: a ceiling there breaks `pip install` on every Python released after it. The classifiers are the support claim, so they are what this corrects. They only reach users on the next release; PyPI's current 0.2.0 still advertises `>=3.9` and stops at 3.12. Nothing else has to move. `python = "^3.10"` already spans both, so `poetry.lock`'s `python-versions` and `content-hash` are unchanged (`poetry check --lock` exits 0; classifiers are not hashed), and every locked dependency ships cp313 and cp314 wheels, so no leg builds from source. Free-threaded 3.14t is left out because nothing here exercises it, not because it would need different artifacts: `sql_compare` is one pure-Python module, so `poetry build` emits a single `py3-none-any` wheel that 3.14t installs unchanged. Adding that leg is its own decision. Verified on 3.13.10 and 3.14.6 in clean environments built from `poetry.lock`: ruff, ruff format, deptry and mypy --strict clean, 64 tests passing on both. The 3.14 leg prints two `SyntaxWarning: 'return' in a 'finally' block` from pluggy 1.5.0 whenever the bytecode cache is cold, which on CI is always. They are emitted while pluggy itself is compiled, before pytest installs `filterwarnings = ["error"]`, so they are noise on an exit-0 run. Bumping pluggy to 1.6.0 would silence them and belongs in its own change against the lock. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MKmEnjRuAM4NcTYxRXG3BA Change-Id: I08ce7a6db8d33895e7135f648c2afa9723ed0852
|
This pull request is part of a Mergify stack:
|
Merge Protections🟢 All 6 merge protections satisfied — ready to merge. Show 6 satisfied protections🟢 🤖 Continuous Integration
🟢 👀 Review Requirements
🟢 Enforce conventional commitMake sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
🟢 🔎 Reviews
🟢 📕 PR description
🟢 🚦 Auto-queueWhen all merge protections are satisfied, this pull request will be queued automatically. |
There was a problem hiding this comment.
🟢 Approval recommended
The changes are limited to metadata and CI matrix expansion, with no functional code impact and no issues found in the updated configuration.
Pull request overview
This pull request updates the project’s declared and continuously-tested Python support to include Python 3.13 and 3.14, aligning packaging metadata (PyPI classifiers) with the CI test matrix.
Changes:
- Add Trove classifiers for Python 3.13 and Python 3.14 in
pyproject.toml. - Expand the GitHub Actions CI matrix to run tests on Python 3.13 and 3.14.
File summaries
| File | Description |
|---|---|
| pyproject.toml | Extends PyPI classifiers to advertise support for Python 3.13 and 3.14. |
| .github/workflows/ci.yaml | Expands CI test matrix to execute the suite on Python 3.13 and 3.14. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@Mergifyio queue |
Merge Queue Status
This pull request spent 22 seconds in the queue, including 6 seconds running CI. Required conditions to merge
|
The two matrix legs added in the previous commit are advisory on their own. `.mergify.yml`'s `&CheckRuns` anchor is this repository's only merge gate: `branches/main/protection` returns no `required_status_checks`, and none of the eleven active rulesets carries one. So a red 3.13 or 3.14 leg would land silently. The ordering mirrors #299 -> #300 but not the reasoning, which is worth stating rather than assuming symmetric. Removing a check needed its own pull request first because Mergify reads its configuration from the default branch: a pull request deleting the job would still have been gated on a check that no longer reported, and could never merge. Adding one has no such deadlock. Both pull requests here are evaluated against main's configuration, which does not name the new checks, so a single atomic commit would have merged just as well. What the split actually buys is revertability. If a new leg turns out to be red on main, reverting this commit alone unblocks the repository while keeping the coverage the previous commit added; an atomic change would have to give up both. Two consequences worth knowing, neither of which ordering can avoid. Because main's configuration does not require the new checks until this lands, nothing forces either pull request of this stack to be green on 3.13 or 3.14. Both run the full five-leg matrix on their own head, so the legs are observable, but they have to be looked at before this one is merged rather than assumed. Every pull request already open when this lands keeps the check-run set from its last CI run, and no `pull_request` event fires when the base moves. `check-success=Test with Python 3.13` can therefore never go true on it, and `auto_merge_conditions: true` folds the success conditions into the queue conditions, so it cannot enter the queue to be rebased out either. Each one needs a push, a rebase or a close/reopen to pick up the new legs. Longer term, this list is a hand-maintained mirror of the job names and will want the same ceremony at 3.15. The monorepo and mergify-cli both replaced it with one aggregate job (`all-greens` / `ci-gate`) behind a single `check-success`, which is worth adopting here on its own. Note that `check-success~=^Test with Python ` is not a shortcut for it: check-success is a list attribute and `~=` matches any element, so one green leg would satisfy it while another fails. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MKmEnjRuAM4NcTYxRXG3BA Depends-On: #310
The classifiers stopped at 3.12 and so did the matrix, while both
internal consumers are already past it: the monorepo
engineandshadow-officeeach declarerequires-python = "~=3.14.0"and pinsql-compare==0.2.0. The library is consumed on 3.14 and tested onneither 3.13 nor 3.14.
requires-python = ">=3.10"is an installability floor, not a supportclaim, and it stays unbounded on purpose: a ceiling there breaks
pip installon every Python released after it. The classifiers are thesupport claim, so they are what this corrects. They only reach users on
the next release; PyPI's current 0.2.0 still advertises
>=3.9andstops at 3.12.
Nothing else has to move.
python = "^3.10"already spans both, sopoetry.lock'spython-versionsandcontent-hashare unchanged(
poetry check --lockexits 0; classifiers are not hashed), and everylocked dependency ships cp313 and cp314 wheels, so no leg builds from
source.
Free-threaded 3.14t is left out because nothing here exercises it, not
because it would need different artifacts:
sql_compareis onepure-Python module, so
poetry buildemits a singlepy3-none-anywheel that 3.14t installs unchanged. Adding that leg is its own
decision.
Verified on 3.13.10 and 3.14.6 in clean environments built from
poetry.lock: ruff, ruff format, deptry and mypy --strict clean, 64tests passing on both. The 3.14 leg prints two
SyntaxWarning: 'return' in a 'finally' blockfrom pluggy 1.5.0 whenever the bytecode cache iscold, which on CI is always. They are emitted while pluggy itself is
compiled, before pytest installs
filterwarnings = ["error"], so theyare noise on an exit-0 run. Bumping pluggy to 1.6.0 would silence them
and belongs in its own change against the lock.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01MKmEnjRuAM4NcTYxRXG3BA