266

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
  • 21,866
  • 6
  • 108
  • 99

10 Answers10

347

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
  • 5,174
  • 1
  • 23
  • 25
  • 13
    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
  • 4
    pipdeptree is great, but it only works if the package is already installed. – Ben Farmer Dec 23 '20 at 00:11
125

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
  • 25,981
  • 23
  • 80
  • 125
Bengineer
  • 7,264
  • 7
  • 27
  • 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
  • 16
    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
27

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
  • 25,042
  • 81
  • 346
  • 663
Maxime R.
  • 9,621
  • 7
  • 53
  • 59
  • 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
  • 4
    minor note: `pip install` no longer supports `--no-install`. – ryan Oct 11 '18 at 16:18
10

The following command will show requirements of all installed packages:

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

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

(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
  • 10,917
  • 2
  • 54
  • 73
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
  • 30,615
  • 24
  • 120
  • 162
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 pkg_resources  # tested with Python 2.7, 3.6 and 3.10
import sys

__program__ = 'dependants.py'


def get_dependants(target_name):
    for package in pkg_resources.working_set:
        for requirement_package in package.requires():
            requirement_name = requirement_package.key
            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)))
bufh
  • 3,153
  • 31
  • 36
Six
  • 5,122
  • 3
  • 29
  • 38
  • 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
1

You have two options here.

#1

The first will output all top-level packages, excluding sub packages. Note that this will also exclude for example requests, even if you want to have it explicitly installed and include dependencies not explicit installed via pip (e.g. pip itself or setuptools which are needed by pip). Side note: these implicit dependencies can be also listed with pip freeze when used with the option --all. If you want to omit these extra dependencies one might exclude them with the --exclude option.

pip3 list --not-required --format freeze --exclude pip --exclude setuptools

#2

The second option is to print the packages based on the existing requirements.txt file.

pip3 freeze -r requirements.txt

This will generate a file in the format:

existing-package==1.0.0
## The following requirements were added by pip freeze:
dependency-package==1.0.0

You can remove all the additionally added packages by using sed:

pip3 freeze -r requirements.txt \
    | sed -n '/^## The following requirements were added by pip freeze:$/q;p'
netzego
  • 372
  • 4
  • 15
NicoHood
  • 687
  • 5
  • 12
  • It is worth mentioning that both outputs from `pip freeze --all` and `pip list --format=freeze` are identical. – netzego May 16 '23 at 18:23
1

With GraphVis as seen on tv

If you like graphs you can use graphviz (Documentation)

pip install graphviz

Then do something like this:

#! /usr/bin/env python3
import graphviz
import pkg_resources

GRAPH_NAME = "pipdeps"

def init_grph():
    grph = graphviz.Digraph(GRAPH_NAME,
                     node_attr={'color': 'lightblue2', 'style': 'filled'})

    # This does not seem to be interpreted on websites I tested
    grph.attr(engine='neato')

    return grph

def add_pip_dependencies_to_graph(grph):
    l_packages = [p for p in pkg_resources.working_set]

    for package in l_packages:
        name = package.key
        for dep in package.requires():
            grph.edge(dep.key, name)

def main():
    grph = init_grph()
    add_pip_dependencies_to_graph(grph)

    print(grph.source)
    # grph.view()

main()

This prints a dotgraph/digraph/graphviz (idk ‍♀️)

You can view it for example in an online graphviz visualiser (e.g. https://dreampuf.github.io/GraphvizOnline)

Alternatively if you have a graphic interface () you can use grph.view()

screenshot of example graphical result

Karol Zlot
  • 2,887
  • 2
  • 20
  • 37
Boop
  • 1,217
  • 1
  • 15
  • 22