升级`pip`会删除其他python的pip [英] Upgrading `pip` removes other python's pips
问题描述
在CentOS 7系统上,我安装了多个版本的Python,每个版本都有自己的 pip
版本:
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
当我要求 pip3.8
进行自我升级时,它会删除已安装的 pip3.7
:
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?
更新:
- 两个安装的lib路径不同,如下所示:
# 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']
-
这不是双向的-升级
pip3.7
不会删除pip3.8
.我相信库已正确升级,并将版本3.7库保留在原位,只是删除了shell wrapper脚本.在
pip3.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)
-
执行
pip3.7 install --upgrade pip
不会删除/usr/local/bin/pip3.6
,因此并非如此总是删除以前的版本.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.为获得完全的可重复性,并显示我从一个相当原始的系统开始,这是一个包含我的Dockerfile文本的Gist: https://gist.github.com/kenahoo/a1104f9cb84694fbd5ec9d6d560a885e .由于
pip3.7
丢失了,因此在RUN pip3.7 install setuptools numpy pandas
行上失败.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.我是否使用
python3.8 -m pip install --upgrade pip或
pip3.8 install --upgrade pip
升级都没关系,他们两个最终都删除了/usr/local/bin/pip3.7
包装器脚本.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.推荐答案
我相信我找到了问题.
简而言之,将
pipX.Y
控制台脚本设置为用于构建 pip 滚轮的Python解释器的版本,而不是该版本的用于安装它的Python解释器.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.例如,将安装在任何 Python 中的 pip 安装在 非 3.8(在我的例子中是 Python 3.6)并使用它下载
pip
本身: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:$ /path/to/pythonX.Y -m pip download pip
这应该为您提供一个 wheel 文件,例如
pip-20.0.2-py2.py3-none-any.whl
,现在将其解压缩:This should give you a wheel file for example
pip-20.0.2-py2.py3-none-any.whl
, now unzip it:$ /path/to/pythonX.Y -m zipfile -e pip-20.0.2-py2.py3-none-any.whl .
现在查看
pip-20.0.2.dist-info/entry_points.txt
的内容:$ cat pip-20.0.2.dist-info/entry_points.txt [console_scripts] pip = pip._internal.cli.main:main pip3 = pip._internal.cli.main:main pip3.8 = pip._internal.cli.main:main
所以即使我有Python 3.6,也有一个控制台脚本
pip3.8
条目.这显然是错误的.例如,如果我确实有一个实际的pip3.8
脚本,则该文件在卸载与Python 3.6相关的 pip 时将被删除,例如进行升级.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:
entry_points={ "console_scripts": [ "pip=pip._internal:main", "pip%s=pip._internal:main" % sys.version_info[:1], "pip%s.%s=pip._internal:main" % sys.version_info[:2], ], },
此行
pip%s.%s = pip._internal:main%sys.version_info [:2]
实际上是在构建 wheel 时实际记录下来的,并且我假设我们先前下载的 wheel 是使用 Python 3.8 构建的.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.pip 的维护者,并且不确定它是否会得到修复(可能不值得).
That bug is (at least partially) known to pip's maintainers, and not sure it will get fixed (probably not worth it).
无论如何,应该始终使用显式的
/path/to/pythonX.Y -m pip
代替.pip *
脚本只是为方便起见而在此处使用的快捷方式.它们在交互式命令行中很有用,可以节省一些击键并能够更快地工作.但是在文件中,从文档到 shell 脚本或 Dockerfiles 的任何文件,我都认为应该始终使用显式扩展版本.例如,我总是写rm --recursive
而不是rm -r
等.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.在 Python 的 pip 的一种特殊情况下,无论如何,这都是有道理的:
Additionally in the one particular case of Python's pip, it makes sense no matter what:
这篇关于升级`pip`会删除其他python的pip的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
-