Skip to main content
added 7 characters in body
Source Link
NicoHood
  • 1.2k
  • 14
  • 19
pip3 freeze -r requirements.txt | sed -n '/## The following requirements were added by pip freeze:/q;p' >| sponge requirements.txt
pip3 freeze -r requirements.txt | sed -n '/## The following requirements were added by pip freeze:/q;p' > requirements.txt
pip3 freeze -r requirements.txt | sed -n '/## The following requirements were added by pip freeze:/q;p' | sponge requirements.txt
Source Link
NicoHood
  • 1.2k
  • 14
  • 19

I had the same question and I came up with a more generic and simple solution. I am using the well-known requirements.txt for all explicit dependencies and requirements.lock as a list of all packages including sub dependencies.

I personally like to manage python, pip and setuptools via the distributions builtin package manager and install pip dependencies inside a virtual environment.

Usually you would start installing all directly required dependencies. This will pull in all sub dependencies as well. If you are not using a virtual environment make sure to add the --user flag.

# If you already have a requirements file
pip3 install -r requirements.txt

# If you start from scratch
pip3 install <package>

If you want to upgrade your packages, you have multiple options here as well. Since I am using a virtual environment I will always update all packages. However you are free to only update your direct requirements. If they need an update of their dependencies, those will be pulled in as well, everything else will be left untouched.

# Update all outdated packages (excluding pip and setuptools itself)
pip3 install -r <(pip3 list --outdated --format freeze --exclude pip setuptools | cut -d '=' -f1) --upgrade

# Update explicitly installed packages, update sub dependencies only if required.
pip3 install -r <(cut -d '=' -f1 requirements.txt) --upgrade

Now we come to the tricky part: Saving back our requirements file. Make sure that the previous requirements file is checked into git, so if anything goes wrong you have a backup.

Remember that we want to differentiate between packages explicitly installed (requirements.txt) and packages including their dependencies (requirements.lock).

If you have not yet setup a requirements.txt I suggest running the following command. Note that it will not include sub dependencies if they are already satisfied by another package. This means requests will not be included in the list, if it was already satisfied by another package. You might still want to add that manually, if your script explicitly relies on such a package.

pip3 list --not-required --format freeze --exclude pip --exclude setuptools > requirements.txt

If you already have a requirements.txt you can update it by using this sed trick. This will leave all sub-dependencies outside, which we will only include in the requirements.lock in the next step.

pip3 freeze -r requirements.txt | sed -n '/## The following requirements were added by pip freeze:/q;p' > requirements.txt

Finally we can output all dependencies to a requirements.lock file which will be our complete list of all packages and versions. If we have issues to reproduce an issue, we can always come back to this lock file and run our code with the previously working dependencies.

# It is important to use the -r option here, so pip will differenciate between directly required packages and dependencies.
pip3 freeze -r requirements.txt > requirements.lock