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

list --outdated: TypeError: '>' not supported between instances of 'Version' and 'Version' #5429

Closed
daavve opened this issue May 20, 2018 · 33 comments
Labels
auto-locked Outdated issues that have been locked by automation project: <downstream> When the cause/effect is related to redistributors

Comments

@daavve
Copy link

daavve commented May 20, 2018

Environment

  • pip version:
  • Python version:
  • OS:

Arch Linux, Testing version of pip: https://www.archlinux.org/packages/testing/any/python-pip/
Description

$ pip list -o

Exception:
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/pip/_internal/basecommand.py", line 228, in main
status = self.run(options, args)
File "/usr/lib/python3.6/site-packages/pip/_internal/commands/list.py", line 145, in run
packages = self.get_outdated(packages, options)
File "/usr/lib/python3.6/site-packages/pip/_internal/commands/list.py", line 156, in get_outdated
dist for dist in self.iter_packages_latest_infos(packages, options)
File "/usr/lib/python3.6/site-packages/pip/_internal/commands/list.py", line 157, in
if dist.latest_version > dist.parsed_version
TypeError: '>' not supported between instances of 'Version' and 'Version'

@daavve
Copy link
Author

daavve commented May 20, 2018

@yan12125
Copy link
Contributor

Looks like an issue related to deblundling. If I modify the get_outdated() function in /usr/lib/python3.6/site-packages/pip/_internal/commands/list.py to:

    def get_outdated(self, packages, options):
        ret = []
        for dist in self.iter_packages_latest_infos(packages, options):
            print(dist.latest_version.__class__)
            print(dist.parsed_version.__class__)
            if dist.latest_version > dist.parsed_version:
                ret.append(dist)
        return ret

pip list -o prints:

<class 'pip._vendor.packaging.version.Version'>
<class 'pkg_resources.extern.packaging.version.Version'>
Exception:
Traceback (most recent call last):                                                                                                      
  File "/usr/lib/python3.6/site-packages/pip/_internal/basecommand.py", line 228, in main                                               
    status = self.run(options, args)                                                                                                    
  File "/usr/lib/python3.6/site-packages/pip/_internal/commands/list.py", line 145, in run                                              
    packages = self.get_outdated(packages, options)                                                                                     
  File "/usr/lib/python3.6/site-packages/pip/_internal/commands/list.py", line 159, in get_outdated                                     
    if dist.latest_version > dist.parsed_version:                                                                                       
TypeError: '>' not supported between instances of 'Version' and 'Version'                                                               

pip._vendor.packaging.version.Version and pkg_resources.extern.packaging.version.Version are actually the same class (both are packaging.version.Version), while Python does not think so.

@pradyunsg
Copy link
Member

Thanks for looking into this @yan12125! :)

Indeed, this is a downstream packaging issue.

@pradyunsg pradyunsg added the project: <downstream> When the cause/effect is related to redistributors label May 21, 2018
@pradyunsg
Copy link
Member

Adding to my above comment, I don't see anything actionable on this from pip's on this -- it's due to how Arch Linux is debundling pip.

@pradyunsg pradyunsg added the S: needs triage Issues/PRs that need to be triaged label May 21, 2018
@daavve
Copy link
Author

daavve commented May 21, 2018

I think you are right. This looks like an Arch issue.

@daavve daavve closed this as completed May 21, 2018
@pradyunsg pradyunsg added resolution: no action When the resolution is to not do anything and removed S: needs triage Issues/PRs that need to be triaged labels May 21, 2018
@yan12125
Copy link
Contributor

I managed to patch pkg_resources locally to make pip list -o work with Arch Linux packages. Hopefully that helps other distributions using debundling. This patch is created against python-setuptools 1:39.2.0-1.

--- pkg_resources/__init__.py.orig	2018-05-22 00:21:05.592049050 +0800
+++ pkg_resources/__init__.py	2018-05-22 00:21:19.378315213 +0800
@@ -71,11 +71,11 @@
 
 from . import py31compat
 from pkg_resources.extern import appdirs
