214

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.

Mark Chackerian
  • 19,405
  • 6
  • 103
  • 97

8 Answers8

283

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]
djsutho
  • 4,524
  • 1
  • 21
  • 24
  • 9
    I believe to fully answer @mark 's question you would need to run: `pipdeptree -r` "Shows the dependency tree in the reverse fashion ie. the sub-dependencies are listed with the list of packages that need them under them." – Esteban Jul 26 '16 at 21:28
  • How can you view the reverse tree for all PyPi packages, not only the locally installed packages? – Tijme Jul 18 '17 at 16:16
  • 2
    `pipdeptree` is great. Unfortunately it does not appear to take into account dependencies for packages installed by conda: e.g. in a conda env where `matplotlib` and `numpy` were installed using pip, but `scipy` was installed using conda, `scipy` shows up in the pipdeptree as having no depencies and no dependents (also `pip show scipy` shows no requirements). – djvg Sep 27 '18 at 09:01
  • @Dennis I've not tried it but this might work for conda https://github.com/rvalieris/conda-tree – djsutho Oct 05 '18 at 02:05
  • I use `pipdeptree -l -f` instead of just `pip freeze` and it's a pleasure to visually see the dependencies directly in the requirements file. – Eric Dec 02 '19 at 17:38
  • 2
    To use this in a virtual environment, you need to do `python -m pipdeptree` otherwise (even when the executable is installed to the virtualenv) it only lists the system dependencies. – Zim Dec 09 '19 at 18:26
  • 3
    pipdeptree is great, but it only works if the package is already installed. – Ben Farmer Dec 23 '20 at 00:11
113

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

Rob Bednark
  • 22,937
  • 20
  • 77
  • 112
Bengineer
  • 6,752
  • 7
  • 24
  • 28
  • 1
    `pip show` was introduced in version 1.4rc5, and is present in the (current as of writing) 1.4.1 – drevicko Oct 23 '13 at 02:52
  • 13
    This doesn't answer my question exactly, because it shows the children (dependencies) for a specific package, instead of the parents. But it's easy enough to throw something together to check the dependencies of each package, using this command. So, for example, I could determine which installed package required PyYAML. – Mark Chackerian Feb 21 '14 at 09:27
  • 4
    As per my previous comment, this shell command dumps out all of the dependencies for each of my installed packages: $ pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' – Mark Chackerian Feb 21 '14 at 15:15
  • An updated version of the script from my previous comment is `pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/` -- but it seems that pipdeptree is now a better solution. – Mark Chackerian Aug 03 '17 at 15:26
  • As of pip 22.0.3 (and possibly earlier), `pip show` shows both other packages which require the package and other packages which are required by the package – binaryfunt Mar 24 '22 at 10:34
20

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.
guettli
  • 23,964
  • 63
  • 293
  • 556
Maxime R.
  • 8,861
  • 7
  • 52
  • 58
  • 2
    I just don't understand why this ``pip freeze -r requirements.txt`` is not widely used. Very useful for maintaining the dependencies and sub dependencies. – Penkey Suresh Jul 03 '17 at 08:43
  • 2
    minor note: `pip install` no longer supports `--no-install`. – ryan Oct 11 '18 at 16:18
7

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
biophetik
  • 833
  • 8
  • 5
3

The following command will show requirements of all installed packages:

pip3 freeze | awk '{print $1}' | cut -d '=' -f1 | xargs pip3 show
3

First of all pip freeze displays all currently installed packages Python, not necessarily using PIP.

Secondly Python packages do contain the information about dependent packages as well as required versions. You can see the dependencies of particular pkg using the methods described here. When you're upgrading a package the installer script like PIP will handle the upgrade of dependencies for you.

To solve updating of packages i recommend using PIP requirements files. You can define what packages and versions you need, and install them at once using pip install.

Community
  • 1
  • 1
Mariusz Jamro
  • 29,116
  • 24
  • 107
  • 151
1

(workaround, not true answer)

Had the same problem, with lxml not installing and me wanting to know who needed lxml. Not who lxml needed. Ended up bypassing the issue by.

  1. noting where my site packages were being put.

  2. go there and recursive grep for the import (the last grep's --invert-match serves to remove lxml's own files from consideration).

Yes, not an answer as to how to use pip to do it, but I didn't get any success out of the suggestions here, for whatever reason.

 site-packages me$ egrep -i --include=*.py  -r -n lxml . | grep import | grep --invert-match /lxml/
JL Peyret
  • 9,051
  • 2
  • 41
  • 63
1

I wrote a quick script to solve this problem. The following script will display the parent (dependant) package(s) for any given package. This way you can be sure it is safe to upgrade or install any particular package. It can be used as follows: dependants.py PACKAGENAME

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Find dependants of a Python package"""

import logging
import pip
import pkg_resources
import sys

__program__ = 'dependants.py'


def get_dependants(target_name):
    for package in pip._internal.utils.misc.get_installed_distributions():
        for requirement_package in package.requires():
            requirement_name = requirement_package.project_name
            if requirement_name == target_name:
                yield package.project_name


# configure logging
logging.basicConfig(format='%(levelname)s: %(message)s',
                    level=logging.INFO)

try:
    target_name = sys.argv[1]
except IndexError:
    logging.error('missing package name')
    sys.exit(1)

try:
    pkg_resources.get_distribution(target_name)
except pkg_resources.DistributionNotFound:
    logging.error("'%s' is not a valid package", target_name)
    sys.exit(1)

print(list(get_dependants(target_name)))
Six
  • 4,562
  • 3
  • 27
  • 37
  • 1
    This no longer works because the `get_installed_distributions()` method is no longer available. https://github.com/pypa/pip/issues/5243 – Phil Gyford Mar 07 '19 at 14:55