Control Unsafe Packages

pip-compile treats a few packages as unsafe to pin. By default these are pip, setuptools and the long-retired distribute, since they’re the tools doing the installing. Users can pin them anyway, or choose their own list, which is also a way to keep a package out of the output entirely.

See the Default Output

Suppose your requirements.in lists setuptools and six. six is pinned as usual, but setuptools ends up at the bottom as a comment:

$ pip-compile --no-header requirements.in
six==1.17.0
    # via -r requirements.in

# The following packages are considered to be unsafe in a requirements file:
# setuptools

Because it’s only a comment, pip install -r requirements.txt won’t install it.

Pin Unsafe Packages

Pass --allow-unsafe to pin them like any other package:

$ pip-compile --no-header --allow-unsafe requirements.in
six==1.17.0
    # via -r requirements.in

# The following packages are considered to be unsafe in a requirements file:
setuptools==84.2.1
    # via -r requirements.in

This will be the default in the next major release. To keep the current behavior after that, pass --no-allow-unsafe.

Use Unsafe Packages With Hashes

With --generate-hashes, leaving unsafe packages unpinned can break installs. pip refuses to install an unpinned package from a file that has hashes, unless it’s already installed, so pip-compile warns you:

$ pip-compile --no-header --generate-hashes requirements.in
six==1.17.0     --hash=sha256:...
    # via -r requirements.in

# WARNING: The following packages were not pinned, but pip requires them to be
# pinned when the requirements file includes hashes and the requirement is not
# satisfied by a package already installed. Consider using the --allow-unsafe flag.
# setuptools

Pass --allow-unsafe as well to pin them with their hashes.

Choose Which Packages Are Unsafe

Pass --unsafe-package to name the packages yourself. It replaces the default list instead of adding to it, so setuptools is pinned again here:

$ pip-compile --no-header --unsafe-package six requirements.in
setuptools==84.2.1
    # via -r requirements.in

# The following packages are considered to be unsafe in a requirements file:
# six

To keep the defaults as well, repeat the option for each package:

$ pip-compile --no-header --unsafe-package six --unsafe-package setuptools requirements.in

# The following packages are considered to be unsafe in a requirements file:
# setuptools
# six

Combine Both Options

If you pass both, --allow-unsafe takes priority. Packages named with --unsafe-package are still listed in the unsafe section, but they’re pinned:

$ pip-compile --no-header --allow-unsafe --unsafe-package six requirements.in
setuptools==84.2.1
    # via -r requirements.in

# The following packages are considered to be unsafe in a requirements file:
six==1.17.0
    # via -r requirements.in

Keep Your Own Project Out of the Output

An extra can refer back to its own project to reuse other extras:

[project.optional-dependencies]
test = ["iniconfig"]
dev = ["foo-example[test]"]

Compiling dev then lists foo-example itself, pinned to a local path:

$ pip-compile --no-header --extra dev pyproject.toml
foo-example[test] @ file:///path/to/project
    # via foo-example (pyproject.toml)
iniconfig==2.3.1
    # via foo-example

To leave it out, mark your project as unsafe:

$ pip-compile --no-header --extra dev --unsafe-package foo-example pyproject.toml
iniconfig==2.3.1
    # via foo-example

# The following packages are considered to be unsafe in a requirements file:
# foo-example