Identifying the dependency relationship for python packages installed with pip

When I do a pip freeze I see large number of Python packages that I didn't explicitly install, e.g.

$ pip freeze
Cheetah==2.4.3
GnuPGInterface==0.3.2
Landscape-Client==11.01
M2Crypto==0.20.1
PAM==0.4.2
PIL==1.1.7
PyYAML==3.09
Twisted-Core==10.2.0
Twisted-Web==10.2.0
(etc.)

Is there a way for me to determine why pip installed these particular dependent packages? In other words, how do I determine the parent package that had these packages as dependencies?

For example, I might want to use Twisted and I don't want to depend on a package until I know more about not accidentally uninstalling it or upgrading it.


Solution 1:

You could try pipdeptree which displays dependencies as a tree structure e.g.:

$ pipdeptree
Lookupy==0.1
wsgiref==0.1.2
argparse==1.2.1
psycopg2==2.5.2
Flask-Script==0.6.6
  - Flask [installed: 0.10.1]
    - Werkzeug [required: >=0.7, installed: 0.9.4]
    - Jinja2 [required: >=2.4, installed: 2.7.2]
      - MarkupSafe [installed: 0.18]
    - itsdangerous [required: >=0.21, installed: 0.23]
alembic==0.6.2
  - SQLAlchemy [required: >=0.7.3, installed: 0.9.1]
  - Mako [installed: 0.9.1]
    - MarkupSafe [required: >=0.9.2, installed: 0.18]
ipython==2.0.0
slugify==0.0.1
redis==2.9.1

To get it run:

pip install pipdeptree


EDIT: as noted by @Esteban in the comments you can also list the tree in reverse with -r or for a single package with -p <package_name> so to find what installed Werkzeug you could run:

$ pipdeptree -r -p Werkzeug
Werkzeug==0.11.15
  - Flask==0.12 [requires: Werkzeug>=0.7]

Solution 2:

The pip show command will show what packages are required for the specified package (note that the specified package must already be installed):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show was introduced in pip version 1.4rc5

Solution 3:

As I recently said on a hn thread, I'll recommend the following:

Have a commented requirements.txt file with your main dependencies:

## this is needed for whatever reason
package1

Install your dependencies: pip install -r requirements.txt. Now you get the full list of your dependencies with pip freeze -r requirements.txt:

## this is needed for whatever reason
package1==1.2.3

## The following requirements were added by pip --freeze:
package1-dependency1==1.2.3
package1-dependency1==1.2.3

This allows you to keep your file structure with comments, nicely separating your dependencies from the dependencies of your dependencies. This way you'll have a much nicer time the day you need to remove one of them :)

Note the following:

  • You can have a clean requirements.raw with version control to rebuild your full requirements.txt.
  • Beware of git urls being replaced by egg names in the process.
  • The dependencies of your dependencies are still alphabetically sorted so you don't directly know which one was required by which package but at this point you don't really need it.
  • Use pip install --no-install <package_name> to list specific requirements.
  • Use virtualenv if you don't.

Solution 4:

You may also use a one line command which pipes the packages in requirements to pip show.

cut -d'=' -f1 requirements.txt | xargs pip show