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.