Skip to content

Releases: pypa/packaging

26.3

Choose a tag to compare

@henryiii henryiii released this 04 Aug 21:42
Immutable release. Only release title and notes can be modified.
26.3

What's Changed

Features

  • Add a public VersionRange API and SpecifierSet.to_range(), representing the versions a specifier set accepts as an interval set that supports intersection, union, difference, complement, set relations, membership tests, and filtering. VersionRange.to_specifier_set() converts a range back to a SpecifierSet where a PEP 440 form exists. (#1267, #1270, #1298)
  • PEP 808: accept Metadata-Version: 2.6. (#1194)
  • Add a limit argument to parse_tag() for compressed tag sets. (#1220)
  • Add a prefer_sdist_predicate argument to Pylock.select() to prefer source distributions over wheels for selected packages. (#1334)
  • Add pure_python_tags() to generate the pure-Python tags for a Python version without touching the running platform. (#1346)
  • Add SpecifierSet.is_subset(), SpecifierSet.is_superset(), and SpecifierSet.is_disjoint(), which compare the versions two specifier sets accept. (#1313)

Behavior adaptations

  • Drop support for Python 3.8; packaging now requires Python 3.9 or later. (#1157)
  • Prefer native linux_* platform tags over manylinux and musllinux tags on Linux. (#160)

Fixes for versions and specifiers

  • Raise InvalidVersion instead of TypeError when Version is given a non-string. (#1319)
  • Raise InvalidVersion for non-string pre-release letters passed to Version.from_parts. (#1241)
  • Fix an AttributeError when hashing internally trimmed versions. (#1242)
  • Fix SpecifierSet.is_unsatisfiable for post-release boundary intersections. (#1257)

Fixes for requirements and markers

  • Make Requirement.__hash__ consistent with __eq__ for trailing-zero-equivalent specifiers (e.g. foo==1.0.0 and foo==1.0.0.0), so equal requirements hash equal and deduplicate in sets and dicts. (#1232)
  • Normalize requested extra names before comparing or hashing requirements. (#644)
  • Preserve a Requirement's specifier prereleases override across a pickle round trip. (#1204)
  • Raise InvalidRequirement instead of InvalidSpecifier when a requirement contains an invalid specifier. (#1332)
  • Clarify the error for post-release prefix wildcards like ==1.0.post1.*. (#1299)
  • Preserve quoting semantics when serializing marker values, so round-tripped markers parse back to the same marker. (#1213)
  • Keep the parentheses of a nested group when serializing markers. (#1316)
  • Normalize extra and dependency_groups values in nested markers at parse time. (#1246, #1310)
  • Raise UndefinedComparison when a set-valued variable like extras is used outside the membership form. (#1265)
  • Raise UndefinedEnvironmentName (a KeyError subclass) for missing environment keys during marker evaluation. (#1276)
  • Wrap malformed string literal errors in InvalidMarker / InvalidRequirement instead of leaking a low-level error. (#1249)
  • Reject requirements and markers with a trailing line break. (#1345)

Fixes for metadata and licenses

  • Collect all from_email validation errors into one ExceptionGroup instead of raising the first. (#1268)
  • Accept the UTF-8 charset case-insensitively in email payloads. (#1330)
  • Reject malformed Description-Content-Type values. (#1329)
  • Don't rewrite user values that contain {field} placeholders in error messages. (#1327)
  • Route multipart email payloads to unparsed instead of asserting. (#1247)
  • Make InvalidMetadata and CyclicDependencyGroup picklable. (#1328)
  • Fold every line boundary str.splitlines recognizes when writing a header with RFC822Message. (#1356)
  • Raise InvalidLicenseExpression for misplaced WITH clauses and empty LicenseRef- names. (#1266)
  • Raise InvalidLicenseExpression instead of KeyError for a LicenseRef- with a + suffix. (#1219)

Fixes for tags and filenames

  • Raise InvalidTag from parse_tag() for tags with the wrong number of components. (#1238)
  • Reject empty tag components in parse_wheel_filename() and parse_tag(). (#1234)
  • Reject an empty project name in the wheel and sdist filename parsers. (#1305)
  • Reject wheel filenames with a trailing newline. (#1341)
  • Reject wheel tags whose interpreter component is not an identifier. (#577)
  • is_normalized_name now rejects names with collapsed double hyphens like a--b. (#1230)
  • Fix duplicate explicit abi3t tags. (#1245)
  • Forward the warn argument to generic_tags() in sys_tags(). (#1264)
  • Raise SystemError for an empty or malformed CPython EXT_SUFFIX. (#1271, #1301)
  • Fix a typo in the macOS fat3 architecture name (was fat32). (#1199)

Fixes for pylock, direct URLs, and dependency groups

  • Percent-decode pylock artifact file names derived from a url so that local versions (e.g. a wheel with 2.12.1+cu130 encoded as 2.12.1%2Bcu130) yield a valid file name. (#1314)
  • Use an explicitly empty tags sequence in Pylock.select() instead of falling back to sys_tags(). (#1349)
  • Fix Pylock.select() on Python builds that report a non-PEP 440 python_full_version (e.g. 3.15.0+). (#1179)
  • Reject TOML booleans where integers are expected in pylock files. (#1244)
  • Add PylockSelectError to packaging.pylock.__all__. (#1202)
  • Fix DirectUrl credential stripping for passwords containing @. (#1218)
  • Parse the URL scheme case-insensitively when checking for file URLs in direct_url. (#1240)
  • Require absolute file URLs for local directories in direct_url. (#1297)
  • Collect InvalidRequirement errors while resolving dependency groups instead of leaking them. (#1302)
  • Don't cache malformed dependency group parses. (#1248)

Performance

  • Implement Specifier and SpecifierSet filtering with the new range engine. (#1120, #1259)
  • Cache the default marker environment. (#1250)
  • Cache the _manylinux module lookup process-wide. (#1254)
  • Add __slots__ to Requirement and the token classes. (#1320, #1258)
  • Keep range caches across canonicalization, precompile the wheel project-name pattern, simplify parse_tag(), and skip platform.mac_ver() when the version and arch are given. (#1253, #1256, #1236, #1255)

Documentation

  • Describe the validation scope of packaging.pylock. (#1339)
  • Explain which packaging.metadata fields are validated. (#1342)
  • Document RFC822Policy in the low-level packaging.metadata interface. (#1222)
  • Enable nitpicky mode and render missing classes and fields in the API reference. (#1196, #1225, [#1277](htt...
Read more

26.2

Choose a tag to compare

@henryiii henryiii released this 24 Apr 20:20
Immutable release. Only release title and notes can be modified.
26.2

What's Changed

Fixes:

  • Fix incorrect sysconfig var name for pyemscripten by @ryanking13 in #1160
  • Make Version, Specifier, SpecifierSet, Tag, Marker, and Requirement pickle-safe
    and backward-compatible with pickles created in 25.0-26.1 (including references to the removed
    packaging._structures module) by @eachimei and @henryiii in #1163, #1168, #1170, and #1171
  • fix: re-export ExceptionGroup for now by @henryiii in #1164

Documentation:

Internal:

New Contributors

Full Changelog: 26.1...26.2

26.1

Choose a tag to compare

@henryiii henryiii released this 14 Apr 21:16
Immutable release. Only release title and notes can be modified.
26.1

Features:

  • PEP 783: add handling for Emscripten wheel tags by @hoodmane in #804 (old name used in implementation, will be fixed in next release)
  • PEP 803: add handling for the abi3.abi3t free-threading tag by @ngoldbaum in #1099
  • PEP 723: add packaging.dependency_groups module, based on the dependency-groups package by @sirosen in #1065
  • Add the packaging.direct_url module by @sbidoul in #944
  • Add the packaging.errors module by @henryiii in #1071
  • Add SpecifierSet.is_unsatisfiable using ranges (new internals that will be expanded in future versions) by @notatallshaw in #1119
  • Add create_compatible_tags_selector to select compatible tags by @sbidoul in #1110
  • Add a key argument to SpecifierSet.filter() by @frostming in #1068
  • Support & and | for Marker's by @henryiii in #1146
  • Normalize Version.__replace__ and add Version.from_parts by @henryiii in #1078
  • Add an option to validate compressed tag set sort order in parse_wheel_filename by @r266-tech in #1150

Behavior adaptations:

Pylock (PEP 751) updates:

  • Add pylock select function by @sbidoul in #1092
  • Document pylock select() method and PylockSelectError by @r266-tech in #1153
  • Add filename property to PackageSdist and PackageWheel, more validation by @sbidoul in #1095
  • Give preference to path over url by @sbidoul in #1128
  • Validate name/version consistency in file names by @sbidoul in #1114

Fixes:

  • Fix > comparison for versions with dev+local segments by @veeceey in #1097
  • Fix incorrect self-comparison for InfinityType and NegativeInfinityType by @bysiber in #1093
  • Canonicalize when deduplicating specifiers in SpecifierSet by @notatallshaw in #1109
  • Fix charset error message formatting by @notatallshaw in #1121
  • Handle the key parameter in SpecifierSet.filter when specifiers are empty and prerelease is False by @notatallshaw in #1096
  • Standardize inner components of repr output by @henryiii in #1090
  • Specifier's === uses original string, not normalized, when available by @notatallshaw in #1124
  • Propagate int-max-str-digits ValueError by @notatallshaw in #1155

Performance:

Internal:

Documentation:

Benchmarks

Performance improvements since 26.0, from the new integrated benchmark suite:

uv run asv run 26.0..HEAD
Screenshot 2026-04-13 at 11 32 14 PM Screenshot 2026-04-13 at 11 32 43 PM

New Contributors

Full Changelog: 26.0...26.1

26.0

Choose a tag to compare

@henryiii henryiii released this 21 Jan 21:03
Immutable release. Only release title and notes can be modified.
26.0

Read about the performance improvements here: https://iscinumpy.dev/post/packaging-faster.

What's Changed

Features:

Behavior adaptations:

  • PEP 440 handling of prereleases for Specifier.contains, SpecifierSet.contains, and SpecifierSet.filter by @notatallshaw in #897
  • Handle PEP 440 edge case in SpecifierSet.filter by @notatallshaw in #942
  • Adjust arbitrary equality intersection preservation in SpecifierSet by @notatallshaw in #951
  • Return False instead of raising for .contains with invalid version by @Liam-DeVoe in #932
  • Support arbitrary equality on arbitrary strings for Specifier and SpecifierSet's filter and contains method. by @notatallshaw in #954
  • Only try to parse as Version on certain marker keys, return False on unequal ordered comparsions by @JP-Ellis in #939

Fixes:

  • Update _hash when unpickling Tag() by @dholth in #860
  • Correct comment and simplify implicit prerelease handling in Specifier.prereleases by @notatallshaw in #896
  • Use explicit _GLibCVersion NamedTuple in _manylinux by @cthoyt in #868
  • Detect invalid license expressions containing () by @bwoodsend in #879
  • Correct regex for metadata 'name' format by @di in #925
  • Improve the message around expecting a semicolon by @pradyunsg in #833
  • Support nested parens in license expressions by @Liam-DeVoe in #931
  • Add space before at symbol in Requirements string by @henryiii in #953
  • A root logger use found by ruff LOG, use packaging logger instead by @henryiii in #965
  • Better support for subclassing Marker and Requirement by @henryiii in #1022
  • Normalize all extras, not just if it comes first by @henryiii in #1024
  • Don't produce a broken repr if Marker fails to construct by @henryiii in #1033

Performance:

Type annotations:

Internal:

Read more

26.0rc3

26.0rc3 Pre-release
Pre-release

Choose a tag to compare

@henryiii henryiii released this 15 Jan 23:26
Immutable release. Only release title and notes can be modified.
26.0rc3

What's Changed

Fixes:

  • Support CPython 3.11.0-3.11.4 and older PyPy3.11 by @henryiii in #1055

Performance:

CI:

Documentation:

Full Changelog: 26.0rc2...26.0rc3

26.0rc2

26.0rc2 Pre-release
Pre-release

Choose a tag to compare

@henryiii henryiii released this 12 Jan 21:18
Immutable release. Only release title and notes can be modified.
26.0rc2

What's Changed

Fixes:

  • Fix regression in (private) Version._key for packaging_legacy by @henryiii in #1048

Performance:

  • Tiny import time improvement and simplification by @henryiii in #1047

Internal:

Full Changelog: 26.0rc1...26.0rc2

26.0rc1

26.0rc1 Pre-release
Pre-release

Choose a tag to compare

@henryiii henryiii released this 09 Jan 01:29
Immutable release. Only release title and notes can be modified.
26.0rc1

What's Changed

Features:

Behavior adaptations:

  • PEP 440 handling of prereleases for Specifier.contains, SpecifierSet.contains, and SpecifierSet.filter by @notatallshaw in #897
  • Handle PEP 440 edge case in SpecifierSet.filter by @notatallshaw in #942
  • Adjust arbitrary equality intersection preservation in SpecifierSet by @notatallshaw in #951
  • Return False instead of raising for .contains with invalid version by @Liam-DeVoe in #932
  • Support arbitrary equality on arbitrary strings for Specifier and SpecifierSet's filter and contains method. by @notatallshaw in #954
  • Only try to parse as Version on certain marker keys, return False on unequal ordered comparsions by @JP-Ellis in #939

Fixes:

  • Update _hash when unpickling Tag() by @dholth in #860
  • Correct comment and simplify implicit prerelease handling in Specifier.prereleases by @notatallshaw in #896
  • Use explicit _GLibCVersion NamedTuple in _manylinux by @cthoyt in #868
  • Detect invalid license expressions containing () by @bwoodsend in #879
  • Correct regex for metadata 'name' format by @di in #925
  • Improve the message around expecting a semicolon by @pradyunsg in #833
  • Support nested parens in license expressions by @Liam-DeVoe in #931
  • Add space before at symbol in Requirements string by @henryiii in #953
  • A root logger use found by ruff LOG, use packaging logger instead by @henryiii in #965
  • Better support for subclassing Marker and Requirement by @henryiii in #1022
  • Normalize all extras, not just if it comes first by @henryiii in #1024
  • Don't produce a broken repr if Marker fails to construct by @henryiii in #1033

Performance:

Type annotations:

Internal:

Read more

25.0

Choose a tag to compare

@pradyunsg pradyunsg released this 19 Apr 11:49
25.0
f585376

What's Changed

New Contributors

Full Changelog: 24.2...25.0

24.2

Choose a tag to compare

@pradyunsg pradyunsg released this 08 Nov 09:48
24.2
d8e3b31

What's Changed

New Contributors

Full Changelog: 24.1...24.2

24.1

Choose a tag to compare

@pradyunsg pradyunsg released this 09 Jun 23:19
24.1
85442b8

What's Changed

New Contributors

Full Changelog: 24.0...24.1