Repository navigation
馃悰 fix(spec): let ~=X.Y match later minor versions - #159
Merged
gaborbernat merged 3 commits intoOct 27, 2026
Merged
Conversation
SimpleVersion pads every release to three parts, and the compatible
release check built its upper bound by dropping the last part of that
padded tuple. That is only right when the specifier itself has three
parts. For ~=3.10 it gave >=3.10,<3.11 instead of the >=3.10,==3.* that
PEP 440 defines, so get_interpreter("~=3.10") returned None on a machine
whose Pythons are all 3.11 or newer, and the uv store filter and
PythonSpec.satisfies with a full X.Y.Z spec skipped the same
interpreters. virtualenv -p "~=3.10" fails the same way.
The check now compares every release part the specifier wrote except
the last, the same prefix match the wildcard check uses. Comparing the
prefix also stops ~=3.12.0 from accepting 3.13.0a1, which sorted below
the old 3.13 bound. A bare ~=3 is not valid PEP 440, but it was
accepted before, so it keeps working and now means ==3.* in both
SimpleSpecifier.contains and PythonInfo.satisfies, which used to
disagree on it.
Anyone who used ~=3.12 to mean 3.12 only now gets later 3.x releases
too; PEP 440 spells that ~=3.12.0 or ==3.12.*.
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.

get_interpreter("~=3.10")found nothing on a machine with 3.13 and 3.14 installed, while>=3.10,<4found 3.14. 馃悰 PEP 440 defines~=3.10as>=3.10, ==3.*, and the docs list~=as supported, so a two-part compatible release should accept every later 3.x.virtualenv -p "~=3.10", interpreter discovery, the uv store filter andPythonSpec.satisfiesall shared the bug, because they all use the same specifier check.The version parser pads every release to three parts, and the compatible-release check derived its upper bound from that padded form, so
~=3.10behaved like~=3.10.0. The check now compares the release prefix the spec wrote, all parts but the last, the way==X.*wildcards already match. Comparing the prefix also stops~=3.12.0from accepting3.13.0a1, which used to slip under the computed bound.~=3.12to mean "3.12 only" now get later 3.x interpreters too; PEP 440 spells that~=3.12.0or==3.12.*. A bare~=3, which PEP 440 rejects, stays accepted and means==3.*, matching what interpreter discovery already did with it.