pypa / pip

The Python package installer
https://pip.pypa.io/
MIT License
9.51k stars 3.02k forks source link

Alpha resolver fails to install on conflict when current resolver would permit it #8339

Open timmc-edx opened 4 years ago

timmc-edx commented 4 years ago

I found that in a case when the regular resolver would complain about a package incompatibility but install it anyway, the alpha resolver errored out and stopped without installing anything.

It is not clear if this is a bug in the current resolver, the new one, both, or neither. :-)

Inputs

Fresh Python 3.5 virtualenv each time with pip 20.2b1 installed on Ubuntu Linux 18.04.4.

Contents of requirements file:

will==0.9.3
boto==2.43.0
PyYAML==3.12
ipython==4.0.3
python-jenkins==0.4.14
pyparsing==2.0.7
pytz==2017.2
yagocd==0.4.4

Old resolver

Output of pip install -r requirements.txt:

Processing /home/timmc/.cache/pip/wheels/27/03/9b/3e8a700c68ffe02c4fe9eec89b1a09fae23aaaedcf68b53353/will-0.9.3-py3-none-any.whl
Collecting boto==2.43.0
  Using cached boto-2.43.0-py2.py3-none-any.whl (1.3 MB)
Processing /home/timmc/.cache/pip/wheels/36/e8/a2/931a0f5060f69996e1d78a0b0ae235c042fee2a767177393bc/PyYAML-3.12-cp35-cp35m-linux_x86_64.whl
Collecting ipython==4.0.3
  Using cached ipython-4.0.3-py3-none-any.whl (730 kB)
Processing /home/timmc/.cache/pip/wheels/f7/a7/04/698ba41a3880444759dd4398e191f125565efe80dfd784d450/python_jenkins-0.4.14-py3-none-any.whl
Collecting pyparsing==2.0.7
  Using cached pyparsing-2.0.7-py2.py3-none-any.whl (38 kB)
Collecting pytz==2017.2
  Using cached pytz-2017.2-py2.py3-none-any.whl (484 kB)
Collecting yagocd==0.4.4
  Using cached yagocd-0.4.4-py2.py3-none-any.whl (53 kB)
Processing /home/timmc/.cache/pip/wheels/f6/72/12/109ff95e19bd8e20fb6291d320e451c46b76650df883f7418a/bottle-0.12.7-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/f6/21/b8/15d92e95de1293453d19d52629acd148b56b7cd7d186720e47/Markdown-2.3.1-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/d7/ea/c7/c92e27f6be8d9daab836133d72ac9dc50dff140c07c4a9c860/Jinja2-2.7.3-py3-none-any.whl
Collecting APScheduler==2.1.2
  Using cached APScheduler-2.1.2-py2.py3-none-any.whl (27 kB)
Processing /home/timmc/.cache/pip/wheels/50/7e/da/5d5adf578f45942fb69607aaf8350280c133cf1f739fe145d1/MarkupSafe-0.23-cp35-cp35m-linux_x86_64.whl
Processing /home/timmc/.cache/pip/wheels/58/6e/27/dcaeea0f4b7272d6ab98f53aeff362a39b9641618c046b23cb/natural-0.1.5-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/04/9a/25/ff42f83b0d6937068c38be559c3d6e6018598efeca37c5fa8a/clint-0.3.7-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/84/56/95/27ce0007f0fa17532ea7e8045370cb93c79c6977a396988185/sleekxmpp-1.3.1-py3-none-any.whl
Collecting CherryPy==3.6.0
  Using cached CherryPy-3.6.0-py3-none-any.whl (453 kB)
Processing /home/timmc/.cache/pip/wheels/40/cb/ac/29fd9b6192aa2c182338f789fbdf23cb335d9f41d4939d300b/hiredis-0.1.4-cp35-cp35m-linux_x86_64.whl
Processing /home/timmc/.cache/pip/wheels/dd/a0/32/a82341526f7e65f128aae8873beea68d78ff65ec71ede4c167/pyasn1_modules-0.0.5-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/33/b2/32/4226c77705b3cd0e474edb13cf3036056d25027dc661277824/dill-0.2.1-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/4c/c1/ce/ed9c5d0f3459fd863831ea832d6a02564c3c2d12bdda84643a/dnspython-1.12.0-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/1b/02/db/dc446c02ad90ecd22b5344065a33d1c52ade55db475332a76d/redis-2.10.3-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/6e/45/91/f61d4c07062e71f4b619d17b66cb54515b7f72ccb2103ded08/pyasn1-0.1.7-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/76/28/c6/17f1eea302a0f65ed8da198bbb2499a7a152e57bc4a8996fb9/pygerduty-0.28-py3-none-any.whl
Collecting requests==2.4.1
  Using cached requests-2.4.1-py2.py3-none-any.whl (458 kB)
