157

Without going through with the installation, I want to quickly see all the packages that pip install would install.

denis
  • 21,378
  • 10
  • 65
  • 88
lastoneisbearfood
  • 3,955
  • 5
  • 26
  • 25
  • 1
    Related: http://stackoverflow.com/q/9232568/183791 – dusan Jun 21 '12 at 22:41
  • Another question including alternative answers for this problem: https://stackoverflow.com/questions/41816693/how-to-list-dependencies-for-a-python-library-without-installing – pgmank Sep 28 '19 at 14:43

11 Answers11

148

Check out my project johnnydep!

Installation:

pip install johnnydep

Usage example:

$ johnnydep requests
name                       summary
-------------------------  ----------------------------------------------------------------------
requests                   Python HTTP for Humans.
├── certifi>=2017.4.17     Python package for providing Mozilla's CA Bundle.
├── chardet<3.1.0,>=3.0.2  Universal encoding detector for Python 2 and 3
├── idna<2.7,>=2.5         Internationalized Domain Names in Applications (IDNA)
└── urllib3<1.23,>=1.21.1  HTTP library with thread-safe connection pooling, file post, and more.

A more complex tree:

$ johnnydep ipython 
name                              summary
--------------------------------  -----------------------------------------------------------------------------
ipython                           IPython: Productive Interactive Computing
├── appnope                       Disable App Nap on OS X 10.9
├── decorator                     Better living through Python with decorators
├── jedi>=0.10                    An autocompletion tool for Python that can be used for text editors.
│   └── parso==0.1.1              A Python Parser
├── pexpect                       Pexpect allows easy control of interactive console applications.
│   └── ptyprocess>=0.5           Run a subprocess in a pseudo terminal
├── pickleshare                   Tiny 'shelve'-like database with concurrency support
├── prompt-toolkit<2.0.0,>=1.0.4  Library for building powerful interactive command lines in Python
│   ├── six>=1.9.0                Python 2 and 3 compatibility utilities
│   └── wcwidth                   Measures number of Terminal column cells of wide-character codes
├── pygments                      Pygments is a syntax highlighting package written in Python.
├── setuptools>=18.5              Easily download, build, install, upgrade, and uninstall Python packages
├── simplegeneric>0.8             Simple generic functions (similar to Python's own len(), pickle.dump(), etc.)
└── traitlets>=4.2                Traitlets Python config system
    ├── decorator                 Better living through Python with decorators
    ├── ipython-genutils          Vestigial utilities from IPython
    └── six                       Python 2 and 3 compatibility utilities
wim
  • 338,267
  • 99
  • 616
  • 750
  • I downloaded this and use it, it's a great package. BUT doesn't it require packages to be installed? The OP is specifically requesting an approach that doesn't require installation. Important to caveat. – so860 Aug 06 '19 at 16:28
  • 8
    @so860 No, it does not require the packages to be installed. That's the whole point, it works in an isolated environment. – wim Aug 06 '19 at 16:37
  • 4
    To be clear: installing `johnnydep` itself installs dependencies. – GPHemsley May 01 '20 at 08:34
  • 3
    @wim: this project is pure brillance ! Love it ! – Jonathan DEKHTIAR Aug 25 '20 at 23:57
  • 1
    This seems like a nice package, but it *does* seem to install the packages. In a separate env, sure, but it still has to actually install the packages there, which is very slow when there are a lot of packages, and it fails if the installation of a package fails. So I do not think it fulfils the OP requirement to see the dependencies without going through the installation process. – Ben Farmer Dec 22 '20 at 01:31
  • 4
    @BenFarmer That's incorrect. It doesn't install packages, it reads the metadata from [wheel](https://www.python.org/dev/peps/pep-0427/) files, which does require a package download- but not an installation. In the rare case that a project has published a source distribution but no compatible wheel is available, then pip will attempt to generate a wheel from the sdist (that is [the only reliable way to get package metadata](https://discuss.python.org/t/sdist-idea-specifying-static-metadata-that-can-be-trusted/4703/12) from sdist). In the most common case, there is no installation process. – wim Dec 22 '20 at 02:03
  • It is a slow process for large dep trees, unfortunately, because the PyPI json APIs don't provide the necessary information to do this without a package download. That's not something specific to johnnydep though, poetry and other projects all have the same slowness due to the package download requirements. – wim Dec 22 '20 at 02:09
  • Ah my mistake, I just saw output about setup.py, and "Failed to build scipy, Cleaning up..." and assumed it was doing an install. It's a bit absurd that this is so hard in Python. Or I guess pip. I guess maybe conda can do it more easily, if you only need to use that. – Ben Farmer Dec 22 '20 at 03:28
  • lovely utilizy. Thank you! – yooloobooy Jan 18 '21 at 00:11
  • 3
    @GPHemsley .. and it has quite some dependencies, see `pip show`: `Requires: structlog, wheel, setuptools, wimpy, cachetools, anytree, distlib, tabulate, colorama, pip, packaging, toml, pkginfo, oyaml` – Timo Jul 03 '21 at 05:48
115

This was tested with pip versions 8.1.2, 9.0.1, 10.0.1, and 18.1.

To get the output without cluttering your current directory on Linux use

pip download [package] -d /tmp --no-binary :all: -v

-d tells pip the directory that download should put files in.

Better, just use this script with the argument being the package name to get only the dependencies as output:

#!/bin/sh

PACKAGE=$1
pip download $PACKAGE -d /tmp --no-binary :all:-v 2>&1 \
| grep Collecting \
| cut -d' ' -f2 \
| grep -Ev "$PACKAGE(~|=|\!|>|<|$)"

Also available here.

wim
  • 338,267
  • 99
  • 616
  • 750
Jmills
  • 2,414
  • 2
  • 19
  • 22
  • A very (*very*) crude reading of `requirements.txt` using this: `< requirements.txt egrep -v "^#" | egrep -v "^$" | xargs -L 1 -I % sh -c 'echo %; echo "======"; ./deps.sh %; echo "";` – Ian Clark Jun 11 '18 at 10:25
  • @hans-musgrave made a good point in another answer that I hadn't noticed previously, so updated the bash script to only exclude lines that match the package along with end of line or the start of a valid [version specifier](https://www.python.org/dev/peps/pep-0440/#version-specifiers) rather than any line that contains the package name. – Jmills Jun 25 '18 at 22:41
  • 5
    Some packages *only* provide binary, so `--no-binary :all:` is not a good idea. A project which only shipped wheel and not sdist would fail. – wim Apr 19 '19 at 18:17
  • 7
    This end up download and compile for all the dependence packages which can be very slow.... – Louis Yang Sep 04 '19 at 20:36
  • For those wanting a quick one-liner, here's an example for pandas, with files being stored in `~/pip-tmp`: `pip download pandas -d ~/pip-tmp -v 2>&1 | grep "Collecting"`. This gives you a quick overview of what the requirements are. Obviously you'd then want to delete the files from the `~/pip-tmp` directory. Also I guess it could take a while if there are a plethora of requirements. – jenniwren Jan 06 '20 at 23:42
  • 1
    Since recent versions of pip can be using PEP 517 / PEP 518, this may also start to turn up false positives because of the build-system requirements. Unreliable. – wim Jan 29 '20 at 20:56
  • 2
    Note that this does not list dependencies that are already installed (which is fine for OP). – GPHemsley May 01 '20 at 08:31
  • 1
    What if I want to do this for a local package I am working on? e.g. that I would install with "pip install -e ./mypackage"? Sometimes I just want to know what the full dependency tree is for a project that I am working on. – Ben Farmer Dec 22 '20 at 03:37
28

If and only if the package is installed, you can use pip show <package>. Look for the Requires: field at the end of the output. Clearly, this breaks your requirement but might be useful nonetheless.

For example:

$ pip --version
pip 7.1.0 [...]
$ pip show pytest
---
Metadata-Version: 2.0
Name: pytest
Version: 2.7.2
Summary: pytest: simple powerful testing with Python
Home-page: http://pytest.org
Author: Holger Krekel, Benjamin Peterson, Ronny Pfannschmidt, Floris Bruynooghe and others
Author-email: holger at merlinux.eu
License: MIT license
Location: /home/usr/.tox/develop/lib/python2.7/site-packages
Requires: py
Mustafa Aydın
  • 17,645
  • 4
  • 15
  • 38
Sardathrion - against SE abuse
  • 17,269
  • 27
  • 101
  • 156
  • 3
    This only shows the direct requirements, all the transitive dependencies would be missing. And it requires an installation. So, it doesn't really answer the question. – wim Jun 18 '19 at 13:58
18

Note: the feature used in this answer was deprecated in 2014 and removed in 2015. Please see other answers that apply to modern pip.

The closest you can get with pip directly is by using the --no-install argument:

pip install --no-install <package>

For example, this is the output when installing celery:

Downloading/unpacking celery                                                                                   
  Downloading celery-2.5.5.tar.gz (945Kb): 945Kb downloaded
  Running setup.py egg_info for package celery

    no previously-included directories found matching 'tests/*.pyc'
    no previously-included directories found matching 'docs/*.pyc'
    no previously-included directories found matching 'contrib/*.pyc'
    no previously-included directories found matching 'celery/*.pyc'
    no previously-included directories found matching 'examples/*.pyc'
    no previously-included directories found matching 'bin/*.pyc'
    no previously-included directories found matching 'docs/.build'
    no previously-included directories found matching 'docs/graffles'
    no previously-included directories found matching '.tox/*'
Downloading/unpacking anyjson>=0.3.1 (from celery)
  Downloading anyjson-0.3.3.tar.gz
  Running setup.py egg_info for package anyjson

Downloading/unpacking kombu>=2.1.8,<2.2.0 (from celery)
  Downloading kombu-2.1.8.tar.gz (273Kb): 273Kb downloaded
  Running setup.py egg_info for package kombu

Downloading/unpacking python-dateutil>=1.5,<2.0 (from celery)
  Downloading python-dateutil-1.5.tar.gz (233Kb): 233Kb downloaded
  Running setup.py egg_info for package python-dateutil

Downloading/unpacking amqplib>=1.0 (from kombu>=2.1.8,<2.2.0->celery)
  Downloading amqplib-1.0.2.tgz (58Kb): 58Kb downloaded
  Running setup.py egg_info for package amqplib

Successfully downloaded celery anyjson kombu python-dateutil amqplib

Admittedly, this does leave some cruft around in the form of temporary files, but it does accomplish the goal. If you're doing this with virtualenv (which you should be), the cleanup is as easy as removing the <virtualenv root>/build directory.

  • 8
    The reason for this is that the metadata doesn't exist outside of setup.py so unlike say with `rpm` or `dpkg` where you build a metadata index on top and query that `pip` and `pypi` don't work that way. So we have to pass over each requirement. –  Jun 22 '12 at 15:40
  • Thanks @paul, your comment makes the answer complete – lastoneisbearfood Jun 22 '12 at 20:51
  • 12
    I tried `pip --no-install celery` but I receive the error `no such option: --no-install` (pip 1.2.1) – Colonel Panic Dec 13 '12 at 20:35
  • 4
    I think he meant `pip install --no-install celery` – entropy Jan 24 '13 at 00:57
  • 23
    On my pip version (1.5.4) the `--no-install` flag is deprecated. – Jian May 09 '14 at 06:26
  • 4
    For 1.5.4, use pip install --download=. --no-use-wheel celery – radtek Aug 05 '14 at 20:27
  • pip now displays a warning deprecating --download and --no-use-wheel as well. – Alison S Apr 27 '16 at 14:55
  • 3
    Pip now says to use `pip download `. They sure are deprecation happy! – Merlyn Morgan-Graham May 09 '16 at 00:54
  • `pip download ` technically works, but has the obvious disadvantage of polluting the current working directory with package cruft. See [The Card Cheat](https://stackoverflow.com/users/1210112/the-card-cheat)'s [one-liner and related shell script](https://stackoverflow.com/a/38531949/2809027) for clever alternatives. – Cecil Curry Aug 09 '16 at 05:01
  • isn't pip freeze supposed to do this? – Alexander Fradiani Oct 29 '16 at 16:27
  • 3
    I'm glad a command ridiculous sounding as "pip install --no-install" was deprecated .. :) – wim Mar 07 '18 at 02:08
12

I quote an alternative solution from @onnovalkering:

PyPi provides a JSON endpoint with package metadata:

>>> import requests
>>> url = 'https://pypi.org/pypi/{}/json'
>>> json = requests.get(url.format('pandas')).json()
>>> json['info']['requires_dist']
['numpy (>=1.9.0)', 'pytz (>=2011k)', 'python-dateutil (>=2.5.0)']
>>> json['info']['requires_python']
'>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*'

For a specific package version, add an additional version segment to the URL:

https://pypi.org/pypi/pandas/0.22.0/json

Also if you are using conda (as suggested by @ShpielMeister), you can use:

conda info package==X.X.X

to display information, including dependencies for a particular version or:

conda info package

to display information, including dependencies about all supported versions of that package.

pgmank
  • 5,303
  • 5
  • 36
  • 52
  • 2
    I downvoted because this json endpoint is not reliable. For an example look at [`boto3`](https://pypi.org/pypi/boto3/json), the requires_dist is null but that is a project which [certainly has dependencies in the metadata](https://github.com/boto/boto3/blob/develop/setup.py#L16-L20). – wim Dec 18 '19 at 03:07
  • 1
    The example for boto3 contains the required packages (`curl -L 'https://pypi.python.org/pypi/boto3/json' | jq '.info.requires_dist'`). So I am not sure if the critique is still valid. – p13rr0m Jul 27 '22 at 08:40
9

Use pipdeptree ( pip install pipdeptree). Needs the package to be installed.

$ pipdeptree -p pandas
pandas==1.2.2
  - numpy [required: >=1.16.5, installed: 1.19.5]
  - python-dateutil [required: >=2.7.3, installed: 2.8.1]
    - six [required: >=1.5, installed: 1.15.0]
  - pytz [required: >=2017.3, installed: 2021.1]

Use johnnydep (pip install johnnydep). Slower because it download the wheels of the packages.

$ johnnydep pandas
2021-06-09 11:01:21 [info     ] init johnnydist                [johnnydep.lib] dist=pandas parent=None
2021-06-09 11:01:22 [info     ] init johnnydist                [johnnydep.lib] dist=numpy>=1.16.5 parent=pandas
2021-06-09 11:01:22 [info     ] init johnnydist                [johnnydep.lib] dist=python-dateutil>=2.7.3 parent=pandas
2021-06-09 11:01:23 [info     ] init johnnydist                [johnnydep.lib] dist=pytz>=2017.3 parent=pandas
2021-06-09 11:01:23 [info     ] init johnnydist                [johnnydep.lib] dist=six>=1.5 parent=python-dateutil>=2.7.3
name                        summary
--------------------------  -----------------------------------------------------------------------
pandas                      Powerful data structures for data analysis, time series, and statistics
├── numpy>=1.16.5           NumPy is the fundamental package for array computing with Python.
├── python-dateutil>=2.7.3  Extensions to the standard Python datetime module
│   └── six>=1.5            Python 2 and 3 compatibility utilities
└── pytz>=2017.3            World timezone definitions, modern and historical
Florian
  • 874
  • 1
  • 8
  • 17
3

Just an addendum on how to use johnnydep.

  1. If you want to have the dependencies in requirements.txt format:
johnnydep pandas --output-format=pinned
pandas==1.4.1
numpy==1.22.3
python-dateutil==2.8.2
pytz==2021.3
six==1.16.0

Above list will be written to stdout while the informational messages during collection are written to stderr (if you want to capture the output using bash or subprocess).

  1. Calling it from Python instead of the CLI:
import sys, johnnydep.cli
sys.argv = ["", "pandas"]
johnnydep.cli.main()
xjcl
  • 12,848
  • 6
  • 67
  • 89
  • Thanks for pointing that out. I was having troubles with appending the standard "human" format to a file because of character conversions. Your solution worked though – RexBarker Jul 14 '22 at 13:08
2

I think these answers are outdated and there's a better solution now. Original post here:

To generate requirements.txt for packages listed in install_requires in your setup.cfg or setup.py, you would need to install pip-tools.

pip install pip-tools
pip-compile

To generate a requirements.txt file that includes packages specified under extras_requires for tests and dev:

pip-compile --extra tests --extra devrequirements.txt file with packages listed under

Furthermore, you can also use requirements.in file instead of setup.cfg or setup.py to list your requirements.

pip-compile requirements.in
rrlamichhane
  • 1,435
  • 2
  • 18
  • 34
1

As an update to @Jmills answer, for newer pip versions that support the --dry-run option:

#!/bin/sh

PACKAGE=$1
pip install $PACKAGE --dry-run --ignore-installed  \
| grep Collecting \
| cut -d' ' -f2 \
| sed -E 's/([><=!]=|[><]).*//g'
Amnon
  • 2,708
  • 2
  • 22
  • 21
  • This works, but this still downloads the packages. I have to run `pip cache purge` afterwards. I wish `--dry-run` would not actually download packages. – Al Conrad Jun 23 '23 at 15:15
0

The command pip install <package> --download <path> should be used, as mentioned in comments by @radtek, since as of 7.0.0 (2015-05-21), --no-install is removed from pip. This will download the dependencies needed into <path>.

toine
  • 1,946
  • 18
  • 24
  • 12
    Ridiculously, **`--download` has been deprecated as well.** The canonical command _now_ appears to be `pip download -d /tmp --no-binary :all:` as [suggested](https://stackoverflow.com/a/38531949/2809027) by [The Card Cheat](https://stackoverflow.com/users/1210112/the-card-cheat). – Cecil Curry Aug 09 '16 at 05:03
-1

Another option is to use a helper script similar to this one which uses the pip.req.parse_requirements API to parse requirements.txt files and a distutils.core.setup replacement to parse setup.py files.

sschuberth
  • 28,386
  • 6
  • 101
  • 146