-from pkg_resources.extern import packaging
-__import__('pkg_resources.extern.packaging.version')
-__import__('pkg_resources.extern.packaging.specifiers')
-__import__('pkg_resources.extern.packaging.requirements')
-__import__('pkg_resources.extern.packaging.markers')
+import packaging
+__import__('packaging.version')
+__import__('packaging.specifiers')
+__import__('packaging.requirements')
+__import__('packaging.markers')
 
 
 if (3, 0) < sys.version_info < (3, 3):

@eli-schwartz
Copy link
Contributor

eli-schwartz commented May 22, 2018

Adding to my above comment, I don't see anything actionable on this from pip's on this -- it's due to how Arch Linux is debundling pip.

We're debundling according to the method nominally supported by pip itself, so I think it should be actionable here. :)

pip._internal.index.PackageFinder attempts to use pip._vendor.packaging.version.parse (which is dist.latest_version in the traceback), then compares it to pip._internal.utils.misc.get_installed_distributions which uses pip._vendor.pkg_resources to return a set of pkg_resources packages -- even though they're the same files, they appear in different locations on the import path, and python complains.

This somehow works for pip when using vendored everything, but only because the vendored pkg_resources is then additionally modified from stock pkg_resources to import everything from the top-level _vendor.packaging

...

I don't fully grok the magic used by pip's vendored() and pkg_resource's VendorImporter(), but it looks like they might be incompatible, and pip is papering over this logic by completely ignoring the latter in its own vendoring code.

@pradyunsg
Copy link
Member

Hey @eli-schwartz!

Could you take a look at #5346 (comment) and provide information about the people at Arch Linux to ping for such things? :)

