Open Gallaecio opened 3 years ago
Another workaround is to set h2>=3.2.0
as a constraint instead. This is because the resolver’s current logic to “prefer” a chosen package version is by 1. whether the package is user-specified, and 2. alphabetically, so h2
is preferred and twisted
backtracks in this case. By specifying h2
as a constraint, twisted
will be preferred.
I have some improvements in mind that may help with this[1], but there’s no actual code yet and will have to wait until 21.2 (at least). I’ll try to remember to ping here when I have something to test.
[1]: Basically adding an additional sort criteria to prefer keeping user-specified packages that are not also transitive requirements of other packages, so twisted
can be preferred over h1
because h1
is also depended by twisted
.
Looking at the logic, untimately this is where things go against your expectation:
WARNING: twisted 16.3.2 does not provide the extra 'http2'
But pip is historically very lenient about extras and would happily drop any invalid values. We could potentially enforce that instead, but that would affect a lot of people since there are packages out there (mostly old and less updated stuff) with invalid extras, and it would be extremely frustrating for their users if pip start failing to install those.
I guess a middle-ground solution would be to enforce extras supplied by the user, i.e. in your case twisted
would fail to install because your supplied http2
extra cannot be installed. But if a package transitively depends on foo[a]
and extra a
doesn’t actually exist on foo
, that extra will continue to be dropped, since this is outside the user’s control—unless the user also specifies foo[a]
from the command line, in which case pip should error out.
The problem is, this is already pretty not trivial to explain, and the implementation would be even less straightforward. But I guess that is something doable (and hopefully reasonable). As always, contributions are always welcomed.
[enforcing valid extras] would affect a lot of people since there are packages out there (mostly old and less updated stuff) with invalid extras. […]. I guess a middle-ground solution would be to enforce extras supplied by the user […]
What about enforcing extras if they are found to be valid? For example, when pip downloads the latest valid Twisted version here, and finds that extra is defined in it, it could as a consequence consider that extra a valid extra (i.e. same as user-defined) and stop backtracking if a version is found that does not define it.
Just a thought, though. I realize this may make the implementation even more complex, and maybe create other problems.
It’s difficult to qualify what is “found to be valid” though. Say a package foo
was published with an invalid extra bar[ext]
, but that ext
extra was added to a later version of bar
. Does ext
count as a valid bar
extra now when you install foo
? Does the answer change depending on whether the later bar
version is installable on the target machine?
The most difficult thing about designing dependency resolution logic is the same dependency specification may change meaning over time. Therefore it is usually a good idea to distinguish between user input and transitive dependencies, because the former is guaranteed to express an accurate user intent, which the latter may not.
(I found this issue while searching before filing a feature request.)
The core of what @Gallaecio is asking for makes a lot of sense to me. Currently, if I say: pip install foo[bar]
and the "bar"
extra does not exist, a warning is printed out (yay!) but then immediately gets pushed out of the way while a bunch of things install ... at first glance, this appears successful!
But what actually happened is that I get foo
installed .. which isn't the foo[bar]
I asked for.
I think pip
should error out in this case (i.e. the "warning" becomes an error). Ideally it would also print out which extras are available for the package you asked for. That is, something like: The "bar" extra is not available in package "foo", which has the following extras: quux, baz, zinga
(I realize the above doesn't necessarily help with the wider issue of what to do about extras declared as dependencies or transitive dependencies -- but I think the CLI user-experience would be better for at least "command-line-specified installation targets")
Maybe this makes sense as a separate feature bug, but it seems highly related to this one...
To add some color to this discussion, I'm working on a build/test system that aims to move a lot of the project configuration into tooling and infrastructure. It assumes that every project under test is going to declare any test dependencies under the test
extra and installs them when setting up to run tests.
Some projects, however, will have no project-specific test dependencies. In this case, the project gets built without any Provides-Extra: test
in the metadata. I'm leaning toward having every project supply the test
extra even when there are no dependencies, to suppress the warning under the current pip install
technique but also satisfy a future where installers are more strict about installing them, such as this issue is proposing.
If you have any concerns about that approach, please comment in https://github.com/coherent-oss/coherent.test/issues/5.
Reproducible with pip 21.0.1 and
master
(af60df514397b8f63182e77ea84aaafa2d5f9c93).What did you want to do?
Install the latest version of
Twisted[http2]
(which as of Twisted 21.2.0 requiresh2 >=3.0, <4.0
), while enforcing the requirementh2>=3.2.0
:Output
What the command does (wrong, I believe) is to:
Twisted
package without thehttp2
extra even defined. I believe the command should rather fail before doing that. If I askTwisted[http2]
to be installed, I should not getTwisted
installed instead.Twisted
and the previous version ofh2
are compatible. This may be related to https://github.com/pypa/pip/issues/9187 or https://github.com/pypa/pip/issues/9215 .Workaround
The desired results are obtained if the upper
h2
version limit fromTwisted[http2]
,<4
, is copied into the command-line levelh2
requirement:Additional information
Based on https://github.com/scrapy/scrapy/pull/5066