Skip to content

Use “pip install” safely

Published: December 7, 2023. Filed under: Django, Python.

This is part of a series of posts I’m doing as a sort of Python/Django Advent calendar, offering a small tip or piece of information each day from the first Sunday of Advent through Christmas Eve. See the first post for an introduction.

Managing dependencies should be boring

Last year I wrote a post about “boring” dependency management in Python, where I advocated a setup based entirely around standard Python packaging tools, in that case the pip package installer and the venv module for creating virtual environments (the only non-standard thing I recommended there was pip-tools, and specifically its pip-compile script, and the only reason I’m willing to recommend it at all is that you can replace it by writing your own script that strings together the equivalent pip commands; it’s just a convenience to save you having to do that yourself).

The end result of that process, if you follow it, will be a set of “requirements files” which can be given to pip to install from, and which will contain your entire dependency tree, fully resolved including all transitive dependencies-of-dependencies-of-dependencies (etc.), pinned to exact versions, and listing the expected hashes of the packages.

The last step, of course, is to install those packages, which I recommend you do with pip. But I want to build on that a little bit, and I may go back and update part of the original post. Originally I did explain why to use python -m pip instead of pip, which is something I’d seen and learned to do a while back, but never had a great one-page explainer for until Brett Cannon wrote one.

But you can and probably should go a little further than this, by passing a few extra flags to pip. Specifically, in the original post I gave the example of running

python -m pip install -r requirements/app.txt

But really it ought to be:

python -m pip install \
    --require-hashes \
    --no-deps \
    --only-binary :all: \
    -r requirements/app.txt

Let’s unpack that:

Brett Cannon, who wrote the above-linked explanation of why to use python -m pip, also has published a GitHub Action which automatically runs pip with these flags, to ensure you’re using it as securely as possible when running your CI.