2025, Dec 16 17:00
How to install a compatible Black without upgrading packaging: pin packaging==21.3 with pip constraints
Learn how to install Black without upgrading packaging by using pip constraints or pinning packaging==21.3, preserving a stable Python environment. Safely.
Keeping a Python environment stable while adding new tooling can be tricky. A common case: a project pins packaging==21.3, but installing the latest Black pulls in packaging>=22.0 and silently upgrades the dependency. If you’re not ready to change runtime assumptions, you need a way to install a compatible Black without manually hunting versions.
Reproducing the issue
Installing Black straight from PyPI resolves to the newest release and upgrades transitive dependencies. On a system where packaging==21.3 is already present, you’ll see something like this:
$ pip install black
Collecting packaging>=22.0 (from black)
Using cached packaging-25.0-py3-none-any.whl.metadata (3.3 kB)
Installing collected packages: packaging, black
Attempting uninstall: packaging
Found existing installation: packaging 21.3
Uninstalling packaging-21.3:
Successfully uninstalled packaging-21.3
Successfully installed black-25.1.0 packaging-25.0
That upgrade is exactly what we want to avoid on a fresh system where behavior must stay unchanged.
What’s going on
The latest Black depends on packaging>=22.0. When you ask pip for black without any other constraints, it selects the newest Black and then upgrades packaging to satisfy that dependency. If your project must keep packaging==21.3, you need to instruct the resolver to respect that constraint while choosing a compatible Black release. The dependency in Black that requires packaging>=22.0 was added in 23.1.0, so older Black versions remain compatible with packaging==21.3.
Practical ways to install a compatible Black
The simplest fix is to use a constraints file that pins packaging to 21.3 and let pip backtrack to a Black version that works with it. This avoids guessing versions by trial and error.
echo "packaging==21.3" > constraints.txt
pip install black -c constraints.txt
If you prefer a one-liner without a separate file, pin packaging explicitly in the same command. Pip will resolve a Black release that fits:
pip install black packaging==21.3
When your project already has a requirements.txt with packaging==21.3, you can reuse it as a constraints source during installation:
pip install black -c requirements.txt
Why this matters
Tooling should be easy to add without destabilizing a working environment. By steering pip with constraints, you preserve pinned dependencies and let the resolver find a matching tool version automatically. This means no manual version spelunking, fewer surprises in CI, and safer onboarding on new systems.
Takeaways
When adding development tools like Black to a project with strict pins, don’t install blindly. Keep packaging==21.3 fixed via a constraints file or by pinning it in the install command, and let pip choose a compatible Black release. If your repo already maintains a requirements.txt, reuse it with -c to enforce the existing versions.