Processing /home/timmc/.cache/pip/wheels/c0/2b/bf/0aca3f70693590b3e06e30303bffb9dfbca196d43eef945059/parsedatetime-1.1.2-py3-none-any.whl
Collecting traitlets
  Using cached traitlets-4.3.3-py2.py3-none-any.whl (75 kB)
Collecting pickleshare
  Using cached pickleshare-0.7.5-py2.py3-none-any.whl (6.9 kB)
Processing /home/timmc/.cache/pip/wheels/12/7f/50/87cce86ea3e870aa24d10579b138d47482efe28506e7caaad4/simplegeneric-0.8.1-py3-none-any.whl
Collecting pexpect; sys_platform != "win32"
  Using cached pexpect-4.8.0-py2.py3-none-any.whl (59 kB)
Collecting decorator
  Using cached decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
Processing /home/timmc/.cache/pip/wheels/cd/6a/21/70eb09ed74894b7b5a598254da1e675bff96d07c9d263f0edf/multi_key_dict-2.0.3-py3-none-any.whl
Collecting six>=1.3.0
  Using cached six-1.15.0-py2.py3-none-any.whl (10 kB)
Collecting pbr>=0.8.2
  Using cached pbr-5.4.5-py2.py3-none-any.whl (110 kB)
Processing /home/timmc/.cache/pip/wheels/b3/d4/de/cb284c2639c66d6e2ef3a385d42774d7c24b460c9d37108666/easydict-1.9-py3-none-any.whl
Processing /home/timmc/.cache/pip/wheels/4f/40/7e/75601a1f7e45b2121bde5b163e0b6d7c25e257bf8b1e7c0597/args-0.1.0-py3-none-any.whl
Collecting ipython-genutils
  Using cached ipython_genutils-0.2.0-py2.py3-none-any.whl (26 kB)
Collecting ptyprocess>=0.5
  Using cached ptyprocess-0.6.0-py2.py3-none-any.whl (39 kB)
ERROR: will 0.9.3 has requirement PyYAML==3.10, but you'll have pyyaml 3.12 which is incompatible.
Installing collected packages: bottle, Markdown, MarkupSafe, Jinja2, PyYAML, APScheduler, natural, args, clint, sleekxmpp, CherryPy, hiredis, pyasn1, pyasn1-modules, dill, dnspython, redis, pygerduty, requests, parsedatetime, will, boto, ipython-genutils, six, decorator, traitlets, pickleshare, simplegeneric, ptyprocess, pexpect, ipython, multi-key-dict, pbr, python-jenkins, pyparsing, pytz, easydict, yagocd
Successfully installed APScheduler-2.1.2 CherryPy-3.6.0 Jinja2-2.7.3 Markdown-2.3.1 MarkupSafe-0.23 PyYAML-3.12 args-0.1.0 boto-2.43.0 bottle-0.12.7 clint-0.3.7 decorator-4.4.2 dill-0.2.1 dnspython-1.12.0 easydict-1.9 hiredis-0.1.4 ipython-4.0.3 ipython-genutils-0.2.0 multi-key-dict-2.0.3 natural-0.1.5 parsedatetime-1.1.2 pbr-5.4.5 pexpect-4.8.0 pickleshare-0.7.5 ptyprocess-0.6.0 pyasn1-0.1.7 pyasn1-modules-0.0.5 pygerduty-0.28 pyparsing-2.0.7 python-jenkins-0.4.14 pytz-2017.2 redis-2.10.3 requests-2.4.1 simplegeneric-0.8.1 six-1.15.0 sleekxmpp-1.3.1 traitlets-4.3.3 will-0.9.3 yagocd-0.4.4

