Environment
Description
Uncaught exception occurs when checking for outdated packages, crashing pip. Apparently the version number is now a type, but does not support >-comparison.
Expected behavior
Print a list of outdated packages
How to Reproduce
Simply run pip list --outdated
Output
$ pip list --outdated
Exception:
Traceback (most recent call last):
File "/usr/lib/python3.7/site-packages/pip/_internal/basecommand.py", line 141, in main
status = self.run(options, args)
File "/usr/lib/python3.7/site-packages/pip/_internal/commands/list.py", line 136, in run
packages = self.get_outdated(packages, options)
File "/usr/lib/python3.7/site-packages/pip/_internal/commands/list.py", line 147, in get_outdated
dist for dist in self.iter_packages_latest_infos(packages, options)
File "/usr/lib/python3.7/site-packages/pip/_internal/commands/list.py", line 148, in <listcomp>
if dist.latest_version > dist.parsed_version
TypeError: '>' not supported between instances of 'Version' and 'Version'
I can reproduce this as well.
Environment
Here are my findings after investigating:
this error comes from dist.parsed_version and dist.latest_version not being the same type, one of which being a packaging.version and the other being a pip._vendor.packaging.version.Version (or possibly a .
Replacing the following lines in pip/_internal/index.py:
from pip._vendor.packaging import specifiers
from pip._vendor.packaging.utils import canonicalize_name
from pip._vendor.packaging.version import parse as parse_version
with
from packaging import specifiers
from packaging.utils import canonicalize_name
from packaging.version import parse as parse_version
fixes the issue, which makes me believe the vendoring process in pip/_vendor obfuscates the declaration of the Version class in a way it is declared twice independently. This will then cause the instance check to fail while comparing the classes of both versions.
Can you reproduce with a pristine version of pip (that is a version that is not unvendored)?
No, cloning the pypa/pip repository and running pip list --outdated works with that version. I assume the bug only occurs with DEBUNDLED=True.
IMHO, any unvendored pip is a (subtly) broken pip...
I can't reproduce this locally, with or without the distribution version of pip (I'm on Arch Linux too). What's the output of pip freeze --all?
@benoit-pierre : you'll laugh, but after trying stuff the error seems to be gone.
I'm not sure what made it go away, but I may have had an alternate pip or setuptools version installed in the user prefix that conflicted with the vendored dependencies.
I don't think a user installed pip/setuptools version is the cause for this, on the contrary, those vendored versions can only work better! Maybe a different version of packaging? I can easily break distrib pip by installing, say packaging==16 (and of course a vendored version of pip still works fine).
I can trigger the error again after installing setuptools in a user-install using:
$ pip install --user -U setuptools --force-reinstall
Installing setuptools also installs pkg_resources which may vendor its own packaging.version.Version I guess.
Yep, I can reproduce it too!
So installing setuptools from PyPI will install pkg_resources, which vendors its own packaging when you install it from PyPI... This will cause pkg_resources and pip to use two different packaging version, hence causing the instancecheck to fail.
I can't really see a way out of this though, unless preventing pkg_resources from vendoring packaging...
I guess the answer is that if you're de-vendoring, you need to de-vendor both pip and setuptools?
That happens when you let your package manager (and packagers) do everything for you, but if a user aggressively updates setuptools (for instance because the official repositories are lagging behind in term of updates) then the user will end up with a de-vendored pip and a vendored setuptools, causing this error to occur.
EDIT: not instance checking when comparing versions and relying on duck-typing would be preferable but I understand why you'd want to do that verification.
Don't use the distribution versions of setuptools/pkg_resources. Vendoring is there exactly to protect against this kind of issues. It really make no sense for a distribution like Arch Linux, whose pretty much always up-to-date, to unvendor pip/setuptools.
I think a new field should be added to the new issue template, or the version field should also mention how pip is installed (distribution package? from PyPi?).
Unfortunately, I think there may always be the case of an unwanted upgrade: if you run a pip install --user -U package where package has setuptools as a dependency, and you have an older setuptools (which may occur on a Debian, Fedora, whatever distro has a long enough release cycle) you may end up encountering this issue because you'll install the vendored setuptools with the unvendored pip.
Should we also add a note to the vendoring README with advice to help packagers avoid this situation?
Sounds good to me!
sorry, I do not understand the discussion above in every detail.
I see the problem described above on my system running Devuan/Beowulf what in the Python-World is identical to Debian/Buster(stable).
sudo apt install python3-pip follwoed by pip3 list --outdated seems to be enough to reproduce the error:
Exception:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/pip/_internal/cli/base_command.py", line 143, in main
status = self.run(options, args)
File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 138, in run
packages = self.get_outdated(packages, options)
File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 149, in get_outdated
dist for dist in self.iter_packages_latest_infos(packages, options)
File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 150, in <listcomp>
if dist.latest_version > dist.parsed_version
TypeError: '>' not supported between instances of 'Version' and 'Version'
I never installed anything outside the Debian Package Manager. So if I understand the discussion above correctly the package manager made a mistake. Is this correct?