Skip to main content

Lightweight pip dependency resolver with deptree preview functionality based on the PubGrub algorithm

Project description

pipgrip

build codecov pypi Version python downloads black

pipgrip is a lightweight pip dependency resolver with deptree preview functionality based on the PubGrub algorithm, which is also used by poetry. For one or more PEP 508 dependency specifications, pipgrip recursively fetches/builds the Python wheels necessary for version solving, and optionally renders the full resulting dependency tree.

pipgrip vs. poetry

poetry offers package management with dependency resolution, essentially replacing pip/setuptools. This means that poetry packages don't contain setup.py, and hence are not compatible with pip install -e: poetry projects would have to be converted to setuptools-based projects with e.g. dephell. To avoid such hassle, pipgrip only requires the selected package(s) + dependencies to be available to pip in the ususal way.

pipgrip vs. pipdeptree

For offline usage, pipdeptree can inspect the current environment and show how the currently installed packages relate to each other. This however requires the packages to be pip-installed, and (despite warnings about e.g. cyclic dependencies) offers no form of dependency resolution since it's only based on the (single) package versions installed in the environment. Such shortcomings are avoided when using pipgrip, since packages don't need to be installed and all versions available to pip are considered.

Installation

This pure-Python, OS independent package is available on PyPI:

pip install pipgrip

Usage

This package can be used to:

  • Render an exhaustive dependency tree for any given pip-compatible package(s) with --tree
  • Alleviate Python dependency hell by resolving the latest viable combination of required packages
  • Avoid bugs by running pipgrip as a stage in CI pipelines
  • Detect version conflicts for given constraints and give human readable feedback about it
  • Warn for cyclic dependencies in local projects [and install them anyway]:
    • pipgrip -v --tree . [--install -e]
  • Install complex packages without worries using:
    • pipgrip --install aiobotocore[awscli]
    • pip install -U --no-deps `pipgrip --pipe aiobotocore[awscli]`
  • Generate a lockfile with a complete working set of dependencies for worriless installs:
    • pipgrip --lock --install --tree -v aiobotocore[awscli]
    • pipgrip --lock -tree aiobotocore[awscli] && pip install -U --no-deps -r ./pipgrip.lock
    • pipgrip aiobotocore[awscli] | pip install -U --no-deps -r /dev/stdin
  • Combine dependency trees of multiple packages into one unified set of pinned packages:
    • pipgrip --lock --install --tree -v .[boto3] s3transfer==0.2.1

See also known caveats.

$ pipgrip --help

Usage: pipgrip [OPTIONS] [DEPENDENCIES]...

  pipgrip is a lightweight pip dependency resolver with deptree preview
  functionality based on the PubGrub algorithm, which is also used by poetry.
  For one or more PEP 508 dependency specifications, pipgrip recursively
  fetches/builds the Python wheels necessary for version solving, and optionally
  renders the full resulting dependency tree.

