On a CentOS 7 system, I have multiple versions of Python installed, each with their own version of pip
:
# head -n1 /usr/local/bin/pip3.*
==> /usr/local/bin/pip3.6 <==
#!/usr/bin/python3
==> /usr/local/bin/pip3.7 <==
#!/usr/local/bin/python3.7
==> /usr/local/bin/pip3.8 <==
#!/usr/local/bin/python3.8
When I ask pip3.8
to upgrade itself, it removes the installed pip3.7
:
# pip3.8 install --upgrade pip
Collecting pip
Using cached https://files.pythonhosted.org/packages/54/0c/d01aa759fdc501a58f431eb594a17495f15b88da142ce14b5845662c13f3/pip-20.0.2-py2.py3-none-any.whl
Installing collected packages: pip
Found existing installation: pip 19.2.3
Uninstalling pip-19.2.3:
Successfully uninstalled pip-19.2.3
Successfully installed pip-20.0.2
# head -n1 /usr/local/bin/pip3.*
==> /usr/local/bin/pip3.6 <==
#!/usr/bin/python3
==> /usr/local/bin/pip3.8 <==
#!/usr/local/bin/python3.8
Why is it doing this, and how can I prevent it?
UPDATES:
- The lib paths are different for the two installations, as shown here:
# python3.7 -c 'import sys; print(sys.path)'
['', '/usr/local/lib/python37.zip', '/usr/local/lib/python3.7', '/usr/local/lib/python3.7/lib-dynload', '/usr/local/lib/python3.7/site-packages']
# python3.8 -c 'import sys; print(sys.path)'
['', '/usr/local/lib/python38.zip', '/usr/local/lib/python3.8', '/usr/local/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/site-packages']
-
It is not bidirectional – upgrading
pip3.7
does not removepip3.8
. -
I believe the library gets upgraded correctly and leaves the version 3.7 library in place, it’s just the shell wrapper script that’s deleted. Here’s after the
pip3.8
upgrade:
# python3.7 -m pip --version
pip 20.0.2 from /usr/local/lib/python3.7/site-packages/pip (python 3.7)
# python3.8 -m pip --version
pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
# pip3.7 --version
bash: pip3.7: command not found
# pip3.8 --version
pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
-
Doing
pip3.7 install --upgrade pip
does not remove/usr/local/bin/pip3.6
, so it’s not the case that it always removes previous versions. -
For full reproducibility, and to show that I’m starting with a fairly pristine system, here’s a Gist containing my Dockerfile text: https://gist.github.com/kenahoo/a1104f9cb84694fbd5ec9d6d560a885e . It fails on the
RUN pip3.7 install setuptools numpy pandas
line becausepip3.7
has gone missing. -
It doesn’t matter whether I upgrade using
python3.8 -m pip install --upgrade pip
orpip3.8 install --upgrade pip
, both of them end up removing the/usr/local/bin/pip3.7
wrapper script.
3
Answers
Update
You can use
pip
‘starget
command to tell pip where it is allowed to look for pip and do an update.To upgrade just pip3.8 which will leave pip 3.7 intact.
When I ran
pip was still in the site-packages for python3.5/3.6 but pip3.5 & 3.6 did not show up in
/usr/local/bin
. So to install packages globally to python3.5/3.6 one would have to usepython3.5 -m pip install <package>
This is because
pip3.5
andpip3.6
should be stored in/usr/bin
not/usr/local/bin
. You can useAnd pip3.5-8 will all exist and work. It is still advisable to use virtual environments with python.
Warning
Pip seems to be issuing a warning that is caused by calling pip directly. The warning suggestions calling pip as a python module moving forward
python -m pip <command>
Workaround
I was able to get it all to work by changing the order in which you install. Since the only issue seems to be that pip3.8 looks for older versions and deletes them, I installed and upgraded before anything else. I just built this on my laptop and it ran (lol it worked on my machine).
outputs from console:
I believe I found the issue.
In short, the
pipX.Y
console script is set to the version of the Python interpreter used to build the pip‘s wheel, instead of the version of the Python interpreter used to install it.For example take any pip installed in any Python that is not 3.8 (in my case it’s Python 3.6) and use it to download
pip
itself:This should give you a wheel file for example
pip-20.0.2-py2.py3-none-any.whl
, now unzip it:Now look at the content of
pip-20.0.2.dist-info/entry_points.txt
:So there is an entry for a console script
pip3.8
even though I have Python 3.6. This is obviously wrong. And for example if I indeed had an actualpip3.8
script then this file would be deleted when uninstalling the pip associated with the Python 3.6, for example to upgrade it.The root of the issue can be seen here for example:
This line
pip%s.%s=pip._internal:main" % sys.version_info[:2]
gets actually written down definitely when building the wheel, and I assume the wheel we downloaded earlier was built with Python 3.8.That bug is (at least partially) known to pip‘s maintainers, and not sure it will get fixed (probably not worth it).
Anyway, one should always use the explicit
/path/to/pythonX.Y -m pip
instead. Thepip*
scripts are just shortcuts that are here for convenience. They are somewhat useful from an interactive command line to save some keystrokes and be able to work faster. But in a file, anything from documentation, to shell scripts, or Dockerfiles, I am the opinion that one should always use the explicit expanded versions. For example I always writerm --recursive
instead ofrm -r
, etc.Additionally in the one particular case of Python‘s pip, it makes sense no matter what:
I force re-installed the original python3’s pip and then I got back the old version in /usr/local/bin/