Add pypa/packaging conformance tests for PEP 440 specifier parsing - #1776
Merged
Stella Huang (StellaHuang95) merged 1 commit intoSep 11, 2026
Conversation
Ports 118 cases from pypa/packaging's tests/test_specifiers.py to validate PythonVersionSpecifier against the reference PEP 440 implementation: - 31 invalid specifiers that must be rejected (test_specifiers_invalid) - 85 version/specifier match cases (test_specifiers) - 2 cases that intentionally differ from packaging, kept in their own suite Expected values were generated by calling packaging with its DEFAULT prerelease semantics, not the prereleases=True that the upstream harness forces. Cases using epochs, local version labels, post/dev releases, or more than three release segments are omitted: a Python interpreter version never has them, and PythonVersion deliberately does not model them. The two divergences are strict-inequality bounds naming a prerelease (>3.0.0a7 and <3.0.0a8). packaging enables prereleases only for ==, >=, <=, ~= and ===, so it filters them out; we enable prereleases for any clause naming one, which pythonVersionSpecifier.unit.test.ts already asserts for <3.14.0rc2. Test data is used under BSD-2-Clause; attribution is in the file header. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rich Chiodo (rchiodo)
approved these changes
Sep 10, 2026
Eduardo Villalpando Mello (edvilme)
approved these changes
Sep 10, 2026
Stella Huang (StellaHuang95)
merged commit Sep 11, 2026
c8009aa
into
microsoft:main
45 of 46 checks passed
Stella Huang (StellaHuang95)
deleted the
stellahuang/pep440-packaging-conformance-tests
branch
September 11, 2026 00:14
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.
What
Adds a data-driven conformance suite that validates
PythonVersionSpecifier/PythonVersionagainst pypa/packaging, the reference PEP 440 implementation.requires-pythonin a PEP 723 inline-script block is a PEP 440 version specifier, andwe evaluate it ourselves (in
matchesPythonVersion) to choose a base interpreter and todecide which Python version to ask uv to install. This pins that behaviour to the
reference implementation so edge cases can't drift.
118 cases ported from
tests/test_specifiers.py:rejects specifiers packaging rejectstryParsereturnsundefinedmatches packaging semanticsmatches()equals packaging's resultdiverges from packaging by designHow expected values were produced
They were generated by calling packaging 24.1 directly, not hand-transcribed.
Two things to know when re-generating:
Specifier(spec, prereleases=True),which is not packaging's default. Expected values here use the default, which is the
correct model for
requires-python. Against the default we match packaging on all 85 cases.2!1.0), local labels (2.0+deadbeef), post/dev releases,or more than three release segments are omitted. A Python interpreter version never has
them, and
PythonVersiondeliberately does not model them (see its class doc).The two intentional divergences
packaging's
Specifier.prereleasesauto-enables prereleases only for==,>=,<=,~=and
===—<and>are excluded. So under packaging's default:>3.0.0a7matches only final releases (3.0.0,3.0.1); it rejects3.0.0a8,3.0.0b1,3.0.0rc1<3.0.0a8rejects every 3.x prereleaseOur rule is uniform: any clause naming a prerelease enables prereleases. That is what the
class docs describe and what
pythonVersionSpecifier.unit.test.tsalready asserts for<3.14.0rc2. These two cases are isolated in their own suite with the reason recorded, sothey're an explicit decision rather than an accidental mismatch.
Testing
npm run lintclean on the new fileLicensing
pypa/packaging is dual-licensed Apache-2.0 / BSD-2-Clause. The ported test data is used
under BSD-2-Clause, with source, copyright and licence recorded in the file header.
No production code is affected — this PR adds a test file only.