ci(pins): make the python-classifier check advisory, not fatal - #9466
Open
lstein wants to merge 2 commits into
Open
ci(pins): make the python-classifier check advisory, not fatal#9466lstein wants to merge 2 commits into
lstein wants to merge 2 commits into
Conversation
The pin check gated on `project.classifiers`, which is optional in PEP 621
and purely informational on PyPI. That made a legal pin fail: with
`requires-python = ">=3.11, <3.13"`, setting pins.json's python to 3.11
exited 1 solely because no `Programming Language :: Python :: 3.11`
classifier existed, even though the package metadata permits 3.11.
`requires-python` is what actually gates installation, so it goes back to
being the only authority the script fails on. A pin the classifiers don't
mention is now a warning naming the classifier to add, and their absence,
malformation or deferral to `project.dynamic` is not a finding at all.
This gives up one thing, and the docstring now says so: a version that
satisfies an open-ended `requires-python` but that no interpreter has
(">=3.11" with a "3.99" pin) is no longer caught. Catching it meant
gating on non-normative metadata, and a checker that rejects a legal pin
is worse than one that misses an implausible typo.
Found by attacking the previous commit: - '... :: Python :: 3.012' counted as declaring 3.12, because the comparison normalized both sides through _parse_version. That is not a trove classifier, so PyPI shows no 3.12 support - silencing the advisory in exactly the case it exists to name. The classifier pattern now rejects leading zeros like the pin pattern does, which also makes the normalization redundant: with one spelling per version on either side, a string comparison is exact. - The warning loop ran before the errors were printed, so a raise while computing advice would have discarded the error list - the failure mode check_python's "never raises" contract exists to prevent. It now runs after, and a test asserts the advisory still appears on a failing run. - Three comments still described classifiers as authoritative or named check_python as the code that reads them.
lstein
force-pushed
the
ci/pins-classifier-advisory
branch
from
August 5, 2026 16:53
e40919b to
fb0b70e
Compare
Collaborator
Author
|
#9351 merged while this was in review, so I rebased — the diff is now just this PR's two commits. |
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.
Summary
Follow-up to the review comment on #9351: the pin check treated
project.classifiersas an authoritative allowlist, which is wrong — classifiers are optional in PEP 621 and purely informational on PyPI, so they cannot decide whether a pin is installable.@JPPhoto's repro, on #9351 as it stands:
requires-python = ">=3.11, <3.13"genuinely permits that pin. The metadata allows the install; only a piece of documentation disagreed.After this PR:
What changed
requires-pythonis once again the only authority the script fails on for thepythonpin.project.dynamicclassifiers are no longer a finding at all —classifiersis optional, so its absence says nothing about the pin.What this gives up, deliberately
A version that satisfies an open-ended
requires-pythonbut that no interpreter has —>=3.11with a3.99pin — is no longer caught. The module docstring says so explicitly, and there's a test named after it.Catching that case was the reason the classifier allowlist went in, but the price was rejecting legal pins, and a checker that blocks a correct change is worse than one that misses an implausible typo. The pin still has to be major.minor with no patch component, and it still has to satisfy
requires-python— with the repo's current>=3.11, <3.13, there is no reachable gap.Testing
116 tests in
tests/test_check_pins.py, all green;ruff format/checkclean; script verified under a barepython3and parsed against the 3.11 grammar (CI runs it with whateverpython3the runner has).New tests: a 3.11 pin passes with only an advisory; the advisory names the classifier to add; a pin the classifiers do mention says nothing; missing / malformed / dynamic classifiers are not findings; a
3.012classifier does not count as declaring 3.12; and the advisory survives a failing run.Mutation-tested the new logic — every mutant applied to the advisory path and the warning loop is caught, including the two that survived my first pass at this change.