Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support selective ignoring of package dependencies #1645

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

skieffer
Copy link

@skieffer skieffer commented Jun 28, 2022

Greetings, and thanks for this great library.

This is another PR addressing the "exclude-type" operations discussed in #333, and it is complementary to #1509.

#1509 lets you say: "After resolving the whole dependency graph, delete these nodes out of it."

This PR lets you say two different things:

  1. "I want package A without requiring any of its dependencies." (cf. pip's --no-deps)

  2. "The authors of package A made it depend on B and C. But when I use A I don't need C. So treat A as if it didn't depend on C."

Usage looks like:

pip-compile --cut-deps A

or

pip-compile --cut-deps A:C

respectively.

Critically, we are not deleting nodes from the dependency graph, we are deleting edges, and refusing to follow them.

This means we are happy for some other package to bring a node into the graph, should that ever happen. So with this graph,

             A      (X)
           /   \   /
          B      C
         / \    / \
        D   E  F   G

as long as I depend only on A, I want pip-compile --cut-deps A:C to keep C, F, G out of my installation.
However, if some day I add X to my project, then I'm happy for C, F, G to come in.

Contributor checklist
  • Provided the tests for the changes.
  • Assure PR title is short, clear, and good to be included in the user-oriented changelog
Maintainer checklist
  • Assure one of these labels is present: backwards incompatible, feature, enhancement, deprecation, bug, dependency, docs or skip-changelog as they determine changelog listing.
  • Assign the PR to an existing or new milestone for the target version (following Semantic Versioning).

@skieffer
Copy link
Author

skieffer commented Jul 3, 2022

Rebased on 6.8.0. The --cut-deps feature is now only in the LegacyResolver.

@skieffer skieffer marked this pull request as ready for review July 3, 2022 11:27
@IanTayler IanTayler mentioned this pull request Jul 6, 2022
@atugushev
Copy link
Member

atugushev commented Dec 13, 2022

Just out of curiosity, what's your real-world use case for this feature?

Rebased on 6.8.0. The --cut-deps feature is now only in the LegacyResolver.

Note the legacy resolver is deprecated and will be removed soon, which is why we don't accept new features related to it.

@skieffer
Copy link
Author

Thanks for your interest. My real-world use case is the gremlinpython package. It declares a dependency on aiohttp and nest_asyncio, but there are ways to use it that don't require these at all (or their many recursive requirements).

So when I install gremlinpython, I'd like to cut the dependency edges

gremlinpython --> aiohttp
gremlinpython --> nest_asyncio

meaning, "I don't want aiohttp or nest_asyncio today. Tomorrow, I may need them for some other reason. Until then, I don't want them."

  • I noted a similar case here.
  • My case is discussed here.

Basically, package maintaners sometimes fail to use extras_require. As package consumers, we should still have options to exclude dependencies that are inessential for our present use case, without excluding them from future use-cases.

akikoskinen added a commit to City-of-Helsinki/open-city-profile that referenced this pull request Apr 11, 2023
Move python-jose dependency to requirements.in, as it's not just a
development dependency. It's needed by the actual server too; via
django-helusers, but still.

Use the `cryptography` backend with python-jose, which is the
recommended choice. Python-jose depends on `ecdsa`, `pyasn1` and `rsa`
packages, but it doesn't need them when the `cryptography` backend is
used. Those packages are excluded from the requirements.txt file by
using --unsafe-package arguments with pip-compile. This works for now,
since python-jose is the ONLY package that depends on those packages. If
any other package update needs any of those other dependencies, then
they need to be allwed again. There is a proposal to pip-tools [1] to
provide a better tool for this kind of use case, but it hasn't been
accepted.

In order to not get those unnecessary dependencies installed anyways,
the --no-deps argument needs to be given to `pip`. This was added to
Dockerfile.

[1] jazzband/pip-tools#1645
akikoskinen added a commit to City-of-Helsinki/open-city-profile that referenced this pull request Apr 11, 2023
Move python-jose dependency to requirements.in, as it's not just a
development dependency. It's needed by the actual server too; via
django-helusers, but still.

Use the `cryptography` backend with python-jose, which is the
recommended choice. Python-jose depends on `ecdsa`, `pyasn1` and `rsa`
packages, but it doesn't need them when the `cryptography` backend is
used. Those packages are excluded from the requirements.txt file by
using --unsafe-package arguments with pip-compile. This works for now,
since python-jose is the ONLY package that depends on those packages. If
any other package update needs any of those other dependencies, then
they need to be allwed again. There is a proposal to pip-tools [1] to
provide a better tool for this kind of use case, but it hasn't been
accepted.

In order to not get those unnecessary dependencies installed anyways,
the --no-deps argument needs to be given to `pip`. This was added to
Dockerfile.

[1] jazzband/pip-tools#1645
@ntjess
Copy link

ntjess commented Dec 22, 2024

Here's another use-case:

Consider a package that lists matplotlib as a dependency, but I never use the functions that rely on it. To cut down on my production size, I'd like to ignore matplotlib and everything that only matplotlib depends on.

Currently, #1509 would force me to mark every single subdependency of matplotlib as also unsafe (e.g. kiwisolver, cycling, pyparser, ... in this example) -- but only if they don't appear as dependencies of the packages I care about.

It also requires me to continually check whether matplotlib is adding new dependencies in new versions as I upgrade my pins.

Ideally, I can just --cut-deps matplotlib and not worry about it.

@webknjaz
Copy link
Member

Looks like these use-cases are relying on the pip-compile output being used as pip requirement files. I've always seen them as rather pip constraints to be used as pip install -r deps.in -c constraints.txt (#2051).

Perhaps, for this use-case, a new output type/method is needed. Since the .in+.txt file pairs are kinda tightly coupled in their semantics. .txt is always expected to pin down the entire transitive tree of what's in .in.

UX-wise, I think it needs to be some setting for distinguishing what the input is (a regular list of direct deps vs. a patched one).

Perhaps, one day it could be paired with #2124.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants