【问题标题】:Upgrading `pip` removes other python's pips升级`pip`会删除其他python的点子
【发布时间】:2020-07-22 07:33:44
【问题描述】:

在 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

当我要求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

为什么会这样,我该如何预防?

更新

  • 两个安装的 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 包装脚本。这是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)
  • 执行pip3.7 install --upgrade pip 不会删除/usr/local/bin/pip3.6,因此它并不总是删除以前的版本。

  • 1234563它在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 包装脚本。

【问题讨论】:

  • 您的 3.7 和 3.8 安装是否指向同一个包目录?
  • 这是双向的,即升级pip3.7 删除pip3.8
  • @jordanm 和 norok2 - 谢谢,我已经在问题的更新中解决了这些问题。
  • 你能安装 python 3.4 看看是否会被 pip3.7 升级删除吗?它可能正在删除早期版本的入口点。不确定这是否是预期的行为。
  • 使用虚拟环境可能会有所帮助,因为只会更改打包的 pip。

标签: python linux pip


【解决方案1】:

我强制重新安装了原来的python3的pip,然后我在/usr/local/bin/中恢复了旧版本

python3 -m pip install --force-reinstall pip

【讨论】:

    【解决方案2】:

    我相信我找到了问题。

    简而言之,pipX.Y 控制台脚本设置为用于构建 pip 轮的 Python 解释器的版本,而不是用于安装它的 Python 解释器的版本。

    例如,将任何 pip 安装在 不是 3.8 的任何 Python 中(在我的情况下是 Python 3.6)并使用它来下载pip自己:

    $ /path/to/pythonX.Y -m pip download pip
    

    这应该会给你一个 wheel 文件,例如 pip-20.0.2-py2.py3-none-any.whl,现在解压缩它:

    $ /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 时,该文件将被删除,例如升级它。

    问题的根源可以在这里看到,例如:

        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 构建的em>。


    pip 的维护人员(至少部分)知道bug,但不确定它是否会得到修复(可能不值得)。

    无论如何,应该始终使用显式的/path/to/pythonX.Y -m pippip* 脚本只是为了方便而提供的快捷方式。它们在交互式命令行中有些有用,可以节省一些击键并能够更快地工作。但是在文件中,从文档到 shell 脚本或 Dockerfiles,我认为应该始终使用显式扩展版本。比如我总是写rm --recursive而不是rm -r等等。

    另外,在 Pythonpip 的一个特殊情况下,无论如何它都是有意义的:

    【讨论】:

    • 这确实看起来像问题。它似乎也没有在 pip v20 中得到修复:github.com/pypa/pip/blob/20.0.2/setup.py#L79
    • 其实我还是有点困惑——如果安装 pip 3.8 会删除 pip3.7,我们难道不希望在 3.8 entry_points.txt 文件中看到 pip3.7 的条目,而不是另一个怎么办?无论如何,在决定要卸载的东西时 pip 实际使用的文件列表是什么?
    • 这正是我所说的。但很可能您尝试升级 frompip 版本来自使用不同解释器构建的轮子。因此,在您的情况下,Python 3.8 最初附带的 pip 可能来自使用 Python 3.7 构建的轮子。很可能是您以某种方式拥有正确的 pip3.8 脚本,但 entry_points.txt 中的条目错误,并且很可能是卸载 pip 时使用的该文件(就在升级之前),因此它会删除错误的 pipX.Y 脚本。或者,也许我只是把自己弄糊涂了。我得仔细看看。
    • 啊哈,你说得对。我在 python 3.8 中用于 pip 的初始entry_points.txt 有一个pip3.7 = pip._internal:main 的条目。所以我想我会认为这是一个 pip 打包错误,我可以将它提交给 pip 人。我可能会通过修复该文件来解决它,然后像往常一样执行升级。
    • 我已经开票了:github.com/pypa/pip/issues/8010
    【解决方案3】:

    更新

    您可以使用piptarget 命令告诉pip 允许在哪里查找pip 并进行更新。

    $ pip3.8 install --upgrade --target /usr/local/lib/python3./site-packages/ pip
    

    只升级 pip3.8 将保持 pip 3.7 不变。

    我跑的时候

    ...
    
    RUN pip3.5 install --upgrade --target /usr/local/lib/python3.5/site-packages/ pip
    RUN pip3.6 install --upgrade --target /usr/local/lib/python3.6/site-packages/ pip
    RUN pip3.7 install --upgrade --target /usr/local/lib/python3.7/site-packages/ pip
    RUN pip3.8 install --upgrade --target /usr/local/lib/python3.8/site-packages/ pip
    
    ...
    

    pip 仍在 python3.5/3.6 的站点包中,但 pip3.5 和 3.6 确实没有出现在 /usr/local/bin 中。因此,要将软件包 全局 安装到 python3.5/3.6 必须使用 python3.5 -m pip install &lt;package&gt;

    这是因为pip3.5pip3.6 应该存储在/usr/bin 而不是/usr/local/bin。你可以使用

    ...
    
    RUN pip3.5 install --upgrade pip
    RUN pip3.6 install --upgrade pip
    RUN pip3.7 install --upgrade --target /usr/local/lib/python3.7/site-packages/ pip
    RUN pip3.8 install --upgrade --target /usr/local/lib/python3.8/site-packages/ pip
    
    ...
    

    并且 pip3.5-8 将全部存在并工作。仍然建议使用带有 python 的虚拟环境。

    警告

    Pip 似乎发出了由直接调用 pip 引起的警告。警告建议将 pip 作为 python 模块向前推进python -m pip &lt;command&gt;

    [root@93e6e7373eff /]# pip3.8 -V
    WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
    Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
    To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
    pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
    
    [root@93e6e7373eff /]# pip3.7 -V
    WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
    Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
    To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
    pip 20.0.2 from /usr/local/lib/python3.7/site-packages/pip (python 3.7)
    
    [root@93e6e7373eff /]# pip3.6 -V
    pip 20.0.2 from /usr/local/lib/python3.6/site-packages/pip (python 3.6)
    
    [root@93e6e7373eff /]# pip3.5 -V
    pip 20.0.2 from /usr/lib/python3.5/site-packages/pip (python 3.5)
    


    解决方法

    我可以通过更改您的安装顺序来完成所有工作。由于唯一的问题似乎是 pip3.8 会查找旧版本并删除它们,因此我先安装和升级了其他版本。我刚刚在我的笔记本电脑上构建了它并且它运行了(哈哈它在我的机器上运行)。

    # -*- dockerfile -*-
    FROM centos:7.7.1908
    RUN yum update -y
    RUN yum install -y epel-release
    RUN yum install -y https://centos7.iuscommunity.org/ius-release.rpm
    
    RUN yum install -y python35u python35u-pip
    RUN yum install -y python36u python36u-pip
    
    RUN yum install -y gcc gcc-c++
    RUN yum install -y make openssl-devel bzip2-devel libffi-devel
    
    # Python3.8 is not currently available from RHEL, EPEL, or IUS repos so download and compile it
    ARG PY38_VERSION=3.8.2
    RUN cd /usr/src && curl https://www.python.org/ftp/python/${PY38_VERSION}/Python-${PY38_VERSION}.tgz | tar -xz &&\
      cd Python-${PY38_VERSION} && ./configure --enable-optimizations && make -j4 altinstall &&\
      rm -rf /usr/src/Python-${PY38_VERSION}
    
    RUN pip3.8 install --upgrade pip
    RUN pip3.8 install setuptools numpy pandas
    
    # Python3.7 is not currently available from RHEL, EPEL, or IUS repos so download and compile it
    RUN yum install -y gcc openssl-devel bzip2-devel libffi-devel make sqlite-devel
    ARG PY37_VERSION=3.7.6
    RUN cd /usr/src && curl https://www.python.org/ftp/python/${PY37_VERSION}/Python-${PY37_VERSION}.tgz | tar -xz &&\
      cd Python-${PY37_VERSION} && ./configure --enable-optimizations && make -j4 altinstall &&\
      rm -rf /usr/src/Python-${PY37_VERSION}
    
    RUN pip3.7 install --upgrade pip
    RUN pip3.7 install setuptools numpy pandas
    
    RUN pip3.5 install --upgrade pip
    RUN pip3.5 install setuptools numpy pandas
    RUN pip3.6 install --upgrade pip
    RUN pip3.6 install setuptools numpy pandas
    
    
    RUN yum install -y python35u-devel python36u-devel python37u-devel python38u-devel
    
    
    CMD /bin/bash
    
    

    控制台输出:

    [root@e3b166a8b479 /]# python3.7 -m pip -V     
    pip 20.0.2 from /usr/local/lib/python3.7/site-packages/pip (python 3.7)
    [root@e3b166a8b479 /]# python3.6 -m pip -V
    pip 20.0.2 from /usr/local/lib/python3.6/site-packages/pip (python 3.6)
    [root@e3b166a8b479 /]# python3.8 -m pip -V
    pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
    [root@e3b166a8b479 /]# ls /usr/local/bin | grep pip
    pip
    pip3
    pip3.6
    pip3.7
    pip3.8
    

    【讨论】:

    • 感谢所有这些研究。我确实注意到 pip 3.5 和 3.6 安装在 /usr/bin 而不是 /usr/local/bin,大概是因为它们来自供应商 RPM 而不是源代码。
    • 看起来当我使用 pip3.8 install --upgrade --target /usr/local/lib/python3.8/site-packages/ pip 升级 pip 3.8 时,pip3.8 包装器已过时,并抱怨说 WARNING: pip is being invoked by an old script wrapper
    • [root@93e6e7373eff /]# pip3.8 -V WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip. Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue. To avoid this problem you can invoke Python with '-m pip' instead of running pip directly. pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8) 该错误似乎是直接调用 pip 造成的。一切都应该工作。运行容器并四处寻找以确保。
    猜你喜欢
    • 1970-01-01
    • 2019-03-20
    • 2021-12-02
    • 2021-08-28
    • 2018-09-10
    • 2019-01-30
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    相关资源
    最近更新 更多