(Only portion that was on stderr was the error line above: ERROR: will 0.9.3 has requirement PyYAML==3.10, but you'll have pyyaml 3.12 which is incompatible. Exit code was zero.)

This resulted in the following pip list --format=freeze:

APScheduler==2.1.2
args==0.1.0
boto==2.43.0
bottle==0.12.7
CherryPy==3.6.0
clint==0.3.7
decorator==4.4.2
dill==0.2.1
dnspython==1.12.0
easydict==1.9
hiredis==0.1.4
ipython==4.0.3
ipython-genutils==0.2.0
Jinja2==2.7.3
Markdown==2.3.1
MarkupSafe==0.23
multi-key-dict==2.0.3
natural==0.1.5
parsedatetime==1.1.2
pbr==5.4.5
pexpect==4.8.0
pickleshare==0.7.5
pip==20.2b1
ptyprocess==0.6.0
pyasn1==0.1.7
pyasn1-modules==0.0.5
pygerduty==0.28
pyparsing==2.0.7
python-jenkins==0.4.14
pytz==2017.2
PyYAML==3.12
redis==2.10.3
requests==2.4.1
setuptools==46.4.0
simplegeneric==0.8.1
six==1.15.0
sleekxmpp==1.3.1
traitlets==4.3.3
wheel==0.34.2
will==0.9.3
yagocd==0.4.4

New resolver

Output of pip install --unstable-feature=resolver -r requirements.txt:

Collecting PyYAML==3.12
  Using cached PyYAML-3.12.zip (375 kB)
Collecting yagocd==0.4.4
  Using cached yagocd-0.4.4-py2.py3-none-any.whl (53 kB)
Collecting ipython==4.0.3
  Using cached ipython-4.0.3-py3-none-any.whl (730 kB)
Collecting will==0.9.3
  Using cached will-0.9.3.tar.gz (41 kB)
ERROR: Could not find a version that satisfies the requirement PyYAML==3.12
ERROR: Could not find a version that satisfies the requirement PyYAML==3.10 (from will)
ERROR: No matching distribution found for pyyaml, pyyaml

Last three lines were on stderr; exit code 1.

This resulted in the following pip list --format=freeze:

pip==20.2b1
setuptools==46.4.0
wheel==0.34.2
timmc-edx commented 4 years ago

Incidentally, I wrote a script to find things like this across repos I care about: https://github.com/timmc-edx/pip-resolver-compare

uranusjr commented 4 years ago

So it seems like both resolvers are able to detect that there is a conflict between PyYAML 3.10 and 3.12. The difference is that the current resolver allows that combination anyway, but the new resolver rejects it outright on the basis of the conflict.

What do you think the new resolver should do in this situation, if not immediately rejecting the result? Should it install PyYAML 3.10 or 3.12, and why?

timmc-edx commented 4 years ago

Good question. I'm fairly new to Python dependency management, so I'm not sure I have a well-informed opinion. But for what it's worth... my gut sense is to reject it by default, but allow it (with 3.12, the pinned version) if an appropriate option is set. This is on the premise that someone may very well have a good reason to use conflicting versions—perhaps they're in dependency hell and need to temporarily be in an "invalid" state in order to move through an upgrade process. Something like that.

But I guess I'd first want to know why the current resolver allows it. :-)

uranusjr commented 4 years ago

The current resolver just doesn’t care 😛 It sees 3.12 first, realises it is a viable choice (it hasn’t seen 3.10 yet), and goes “nah, good enough, you know what you’re doing.” The new resolver treats all requirements equally instead, and does not assume the user knows best.

So the problem is two-way. IMO pip can’t just assume the user really knows what they’re doing, since they don’t always do. Maybe the solution for the problem would be to keep the new resolver’s current behaviour, but introduce some kind of an “override” mechanism for those who do know what they’re doing.

I vaguely recall a discussion somewhere on this particular feature, but can’t seem to find the thread now. So I’ll keep this open so people can jump in and provide ideas.

timmc-edx commented 4 years ago

Maybe this is the issue you're thinking of? https://github.com/pypa/pip/issues/8076 "Relaxing / Ignoring constraints during dependency resolution"

timmc-edx commented 4 years ago

(Incidentally, this issue seems to have lost, or never acquired, the "C: new resolver" label.)

uranusjr commented 4 years ago

Ah, yes! Thanks so much for digging it out!

pradyunsg commented 4 years ago

This also came up in #8307, where I'd suggested that such an override mechanism would cover that usecase and others like it.