Open DEKHTIARJonathan opened 4 years ago
Thank you for the thorough report!
It looks like there are a few issues here:
In the conflict checking that occurs when using the old resolver, which leads to:
ERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts.
We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.
test-pkg 1.0.0 requires is-sorted==0.0.1; extra != "env_a" and extra != "env_b", but you'll have is-sorted 0.0.2 which is incompatible.
pip doesn't seem to take extras into account.
pip doesn't normalize extras. When trying to reproduce with your current script (which has extra != "env_A" and extra != "env_B"
) I did not get the Ignoring is-sorted...
message. I'm not sure if this is something we should be doing.
Even with the script updated to use env_a
and env_b
, pip isn't picking is-sorted 0.0.2
even though it is available as a wheel, matches the platform, and none of the other projects seem to have a dependency like is-sorted==0.0.1
I don't think the last issue is related to extras, because the line
Ignoring is-sorted: markers 'extra != "env_a" and extra != "env_b"' don't match your environment
indicates that we ignored that dependency. Technically picking is-sorted 0.0.1
is valid because the matching lines have is-sorted<0.1,>=0.0.1
, but we should be preferring the later version.
2. pip doesn't normalize extras. When trying to reproduce with your current script (which has
extra != "env_A" and extra != "env_B"
) I did not get theIgnoring is-sorted...
message. I'm not sure if this is something we should be doing.
I remember having a discussion with someone about this a while ago. setuptools
does not normalise extras when building distributions, and pip either when installing them. But pkg_resources
does when checking dependencies, and with entirely undocumented and unspecified rules (AFAIK). This is a much larger problem than pip’s dependency resolver.
@uranusjr as far as I can tell, the situation we get into is, given dist/test_pkg-1.0.0-py3-none-any.whl[env_a]
:
LinkCandidate
for e.g. dist/test_pkg-1.0.0-py3-none-any.whl
ExtrasCandidate
that represents dist/test_pkg-1.0.0-py3-none-any.whl[env_a]
PipProvider.find_matches
gets invoked by resolvelib, it is with a criterion constructed from all of the candidates' dependencies. Since we don't filter LinkCandidate
dependencies, it includes the one with ==0.0.1
. We merge that with the other criteria here and pass it down into PackageFinder, which only yields links with ==0.0.1
because that's the most specificSo we should probably exclude dependencies with extras around here?
There are more to this, since the provider currently assumes an extra-ed requirement automatically has all the same dependencies as its extra-less counterpart. But yes, the code you linked would be one of the places that need to change.
Tagging @pfmoore since I imagine you’d have much feeling about this 😉
Glad that you all managed to reproduce and locate the issue. Let me know if I can help 👍
Another more personal note: I am hesitant to classify this as a pip bug. Although the described usage is well within the specification, I suspect it is against the intention of the extras feature, based on my interaction with people designing it. If that’s the case, this would classify better as a feature request instead, and the resolution may be that we need to fix the specification to disallow the usage, instead of introducing the feature to support it.
@uranusjr i'm not sure to understand what you imply. It is "well within the specifications" but it is not a bug? How could this be? It's either something that should work or something that shouldn't work. If it's within the specs then it should be considered a bug IMHO.
There is no other way to make a "default" extra require if no extra is specified (which is eventually what I try to do)... We could go around this limitation in this specific case if we could register the None extra environment. But it's impossible...
And even if that was doable it technically doesn't fix all cases that this issue illustrates.
The extras feature is carried over from the pre-specification era of Python packaging, and specified after the fact. It is important to consider the “spirit of the law” when dealing with discrepancies here, since the specification is as suspect to bugs as the implementation.
The lack of a way to define a “default extra” is actually a long-standing problem in Python packaging. This would not be the case if the extras feature was designed initially with this usage in mind. Therefore, the fact that specification creators are still looking for a way to specify default extras indicates that the extras feature was, in fact, not designed to support this usage. The solution may be that we should design a way to specify default extras (which is generally agreed to be needed), instead of stretching a feature beyond its intended purpose simply because the specification allows it.
It's been 3 years (in one month) that this issue is opened : https://github.com/pypa/setuptools/issues/1139
Do you guys have any idea when you plan on coming up with a fix? I understand your point, but saying "it's important to consider the spirit of the law" and not providing any solution for 3 years isn't something that helps to accept that aforesaid "spirit".
Pip dependency resolver is currently being refactored and rewritten. I think it's a great time to address the question in whatever way you feel comfortable. Or at the very least provide a workaround and unblock everyone...
Please understand that no-one in either pip, setuptools, or Python packaging in general are obliged to provide functionalities that you need. The lack of movement indicates that people who are willing to do things (mostly without return, I want to add) do no care enough about it, and those want the feature do no care enough to actually get involved in the work. Feel free to help out if you do care enough to, but simply asking people to do things they don’t want wouldn’t get you very far, I’m afraid.
@uranusjr sorry if I was misunderstood, to quote myself
"Glad that you all managed to reproduce and locate the issue. Let me know if I can help 👍"
I'm all for getting my hands dirty and pushing/implementing this. I already contributes to numerous open source projects and would be glad to join PyPA devs. I may need some directions in how you guys you want to approach the problem. If I understand the situation correctly, it's less a technical problem and more agreeing on how to address the issue.
Do you have a preferred mean of communication within PyPA? A slack or Discord maybe? Please let me know how I can get in touch with the right people and agree on how you all want the issue to be addressed. It may require writing a PEP. I'm fairly new to all of this, so any guidance is appreciated.
I think the misunderstanding is the communication channel is not as well-known as I anticipated, sorry. PyPA does have multiple communication channels, as listed on pypa.io. The Discourse forum is the most active these days, but feel free to choose any one you feel the most comfortable with.
Sweet. I'm all to use the forum, that way the discussion is public and easily readable/accessible by anyone.
Do you know if there's any on going thread on this topic (I try to avoid creating a duplicate)?
I would appreciate if you could send me an email : contact@jonathandekhtiar.eu that way if I have any question I can reach out to you 😊 Thanks buddy 👍
@uranusjr @chrahunt https://discuss.python.org/t/adding-a-default-extra-require-environment/4898
Chris's comment (https://github.com/pypa/pip/issues/8686#issuecomment-667757703) does sounds like a reasonable summary and I don't think we came up with any concensus regarding what to do toward changing behaviors around this area (beyond it's broken and needs fixing).
In other words, I can't figure out what we've decided to do to be able to close this issue. :)
We hit this in homeassistant
upgrades and have no idea what to do yet :)
https://community.home-assistant.io/t/upgrade-ha-0-114-2-from-0-107-7/219412
Hi, I am getting the following errors: ERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts. We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.
(tensorflow) C:\tensorflow\models\research\object_detection>python train.py --train_dir=training/ --pipeline_config_path=training/faster_rcnn_inception_v2_pets.config --logtostderr
Traceback (most recent call last):
File "train.py", line 54, in
@Jayanth1812 This is a Tensorflow issue, not related to pip.
I tried installing Tensorflow of different version, but it doesn't work for me. So, I re-installed to tensorflow-2.0. While installing I am getting error like this: ERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts. We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default. tf-models-official 2.3.0 requires tensorflow>=2.3.0, but you'll have tensorflow 2.0 which is incompatible.
If I install Tensorflow 2.3.0 then also it is not supporting, What should I do now?
@uranusjr Which version of tensor flow should I install?
@Jayanth1812 See here for some advice. For anything more detailed, you'll need to ask the Tensorflow project, as the pip developers don't have any information about why tensorflow packages have the dependencies that they claim.
@Jayanth1812 Please stop spamming this issue, you need to find a tensorflow support list to get help.
Hi, I ran into a similar problem, which can be described with a simplified example from the starting message.
Let's have a setup.py
like this:
from setuptools import setup
# Add a dependency on a package, which must be excluded if the extra is specified
install_requires = ["is-sorted; extra != 'env_a'"]
extras_require = {
"env_a": [] # just list an extra. Can have any deps, but it's not important.
}
setup(
name='test_pkg',
version='1.0.0',
install_requires=install_requires,
extras_require=extras_require,
)
Then we create a distribution (since we can't just call pip install .[env_a]
, which will fail)
python setup.py bdist_wheel
And try to install it:
$ pip list
Package Version
---------- -------
pip 21.2.3
setuptools 57.4.0
wheel 0.37.0
$ pip install dist/test_pkg-1.0.0-py3-none-any.whl[env_a]
Processing ./dist/test_pkg-1.0.0-py3-none-any.whl
Ignoring is-sorted: markers 'extra != "env_a"' don't match your environment
Collecting is-sorted==0.0.1
Using cached is_sorted-0.0.1-py3-none-any.whl (2.8 kB)
Installing collected packages: is-sorted, test-pkg
Successfully installed is-sorted-0.0.1 test-pkg-1.0.0
$ pip list
Package Version
---------- -------
is-sorted 0.0.1
pip 21.2.3
setuptools 57.4.0
test-pkg 1.0.0
wheel 0.37.0
And we get the ignored package installed regardless of [env_a]
being specified.
In my case, the package to be ignored is opencv-python-headless
, which might be replaced by regular opencv-python
in an extra.
@zhiltsov-max Please respond (and try to push forward the discussion) in https://discuss.python.org/t/4898. This is a specification issue (PEP 440 does not properly specify what this should be handled) and not something we can just fix in pip.
@uranusjr, thanks for replying! I've seen that discussion almost a year ago, when I first bumped into variable dependencies, but I workarounded the problem with an environment variable and --no-binary
. From what I've seen, in the discussion few approaches were proposed, somebody suggested implementations, core team members reacted and, apparently, no actions were taken. The topic starter and participants have already done a big work in making the idea of default extra real, and I appreciate it, but I'm not sure how can I help with pushing it forward. I'm open for participating.
The problem I reported looks just like a bug, because pip
correctly reports an ignored dependency, and then installs it. If dependencies have conflicts between extras or base, they will just be installed all together.
Unfortunately this is not pip bug, but a design issue. The reason pip does not do what you want is not because pip interprets extra != "env_a"
incorrectly, but that expression does not mean what you think it does (if it does, pip would have done what you want).
When you install a package with extras, say foo[a,b]
, you are actually requesting extras, not an extra singular. The way this is broken down, as specified in PEP 508, is to break a package’s dependencies into parts: those included when no extras are specified, those included only if you want the a
extra, and those included only if you want the b
extra. When foo[a,b]
is requested, all three are combined together.
Now if you extend the concept to when only one extra is requested, say foo[a]
, you are still not requesting one extra, but a list of extras of length 1, and the package’s dependencies are broken into two: those included when no extras are specified, and those only if you want the a
extra. With this design, bar; extra != 'a'
goes into the former group—because when no extras are requested, the expression evaluates to True. So when those parts are installed, bar
will still end up in the environment.
I hope this clears up why the current PEP 508 markers is confusing in this aspect and why pip seems to interpret it wrong. Again, pip actually interprets it correctly as designed; its the design that gives extra != value
a semantic meaning that you do not expect (and that semantic meaning means there’s currently no way to achieve what you want). So this should not be fixed by pip because pip should not deviate from the standard; you need to fix the standard.
I have found a dependency resolving issue in PIP, here is how to reproduce. Nor the "old" or the "2020-resolver" is able to fix the issue. However they both fails in different ways.
This is a very problematic for us. When do you think it could be resolved ?
Environment:
Script to reproduce
What shall be expected
is-sorted==0.0.1
env_a
:random-string
is-sorted>=0.0.1,<0.1
env_b
:get-random
is-sorted>=0.0.1,<0.1
env_a && env_b
:random-string
# fromenv_a
get-random
# fromenv_b
is-sorted>=0.0.1,<0.1
What happens in practice ?
0. Let's build the wheel:
python setup.py bdist_wheel
If we look at the file
METADATA
, everything seems OK:1. Install with NO extra require
Conclusion: Everything is good.
2. Install with
env_a
extra requireConclusion: A scary "red" warning for no reason:
is-sorted-0.0.2 random-string-1.0 test-pkg-1.0.0
shall be the correct set of dependencies3. Install with
env_b
extra requireConclusion: A scary "red" warning for no reason:
get-random-0.1.4 is-sorted-0.0.2 test-pkg-1.0.0
shall be the correct set of dependencies4. Install with
env_a && env_b
extra requireConclusion: A scary "red" warning for no reason:
get-random-0.1.4 is-sorted-0.0.2 random-string-1.0 test-pkg-1.0.0
shall be the correct set of dependenciesHow about with
--use-feature=2020-resolver
?Now it's even worse, we don't have a warning anymore because the dependency resolving is wrong.
1. Install with NO extra require and
--use-feature=2020-resolver
Conclusion: Everything is good.
2. Install with
env_a
extra require and--use-feature=2020-resolver
Conclusion: No error anymore, however it installs
is-sorted-0.0.1
and should install:is-sorted-0.0.2
3. Install with
env_b
extra require and--use-feature=2020-resolver
Conclusion: No error anymore, however it installs
is-sorted-0.0.1
and should install:is-sorted-0.0.2
4. Install with
env_a && env_b
extra require and--use-feature=2020-resolver
:Conclusion: No error anymore, however it installs
is-sorted-0.0.1
and should install:is-sorted-0.0.2