Add PEP 440 version comparison for pypi scheme#26
Open
andrew wants to merge 4 commits into
Open
Conversation
parseDotSeparated silently dropped non-numeric segment suffixes, so 5.2b1 parsed as 5.0.0 and every PEP 440 prerelease form collapsed to the release. There was also no pypi case in CompareWithScheme, and Range.Contains used generic comparison regardless of scheme. Add a PEP 440 comparator covering epoch, release padding, pre/post/dev ordering, spelling and separator normalization, and local version segments. Store the scheme on Range so Contains can dispatch to it. Split trailing letter suffixes in parseDotSeparated instead of discarding them. Fixes #24
Range.IsEmpty used generic comparison, so a pypi range like [1.0.dev1, 1.0a1) reported empty and serialized as vers:pypi/. Use the scheme comparator there too. Scheme was not set on ranges from the wildcard path, ParseNative sub-parsers that bypass parseConstraints (including pypi ~=), or the results of Union/Intersect/Exclude. Stamp it in each of those places so Contains and IsEmpty on the result use the right rules. Replace the 1<<30 positive-infinity sentinel in the PEP 440 comparator with explicit hasPre/hasPost/hasDev flags. Numeric components are unbounded in PEP 440 and a large enough dev number sorted the wrong side of an absent one.
…merics as strings Range.Intersect and Range.Union built results using generic comparison, so intersecting >=1.0.dev1 with <1.0a1 under pypi discarded the resulting interval as empty. Add cmp-taking variants of Interval.Intersect/Union/Overlaps/Adjacent and mergeIntervals, and have Range.Intersect/Union use the scheme comparator. Store PEP 440 numeric components (epoch, release segments, pre/post/ dev numbers, numeric local segments) as digit strings and compare them by length then lexically. Values that overflow int no longer collapse to zero, and large local segments stay numeric.
…equality for Union exclusions parsePypiRange delegated ~= to the gem pessimistic algorithm, which counts raw dots (so .dev/.post added phantom segments) and drops the epoch. ~=1.4.dev1 produced <1.5 instead of <2, and ~=1!1.4.5 lost the epoch on the upper bound. Add a pypi-specific handler that reads the release segments and epoch via parsePEP440 and increments the second-last release segment. Stop trimming trailing zeros from the parsed release so ~=2.0.dev1 sees two segments; cmpNumStrSlice already treats missing segments as zero so comparison is unchanged. Range.Union intersected exclusions by string equality, so unioning ranges that exclude 1.5 and 1.5.0 respectively dropped the exclusion even though those are the same version under PEP 440. Compare with the scheme comparator instead.
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.
Fixes #24.
parseDotSeparatedsilently dropped non-numeric segment suffixes, so5.2b1parsed as5.0.0and every PEP 440 prerelease form (a,b,rc,.dev,.post) collapsed to the release. There was also nopypicase inCompareWithScheme, andRange.Containsused generic comparison regardless of scheme, so even a correct comparator would not have been reached.This adds a PEP 440 comparator (
pypi.go) covering epoch, release-segment padding,dev < a < b < rc < release < postordering, the spelling and separator variants the spec allows, and local version segments.Rangenow records the scheme it was parsed under andContainsdispatches to the matching comparator;intersectConsecutiveIntervalsuses the same comparator when deciding whether a paired>=X | <Yinterval is empty, so[5.1, 5.2b1)is no longer thrown away.parseDotSeparatedsplits a trailing letter suffix off a segment instead of discarding it, which fixes the genericNormalizepath.New tests in
pypi_test.gocover the three reported cases plus the ordering chain from the PEP 440 spec, normalization equivalences, epochs, local versions, and range containment through bothvers:pypi/and native syntax.The scheme-on-
Rangechange also means maven and nuget containment now use their own comparators, which fixes a couple of latent cases noted in #25, though the rest of #25 (deb, rpm, gem) is out of scope here.