在 CentOS 7 系统上,我安装了多个版本的 Python,每个版本都有自己的以下版本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
Run Code Online (Sandbox Code Playgroud)
当我要求pip3.8升级自己时,它会删除已安装的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
Run Code Online (Sandbox Code Playgroud)
为什么会这样,我该如何预防?
更新:
# 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']
Run Code Online (Sandbox Code Playgroud)
它不是双向升级pip3.7不删除pip3.8。
我相信该库会正确升级并保留 3.7 版库,只是删除了 shell 包装器脚本。pip3.8升级后是这样的:
# 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)
Run Code Online (Sandbox Code Playgroud)
这样pip3.7 install --upgrade pip做不会删除/usr/local/bin/pip3.6,因此它并不总是删除以前的版本。
为了完全重现,并表明我从一个相当原始的系统开始,这里有一个包含我的 Dockerfile 文本的 Gist:https ://gist.github.com/kenahoo/a1104f9cb84694fbd5ec9d6d560a885e 。它上RUN pip3.7 install setuptools numpy pandas线失败,因为pip3.7丢失了。
我是否使用python3.8 -m pip install --upgrade pip或升级都没有关系pip3.8 install --upgrade pip,它们最终都会删除/usr/local/bin/pip3.7包装器脚本。
我相信我发现了这个问题。
简而言之,pipX.Y控制台脚本设置为用于构建pip轮子的 Python 解释器版本,而不是用于安装它的 Python 解释器版本。
例如,获取任何非3.8版本的Python中安装的任何pip(在我的例子中是 Python 3.6)并使用它来下载自身:pip
$ /path/to/pythonX.Y -m pip download pip
Run Code Online (Sandbox Code Playgroud)
例如,这应该给你一个wheelpip-20.0.2-py2.py3-none-any.whl文件,现在解压它:
$ /path/to/pythonX.Y -m zipfile -e pip-20.0.2-py2.py3-none-any.whl .
Run Code Online (Sandbox Code Playgroud)
现在看一下内容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
Run Code Online (Sandbox Code Playgroud)
pip3.8因此,即使我有 Python 3.6,也有一个控制台脚本的条目。这显然是错误的。例如,如果我确实有一个实际的脚本,那么在卸载与 Python 3.6 关联的pip时(例如升级它),pip3.8该文件将被删除。
问题的根源可以在这里看到,例如:
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],
],
},
Run Code Online (Sandbox Code Playgroud)
这行代码实际上是在构建轮子pip%s.%s=pip._internal:main" % sys.version_info[:2]时明确写下来的,我假设我们之前下载的轮子是用Python 3.8构建的。
pip的维护者(至少部分)知道该错误,并且不确定它是否会得到修复(可能不值得)。
无论如何,人们应该总是使用显式/path/to/pythonX.Y -m pip的。这些pip*脚本只是为了方便起见而设置的快捷方式。它们在交互式命令行中有点有用,可以节省一些击键并能够更快地工作。但在文件中,从文档到shell脚本或Dockerfiles的任何内容,我认为应该始终使用显式扩展版本。例如,我总是写rm --recursive而不是rm -r等等。
另外,在Python的pip的一种特殊情况下,无论如何它都是有意义的:
| 归档时间: |
|
| 查看次数: |
1564 次 |
| 最近记录: |