v0.2.0 — conformance release
Conformance release. requirement/, version/, and the PEP 508 grammar are now tested against tables ported from pypa/packaging's tests/test_requirements.py (upstream SHA 4eb0753), plus property-based tests adapted from its Hypothesis suite. The divergences those tests revealed are fixed.
This release changes behavior. It is a minor rather than a patch bump because a consumer pinning ^0.1 would otherwise pick up the narrowing and the ordering change silently. See CHANGELOG.md for the full list.
Breaking
Requirement.String()renders the marker separator as"; "when the requirement has no URL — it previously always rendered" ; ". The" ; "form is kept when a URL is present, since a bare;after a URL is ambiguous. Consumers that compare, hash, cache, or persist rendered requirement strings will see different bytes for the same input.- Local version labels normalize
-and_to., as PEP 440 requires. This changesString()output, equality, and ordering. Previously a label was compared as a single alphabetic segment, so1.0+ubuntu-2sorted above1.0+ubuntu-10; it now sorts below, matching upstream. - Arbitrary equality (
===) accepts exactly one token.=== lolwatis valid;===any string hereis now rejected. - A
.*prefix match is rejected on a post-release (e.g.==1.2.3.post4.*). - A trailing line break (
\n,\r,\r\n) is rejected. A trailing space or tab is still accepted. - Malformed quoted strings in environment markers are rejected: a trailing unpaired backslash and a truncated
\x. Valid Python escapes still parse.
Added
name()— an empty parenthesized specifier group — is valid, meaning "no version constraint".- A vertical tab is accepted as surrounding whitespace, matching upstream (Go's
\somits\vwhere Python's includes it). - Conformance tables and property tests ported from
pypa/packaging. The property-test dependency (pgregory.net/rapid, MPL-2.0) is test-only and does not enter this module's non-test import graph.
Fixed
- The PEP 440 operator alternation is built in a deterministic, longest-first order. It was previously assembled by ranging a Go map, so the compiled pattern varied per process — and because Go's
regexpis leftmost-first, an operator that is a prefix of another could win.
Note on comparing against pip install packaging
The trailing-line-break rule matches upstream's current source, not the released packaging 26.2. Upstream changed its end-of-input rule from $ to \Z after 26.2, and Python's $ matches before a trailing newline — so 26.2 still accepts "name>=1\n". A difference seen there is upstream's version skew, not a divergence here.