packaging
Reusable core utilities for Python packaging interoperability specifications. Implements PEP 440 version handling, specifiers, markers, requirements, tags, metadata, and lockfiles. Used internally by pip, setuptools, and most build tools. Uses calendar-based versioning (YY.N). Current version is 26.0 (2026).
Warnings
- breaking LegacyVersion and LegacySpecifier were removed in 22.0. packaging.version.parse() now raises InvalidVersion for non-PEP 440 version strings instead of silently returning a LegacyVersion object.
- breaking SpecifierSet and Specifier were moved from packaging.version to packaging.specifiers in an early release. Importing from packaging.version will fail.
- breaking Optional metadata.Metadata attributes now default to None (changed in 24.0). Code checking for empty-string defaults will silently mishandle absent fields.
- gotcha SpecifierSet.filter() and Specifier.contains() exclude pre-releases by default unless the specifier itself includes a pre-release version. Pass prereleases=True explicitly to include them.
- gotcha canonicalize_name() returns a NormalizedName (typing.NewType of str). Mixing raw strings and NormalizedName values causes mypy errors. Always canonicalize before comparing package names.
- gotcha The library uses calendar versioning (YY.N), not semver. There is no reliable way to determine whether a release contains breaking changes from the version number alone.
- gotcha packaging has no runtime dependencies since 21.0 (pyparsing was removed and replaced with a hand-written parser). Do not add pyparsing as a workaround for older compatibility issues.
Install
-
pip install packaging
Imports
- Version
from packaging.version import Version
- parse
from packaging.version import Version, parse
- SpecifierSet
from packaging.specifiers import SpecifierSet
- Requirement
from packaging.requirements import Requirement
- canonicalize_name
from packaging.utils import canonicalize_name
- Marker
from packaging.markers import Marker
Quickstart
from packaging.version import Version
from packaging.specifiers import SpecifierSet
from packaging.requirements import Requirement
from packaging.utils import canonicalize_name
# Parse and compare PEP 440 versions
v = Version('1.2.3')
print(v.major, v.minor, v.micro) # 1 2 3
print(v.is_prerelease) # False
# Check if a version satisfies a specifier
spec = SpecifierSet('>=1.0,<2.0')
print(v in spec) # True
# Parse a PEP 508 requirement string
req = Requirement('requests[security]>=2.28; python_version>="3.8"')
print(req.name) # requests
print(req.extras) # {'security'}
print(req.specifier) # >=2.28
print(req.marker) # python_version >= "3.8"
# Normalize a package name (PEP 503)
print(canonicalize_name('Django')) # django
print(canonicalize_name('oslo.concurrency')) # oslo-concurrency