Pip 10 и apt: как избежать ошибок "Can not uninstall X" для пакетов distutils

Я имею дело с устаревшим 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 была выпущена, и частью выпуска является это новое ограничение:

Удалена поддержка для удаления проектов, которые были установлены с помощью distutils. Установленные проекты distutils не включают метаданные, указывающие, какие файлы принадлежат этой установке, и, следовательно, невозможно фактически удалить их, а не просто удалить метаданные, говоря, что они были установлены, оставив при этом все фактические файлы.

Это приводит к следующей проблеме в моей настройке. Например, first apt устанавливает python-numpy. Позже pip пытается установить более новую версию numpy например, из /tmp/requirements1.txt, и пытается удалить старую версию, но из-за нового ограничения он не может удалить эту версию:

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.

Теперь я знаю, что на данный момент есть несколько решений.

Я не мог установить python-numpy через apt. Однако это вызывает проблемы, поскольку python-numpy устанавливает несколько различных пакетов в качестве требований, и я не знаю, зависит ли другая часть системы от этих пакетов. И в самом деле, есть несколько apt пакетов, установленных через Dockerfile, и каждый из них я извлекаю, кажется, показывают другой Cannot uninstall X ошибку, и снимают ряд других пакетов, наряду с этим, что наше приложение может или не может полагаться.

Я мог бы также использовать --ignore-installed вариант, когда я пытаюсь pip установить вещи, которые уже были установлены через apt, но затем снова у меня такая же проблема каждого --ignore-installed аргумента, раскрывающий еще одну вещь, которая должна быть игнорируются.

Я мог бы прикрепить pip к более старой версии, которая не имеет этого ограничения, но я не хочу застрять, используя устаревшую версию pip навсегда.

Я ходил кругами, пытаясь найти хорошее решение, которое включало бы минимальные изменения в этот устаревший Dockerfile и позволяло приложению, которое мы развертываем с этим файлом, продолжать функционировать, как было. Любые предложения о том, как я могу благополучно обойти эту проблему pip 10 не в состоянии установить новые версии distutils пакетов? Спасибо!

ОБНОВИТЬ:

Я не понимал, что --ignore-installed можно использовать без пакета в качестве аргумента, чтобы игнорировать все установленные пакеты. Я думаю о том, может ли это быть хорошим вариантом для меня, и спросил об этом здесь.

Ответ 1

Это решение, к которому я пришел, и наши приложения работали без проблем в течение почти месяца с этим исправлением:

Все, что мне нужно было сделать, это добавить

--ignore-installed

в строки pip install в моем dockerfile, которые вызывали ошибки. Используя тот же пример 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 просто говорит: "Игнорировать установленные пакеты (вместо переустановки)"), и я спросил о потенциальных опасностях этого флага здесь, но пока не получил удовлетворительного ответа. Тем не менее, если есть какие-либо негативные побочные эффекты, наша производственная среда еще не увидела их влияния, и я думаю, что риск низкий/нет (по крайней мере, таков наш опыт). Я смог подтвердить, что в нашем случае, когда этот флаг использовался, существующая установка не была удалена, но всегда использовалась более новая установка.

Обновить:

Я хотел бы выделить этот ответ @ivan_pozdeev. Он предоставляет некоторую информацию, которая не входит в этот ответ, и он также выделяет некоторые потенциальные побочные эффекты моего решения.

Ответ 2

Вот что сработало для me--

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>

Ответ 3

Вы можете просто удалить numpy вручную, но сохранить другие зависимости, установленные apt. Затем используйте пик, как прежде, для установки последней версии 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 должно быть одинаковым. Но если вы хотите подтвердить местоположение, вы можете запустить контейнер без запуска файлов требований .txt и выпустить следующие команды в консоли python внутри контейнера.

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