(I can't respond to your comment now because I'm super short on time; I'll reopen this issue so that I remember that I need to get back to this.)

@pradyunsg pradyunsg reopened this May 22, 2018
@pradyunsg pradyunsg removed the resolution: no action When the resolution is to not do anything label May 22, 2018
@yan12125
Copy link
Contributor

I created a more general patch:

--- pkg_resources/extern/__init__.py.orig	2018-05-23 00:58:31.680640763 +0800
+++ pkg_resources/extern/__init__.py	2018-05-23 00:58:47.678203875 +0800
@@ -48,7 +48,7 @@
                 # on later Python versions to cause relative imports
                 # in the vendor package to resolve the same modules
                 # as those going through this importer.
-                if sys.version_info > (3, 3):
+                if sys.version_info > (3, 3) and prefix != '':
                     del sys.modules[extant]
                 return mod
             except ImportError:

Anyway this looks like a setuptools issue rather than a pip one.

@eli-schwartz
Copy link
Contributor

@jaraco, can you confirm?

@yan12125
Copy link
Contributor

yan12125 commented Jan 5, 2019

The issue reappeared with pip git-master and Python 3.7.2 even with the setuptools patch in #5429 (comment). This time the fix should go to pip IMO. I'm currently working on this.

@valtron
Copy link

valtron commented Feb 4, 2019

Reinstall pip to fix this:

pip3 install --ignore-installed pip

pradyunsg pushed a commit that referenced this issue Mar 15, 2019
…ces (#6113)

With the original `vendored()` implementation and such an initialization sequence:

```
vendored("packaging")
vendored("packaging.version")
```

In `sys.modules`, `pip._vendor.packaging` is correctly connected to the debundled `packaging`, while `pip._vendor.packaging.version` is not, as the latter is `__import__`ed from the existing `pip._vendor.packaging` module. That results in the same issue as #5429 - `pip._vendor.packaging.version.Version` and `packaging.version.Version` cannot be compared.

This patch attempts to fix this issue by skipping `__import__` from the vendored name. This is safe because `vendored()` is called only when `DEBUNDLED = True`, and vendored libraries are already deleted as per [debundling instructions](https://github.com/pypa/pip/blob/master/src/pip/_vendor/README.rst#debundling).
@ntninja
Copy link

ntninja commented May 12, 2019

I'm affected as well by this on Debian unstable and neither of @yan12125's patches worked. 🙁

@yan12125
Copy link
Contributor

The issue still exists in pip 19.1?

@eli-schwartz
Copy link
Contributor

Debian unstable still packages pip 18.1, so @Alexander255's issue is definitely not confirmed with pip 19.

@bernd-wechner
Copy link

bernd-wechner commented Jul 11, 2019

pip3 install --ignore-installed pip

Wow I just did that because I have this issue on Mint 19. Only it broke pip. Awesome.

$ pip3 install --ignore-installed pip
Collecting pip
  Cache entry deserialization failed, entry ignored
  Downloading https://files.pythonhosted.org/packages/5c/e0/be401c003291b56efc55aeba6a80ab790d3d4cece2778288d65323009420/pip-19.1.1-py2.py3-none-any.whl (1.4MB)
    100% |████████████████████████████████| 1.4MB 814kB/s 
Installing collected packages: pip
Successfully installed pip-19.1.1
$ pip3
Traceback (most recent call last):
  File "/usr/bin/pip3", line 9, in <module>
    from pip import main
ImportError: cannot import name 'main'

Any pointer appreciated. That sux!

Addendum: fixed it my uninstalling pip3 with apt and reinstalling.

@bernd-wechner
Copy link

bernd-wechner commented Jul 11, 2019

@yan12125

and prefix != '':

I made that patch and still had the problem. So undid it.

@eli-schwartz
Copy link
Contributor

Wow I just did that because I have this issue on Mint 19. Only it broke pip. Awesome.

Don't follow bad advice from people who don't know what they are talking about and don't have context on the issue. Speaking with my "I am a developer for a linux distro" hat on, do not ever sudo pip anything. Ever. And definitely, definitely, definitely, do not try to install pip from your distro package manager and then update it using pip, because you WILL break it and as extensively discussed in #5346, and ideally pip would learn to say "you are not allowed to update this using pip, please use your package manager instead" as tracked by #5605.

You will need to either install pip via apt, or install pip via get-pip.py, and make sure you don't have bits and pieces of the wrong thing in your PYTHONPATH.

...

As for why Linux Mint's pip package has this bug, you need to discuss this with the Debian packagers of python3-pip. My guess is they are shipping a broken setuptools. See https://bugs.archlinux.org/task/58670 for more details.

@bernd-wechner
Copy link

Thanks enormously for informative advice. I uninstalled the Debian pip packages and installed get-pip.py as per the Python website and now pip works fine, and I have pip installing python3 packages (whereas Debian packages install pip2 and pip3 and link pip to pip2 still - and I like many, have near zero interest in Python 2 anymore).

And pip list -o works fine now too. Basically everything seems fine after removing the debian packages and using get-pip.py.

I do have one question though.

do not ever sudo pip anything.

I mildly agree with the principle here, but what if I want my packages installed in /usr/lib/python3.6/dist-packages say and not in my home dir? In fact with this pip I just installed it tries that and bombs suggesting I use the --user option. What is your recommendation in that space?

@pradyunsg
Copy link
Member

what if I want my packages installed in /usr/lib/python3.6/dist-packages

What's the use case for not using a Debian-provided pip but still wanting to install to a location where that would install packages?

@pradyunsg
Copy link
Member

What is your recommendation in that space?

As the fellow who added that to message -- I'd say use --user as the message suggests. 🙃

@bernd-wechner
Copy link

what if I want my packages installed in /usr/lib/python3.6/dist-packages

What's the use case for not using a Debian-provided pip but still wanting to install to a location where that would install packages?

Forgive me, but the obvious: to make the packages available not to the current user and Python code they run, but to other users, including system services that need access to them. The use case is not to install them where the Debian packaged pip would install them, the use case is system wide installation (vs. local user installation).

With all due respect, that is such a common and ordinary and fairly obvious use case I'd have thought that pip by default installs there (I have to use --user flag to get around it) and I forgot to state it explicitly.

@eli-schwartz
Copy link
Contributor

You're installing system services without using the package manager? Personally I'd avoid that sort of thing. Then again, Arch Linux does make it very easy to empower the masses to create system packages.

...

Using sudo pip means that pip can and will overwrite files tracked by the package manager. Do you have software on your system which is written in python and distributed via apt? Python is a popular programming language for desktop software, there are DEs written in python. Do you want to break that software by overwriting system packages with incompatible components?

@pradyunsg
Copy link
Member

With all due respect, that is such a common and ordinary and fairly obvious use case I'd have thought that pip by default installs there (I have to use --user flag to get around it) and I forgot to state it explicitly.

Yep yep - #1668. It's a bit tricker than it looks on the surface. 🙃

@bernd-wechner
Copy link

Using sudo pip means that pip can and will overwrite files tracked by the package manager. Do you have software on your system which is written in python and distributed via apt? Python is a popular programming language for desktop software, there are DEs written in python. Do you want to break that software by overwriting system packages with incompatible components?

Guess you're right. Never really thought about it. Still that does create a conundrum that is discussed in the issue predyunsg mentioned via a linked to item... namely that the OS package (Ubuntu apt repos in my case) are generally way out of date ... and so if you want the latest at a system level it's pip or conda I guess.

Of course I guess I concur, to be safe just install to home dir as a first cut.

In the end though I admit I work on a few premises:

  1. That anybody installing python packages (apt, pip, conda?) also takes the trouble to ensure the python path includes the directory they use to install them.
  2. That python packages on the whole don't do backward breaks, i.e. maintain backward compatibility as a priority (inside of a major Python release in any case).

Of course as you point out those premises may be a little naive, and introduce unnecessary risk if taken as truths and installing with pip to system dirs.

it does leave the question open (as per predyunsg's linked item) why on earth pip defaults to system dirs, if the wisdom you share is widely held in the community of people who develop and maintain pip! It does indeed seem sensible to default to local.

@pradyunsg
Copy link
Member

why on earth pip defaults to system dirs

Because... no one's put in the effort to change that and it's a non-trivial change. :)

@martin3000
Copy link

martin3000 commented Jul 28, 2019

In list.py I changed

    def get_outdated(self, packages, options):
        return [
            dist for dist in self.iter_packages_latest_infos(packages, options)
            if dist.latest_version > dist.parsed_version
        ]

to

    def get_outdated(self, packages, options):
        return [
            dist for dist in self.iter_packages_latest_infos(packages, options)
            if str(dist.latest_version) > str(dist.parsed_version)
        ]

and it works.

@yan12125
Copy link
Contributor

@martin3000 That patch may lead to incorrect results as PEP 440 version comparisons are not plain string comparisons.

@pradyunsg Could you consider closing this issue to send a message that "this has been fixed"? Specifically, users need setuptools >= 40.0.0 and pip >= 19.1. I don't think this ticket needs more discussions about patches for pip/setuptools unless pip list -o would be broken again.

@martin3000
Copy link

Comparing the strings ist not ok, but here in Ubuntu 19.04 it was crashing.

@yan12125
Copy link
Contributor

Apparently Ubuntu 19.04 ships with pip 18.1 [1]. The issue is fixed since pip 19.1 (commit 8ef3283, specifically). You may want to report the issue to Ubuntu or Debian developers, so that they can fix their package by either upgrading pip or backporting the relevant commit.

Alternatively, you can also uninstall the system pip package with apt and install the latest pip following https://pip.pypa.io/en/stable/installing/. Note that it's better to keep only one of Ubuntu's pip and the one from pypa.io, or there might be errors like #5429 (comment).

[1] https://launchpad.net/ubuntu/disco/+source/python-pip

@jeremy-rifkin
Copy link

Had this issue with ubuntu 18 and apt's python3-pip package (pip 9.0.1).
Fixed by uninstalling pip 9.01 and using get-pip.py to install pip 19.2.

@pradyunsg
Copy link
Member

Could you consider closing this issue to send a message that "this has been fixed"? Specifically, users need setuptools >= 40.0.0 and pip >= 19.1.

Sounds reasonable!

@verhovsky
Copy link

verhovsky commented Jan 2, 2020

This might be unsafe, but

sudo -H pip3 install --upgrade pip

Solved it for me on Ubuntu 18.04. Make sure you do sudo, otherwise you'll get ModuleNotFoundError: No module named 'pip'.

@lock lock bot added the auto-locked Outdated issues that have been locked by automation label Feb 1, 2020
@lock lock bot locked as resolved and limited conversation to collaborators Feb 1, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
auto-locked Outdated issues that have been locked by automation project: <downstream> When the cause/effect is related to redistributors
Projects
None yet
Development

No branches or pull requests

10 participants