Options:
  --install                     Install full dependency tree after resolving.
  -e, --editable                Install a project in editable mode.
  -r, --requirements-file FILE  Install from the given requirements file. This
                                option can be used multiple times.
  --lock                        Write out pins to './pipgrip.lock'.
  --pipe                        Output space-separated pins instead of newline-
                                separated pins.
  --json                        Output pins as json dict instead of newline-
                                separated pins.
  --tree                        Output human readable dependency tree (top-down).
  --reversed-tree               Output human readable dependency tree (bottom-up).
  --max-depth INTEGER           Maximum tree rendering depth (defaults to -1).
  --cache-dir DIRECTORY         Use a custom cache dir.
  --no-cache-dir                Disable pip cache for the wheels downloaded by
                                pipper. Overrides --cache-dir.
  --index-url TEXT              Base URL of the Python Package Index (default
                                https://pypi.org/simple).
  --extra_index-url TEXT        Extra URLs of package indexes to use in addition
                                to --index-url.
  --pre                         Include pre-release and development versions. By
                                default, pip only finds stable versions.
  -v, --verbose                 Control verbosity: -v will print cyclic
                                dependencies (WARNING), -vv will show solving
                                decisions (INFO), -vvv for development (DEBUG).
  -h, --help                    Show this message and exit.

Dependency trees

Exhaustive dependency trees without the need to install any packages (at most build some wheels).

$ pipgrip --tree pipgrip

pipgrip (0.2.0)
├── anytree (2.8.0)
│   └── six>=1.9.0 (1.14.0)
├── click (7.0)
├── packaging>=17 (20.1)
│   ├── pyparsing>=2.0.2 (2.4.6)
│   └── six (1.14.0)
├── pkginfo>=1.4.2 (1.5.0.1)
├── setuptools>=38.3 (45.1.0)
└── wheel (0.33.6)

Lockfile generation

Using the --lock option, resolved (pinned) dependencies are additionally written to ./pipgrip.lock.

$ pipgrip --tree --lock botocore==1.13.48 'boto3>=1.10,<1.10.50'

botocore==1.13.48 (1.13.48)
├── docutils<0.16,>=0.10 (0.15.2)
├── jmespath<1.0.0,>=0.7.1 (0.9.5)
├── python-dateutil<3.0.0,>=2.1 (2.8.1)
│   └── six>=1.5 (1.14.0)
└── urllib3<1.26,>=1.20 (1.25.8)
boto3<1.10.50,>=1.10 (1.10.48)
├── botocore<1.14.0,>=1.13.48 (1.13.48)
│   ├── docutils<0.16,>=0.10 (0.15.2)
│   ├── jmespath<1.0.0,>=0.7.1 (0.9.5)
│   ├── python-dateutil<3.0.0,>=2.1 (2.8.1)
│   │   └── six>=1.5 (1.14.0)
│   └── urllib3<1.26,>=1.20 (1.25.8)
├── jmespath<1.0.0,>=0.7.1 (0.9.5)
└── s3transfer<0.3.0,>=0.2.0 (0.2.1)
    └── botocore<2.0.0,>=1.12.36 (1.13.48)
        ├── docutils<0.16,>=0.10 (0.15.2)
        ├── jmespath<1.0.0,>=0.7.1 (0.9.5)
        ├── python-dateutil<3.0.0,>=2.1 (2.8.1)
        │   └── six>=1.5 (1.14.0)
        └── urllib3<1.26,>=1.20 (1.25.8)

$ cat ./pipgrip.lock

botocore==1.13.48
docutils==0.15.2
jmespath==0.9.5
python-dateutil==2.8.1
six==1.14.0
urllib3==1.25.8
boto3==1.10.48
s3transfer==0.2.1

NOTE: Since the selected botocore version is older than the one required by the recent versions of boto3, all boto3 versions will be checked for compatibility with botocore==1.12.42.

Version conflicts

If version conflicts exist for the given (ranges of) package version(s), a verbose explanation is raised.

$ pipgrip auto-sklearn~=0.6 dragnet==2.0.4

Error: Because dragnet (2.0.4) depends on scikit-learn (>=0.15.2,<0.21.0)
 and auto-sklearn (0.6.0) depends on scikit-learn (<0.22,>=0.21.0), dragnet (2.0.4) is incompatible with auto-sklearn (0.6.0).
And because no versions of auto-sklearn match >0.6.0,<1.0, dragnet (2.0.4) is incompatible with auto-sklearn (>=0.6.0,<1.0).
So, because root depends on both auto-sklearn (~=0.6) and dragnet (==2.0.4), version solving failed.

NOTE: If older versions of auto-sklearn are allowed, PubGrub will try all acceptable versions of auto-sklearn. In this case, auto-sklearn==0.5.2 requires scikit-learn (<0.20,>=0.19), making it compatible with dragnet==2.0.4.

Cyclic dependencies

If cyclic dependencies are found, it is noted in the resulting tree.

$ pipgrip --tree -v keras==2.2.2

WARNING: Cyclic dependency found: keras depends on keras-applications and vice versa.
WARNING: Cyclic dependency found: keras depends on keras-preprocessing and vice versa.
keras==2.2.2 (2.2.2)
├── h5py (2.10.0)
│   ├── numpy>=1.7 (1.18.1)
│   └── six (1.14.0)
├── keras-applications==1.0.4 (1.0.4)
│   ├── h5py (2.10.0)
│   │   ├── numpy>=1.7 (1.18.1)
│   │   └── six (1.14.0)
│   ├── keras>=2.1.6 (2.2.2, cyclic)
│   └── numpy>=1.9.1 (1.18.1)
├── keras-preprocessing==1.0.2 (1.0.2)
│   ├── keras>=2.1.6 (2.2.2, cyclic)
│   ├── numpy>=1.9.1 (1.18.1)
│   ├── scipy>=0.14 (1.4.1)
│   │   └── numpy>=1.13.3 (1.18.1)
│   └── six>=1.9.0 (1.14.0)
├── numpy>=1.9.1 (1.18.1)
├── pyyaml (5.3)
├── scipy>=0.14 (1.4.1)
│   └── numpy>=1.13.3 (1.18.1)
└── six>=1.9.0 (1.14.0)

Known caveats

  • pip install -U `pipgrip --pipe package` without --no-deps is unsafe while pip doesn't yet have a built-in dependency resolver, and leaves room for interpretation by pip
  • Package names are canonicalised in wheel metadata, resulting in e.g. path.py -> path-py and keras_preprocessing -> keras-preprocessing in output
  • VCS Support isn't implemented yet
  • --reversed-tree isn't implemented yet
  • Since pip install -r does not accept . as requirement, it is omitted from lockfiles, so --install or --pipe should be used when installing local projects
  • The equivalent of e.g. pip install ../aiobotocore[boto3] is not yet implemented. However, e.g. pipgrip --install .[boto3] is allowed.

Development

gitmoji pre-commit

Create a virtual environment and get ready to develop:

make install

This make-command is equivalent to the following steps:

Install pre-commit and other continous integration dependencies in order to make commits and run tests.

pip install -r requirements/ci.txt
pre-commit install

With requirements installed, make lint and make test can now be run. There is also make clean, and make all which runs all three.

To import the package in the python environment, install the package (-e for editable installation, upon import, python will read directly from the repository).

pip install -e .

See also


BSD 3-Clause License

Copyright (c) 2020, ddelange
All rights reserved.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pipgrip-0.2.0.tar.gz (44.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pipgrip-0.2.0-py2.py3-none-any.whl (49.4 kB view details)

Uploaded Python 2Python 3

File details

Details for the file pipgrip-0.2.0.tar.gz.

File metadata

  • Download URL: pipgrip-0.2.0.tar.gz
  • Upload date:
  • Size: 44.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.6

File hashes

Hashes for pipgrip-0.2.0.tar.gz
Algorithm Hash digest
SHA256 51d96c6726263e7c1aba963f9032c8aa6ffbf0d424d1fafe05384e98377d4a85
MD5 decb55da6dc25e2da6347e1d93d42b14
BLAKE2b-256 29f69b634d5c7e055cba169f5d387a224c555534513fed196dd3d75142bdf736

See more details on using hashes here.

File details

Details for the file pipgrip-0.2.0-py2.py3-none-any.whl.

File metadata

  • Download URL: pipgrip-0.2.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 49.4 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.7.6

File hashes

Hashes for pipgrip-0.2.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 b34fae70f7df971120dc343b90ea70508c9f24ff7642de5fc2cdd418f1029d37
MD5 bd66715c904582bc68454c0bc6ee6216
BLAKE2b-256 88f8fccdd9a3a78818c587743c598946f0935da246203ce11ac5674f27459bd0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page