pip 10 和 apt:如何避免 distutils 软件包的“无法卸载 X”错误

Posted

技术标签:

【中文标题】pip 10 和 apt:如何避免 distutils 软件包的“无法卸载 X”错误【英文标题】:pip 10 and apt: how to avoid "Cannot uninstall X" errors for distutils packages 【发布时间】:2018-09-30 15:31:19 【问题描述】:

我正在处理一个遗留的 Dockerfile。这是我正在处理的非常简化的版本:

FROM ubuntu:14.04

RUN apt-get -y update && apt-get -y install \
    python-pip \
    python-numpy # ...and many other packages

RUN pip install -U pip

RUN pip install -r /tmp/requirements1.txt # includes e.g., numpy==1.13.0
RUN pip install -r /tmp/requirements2.txt
RUN pip install -r /tmp/requirements3.txt

首先使用apt安装几个包,然后使用pip安装几个包。 pip第10版已经发布,part of the release就是这个新限制:

删除了对卸载已使用 distutils 安装的项目的支持。 distutils 安装的项目不包含指示哪些文件属于该安装的元数据,因此不可能实际卸载它们,而只能删除表示它们已安装的元数据,同时留下所有实际文件。

这导致我的设置出现以下问题。例如,首先apt 安装python-numpy。后来pip 尝试从/tmp/requirements1.txt 安装较新版本的numpy,并尝试卸载旧版本,但由于新限制,它无法删除此版本:

Installing collected packages: numpy
  Found existing installation: numpy 1.8.2
Cannot uninstall 'numpy'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.

现在我知道目前有几种解决方案。

我无法通过apt 安装python-numpy。但是,这会导致问题,因为python-numpy 安装了几个不同的包作为要求,我不知道系统的另一部分是否依赖这些包。实际上,通过 Dockerfile 安装了几个 apt 包,我删除的每个包似乎都揭示了另一个 Cannot uninstall X 错误,并随之删除了许多其他包,我们的应用程序可能依赖也可能不依赖.

当我尝试pip 安装已经通过apt 安装的东西时,我也可以使用--ignore-installed 选项,但是我又遇到了同样的问题,每个--ignore-installed 参数揭示了另一件事需要忽略。

我可以将pip 固定在没有此限制的旧版本上,但我不想永远使用过时的pip 版本。

我一直在兜圈子,试图提出一个好的解决方案,该解决方案涉及对这个遗留 Dockerfile 的最小更改,并允许我们使用该文件部署的应用程序继续像以前一样运行。关于如何安全地解决pip 10 无法安装较新版本的distutils 软件包的任何建议?谢谢!

更新:

我没有意识到 --ignore-installed 可以在没有包的情况下用作忽略所有已安装包的参数。我正在考虑这对我来说是否是一个不错的选择,并且已经询问了here。

【问题讨论】:

【参考方案1】:

这是我最终采用的解决方案,并且我们的应用程序已经在生产环境中运行了近一个月,没有任何问题,并且修复了这个问题:

我所要做的就是添加

--ignore-installed

到我的 dockerfile 中引发错误的 pip install 行。使用我原始问题中的相同 dockerfile 示例,固定的 dockerfile 看起来像:

FROM ubuntu:14.04

RUN apt-get -y update && apt-get -y install \
    python-pip \
    python-numpy # ...and many other packages

RUN pip install -U pip

RUN pip install -r /tmp/requirements1.txt --ignore-installed # don't try to uninstall existing packages, e.g., numpy
RUN pip install -r /tmp/requirements2.txt
RUN pip install -r /tmp/requirements3.txt

我认为--ignore-installed 的文档不清楚(pip install --help 只是说“忽略已安装的软件包(而不是重新安装)。”),我询问了这个标志 here 的潜在危险,但还没有得到满意的答案。但是,如果有任何负面影响,我们的生产环境还没有看到它们的影响,我认为风险很低/没有(至少这是我们的经验)。我能够确认,在我们的例子中,当使用这个标志时,现有的安装并没有被卸载,但新的安装总是被使用。

更新:

我想突出显示@ivan_pozdeev 的this 回答。他提供了一些此答案未包含的信息,并且还概述了我的解决方案的一些潜在副作用。

【讨论】:

这使得系统的配置不​​受支持,因此无法维护。即使你这次很幸运,它也可能在未来任何其他包管理操作之后以不可预知的方式破坏事情。请参阅***.com/questions/53807511/… 处的说明 @ivan_pozdeev 感谢您提供的信息。我怀疑这个解决方案可能有潜在的缺点,并在另一个问题中询问了这些问题,并且在没有得到对该问题的答复后才发布此答案:***.com/questions/49932926/… 我将在上面突出显示您的答案,以便使用我的解决方案的人意识到潜在的副作用。【参考方案2】:

这对我有用--

pip install --ignore-installed <Your package name>

sudo pip install --ignore-installed <Your package name>

或(在 jupyter 笔记本内)

import sys
!sys.executable -m pip install --ignore-installed <Your package name>

【讨论】:

“在 jupyter 笔记本中”【参考方案3】:

对于窗户 写

conda update --all pip install --upgrade <Your package name>

conda update --all pip install <Your package name>

pip install wrapt --upgrade --ignore-installed pip install <Your package name>

来自ERROR: Cannot uninstall 'wrapt'. during upgrade

【讨论】:

【参考方案4】:

您可以手动删除 numpy,但保留 apt 安装的其他依赖项。然后像以前一样使用 pip 安装最新版本的 numpy。

#Manually remove just numpy installed by distutils
RUN rm /usr/lib/python2.7/dist-packages/numpy-1.8.2.egg-info
RUN rm -r /usr/lib/python2.7/dist-packages/numpy

RUN pip install -U pip
RUN pip install -r /tmp/requirements1.txt

numpy的位置应该是一样的。但是,如果您想确认位置,您可以在不运行 requirements.txt 文件的情况下运行容器,并在容器内的 python 控制台中发出以下命令。

>>> import numpy
>>> print numpy.__file__
/usr/lib/python2.7/dist-packages/numpy/__init__.pyc

【讨论】:

感谢您的回答!但这与我上面列出的一些可能的解决方案有类似的问题。在我的示例中,问题出在 numpy 上,但实际上我需要以这种方式删除几个(约 10 个或更多)包,我想找到一个不涉及硬编码删除的更通用的解决方案这些包中的每一个。不过谢谢你的主意!我不认为这是在不删除依赖项的情况下删除 python 包的一种方式!

以上是关于pip 10 和 apt:如何避免 distutils 软件包的“无法卸载 X”错误的主要内容,如果未能解决你的问题,请参考以下文章

如何重置 virtualenv 和 pip?

pip、brew、apt-get区别和作用

使用 pip 与 apt-get 安装软件包有啥区别?

pip和apt-get换源

apt-get virtualenv 和 pip virtualenv 有啥区别?

Ubuntu apt-get和pip源更换