Почему вам действительно нужно обновить pip
Новые выпуски программного обеспечения могут содержать исправления ошибок, новые функции и более высокую производительность. Например, в NumPy 1.20 добавлены аннотации типов и улучшена производительность за счет использования SIMD, когда это возможно. Если вы устанавливаете NumPy, возможно, вы захотите установить самую новую версию.
К сожалению, если вы используете старую версию pip
, установка последней версии пакета Python может завершиться ошибкой или установиться более медленным и более сложным способом.
Почему? Комбинация управления версиями glibc
, графика окончания срока службы CentOS и способов установки pip
пакетов.
Давайте посмотрим, в чем именно заключается проблема, как ее решить и, наконец, если вам достаточно интересно, что ее вызывает.
Проблема со старым pip
Начнем с образа Docker Ubuntu 18.04. Эта версия Ubuntu, выпущенная в апреле 2018 года, включает Python версии 3.6 и pip
версии 9.
[itamarst@blake dev]$ docker run -it ubuntu:18.04
root@1a43d55f0524:/# apt-get update
...
root@1a43d55f0524:/# apt-get install --no-install-recommends python3 python3-pip
...
root@1a43d55f0524:/# pip3 --version
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)
Все идет нормально.
Ошибка №1: компиляция из исходников
Затем давайте установим пакет cryptography
, который является одним из самых загружаемых пакетов Python на PyPI, с миллионами загрузок в месяц (обычно как косвенная зависимость).
root@1a43d55f0524:/# pip3 install cryptography
Collecting cryptography
Downloading https://files.pythonhosted.org/packages/fa/2d/2154d8cb773064570f48ec0b60258a4522490fcb115a6c7c9423482ca993/cryptography-3.4.6.tar.gz (546kB)
100% |################################| 552kB 1.4MB/s
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'setuptools'
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-6jesygn0/cryptography/
Эта ошибка означает, что pip
, хочет скомпилировали пакеты; это сработает, если мы установим компилятор setuptools
и цепочку инструментов разработки Python, но это будет довольно медленно.
Конечно, это не один пакет. Та же проблема возникает например с PyArrow:
root@1a43d55f0524:/# pip3 install pyarrow
Collecting pyarrow
Downloading https://files.pythonhosted.org/packages/62/d3/a482d8a4039bf931ed6388308f0cc0541d0cab46f0bbff7c897a74f1c576/pyarrow-3.0.0.tar.gz (682kB)
100% |################################| 686kB 1.1MB/s
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'setuptools'
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-heq6zwd7/pyarrow/
Почему pip
пытается скомпилировать эти пакеты с нуля? Почему мы не получаем предварительно скомпилированный двоичный пакет?
Мы увидим ответ чуть позже, после того как рассмотрим вторую ошибку.
Ошибка №2: старые версии
Затем давайте установим Fil, мой профилировщик памяти для Python.
root@1a43d55f0524:/# pip3 install filprofiler
Collecting filprofiler
Downloading https://files.pythonhosted.org/packages/e3/a2/843e7b5f1aba27effb0146c7e564e2592bfc9344a8c8ef0d55245bd47508/filprofiler-0.7.2-cp36-cp36m-manylinux1_x86_64.whl (565kB)
100% |################################| 573kB 1.8MB/s
Installing collected packages: filprofiler
Successfully installed filprofiler-0.7.2
Это сработало! За исключением того, что вы посетите страницу PyPI для Fil, вы увидите, что версия 0.7.2 довольно устарела. На момент написания этой статьи последняя версия Fil - 0.14.1.
Почему была установлена старая версия?
pip и manylinux
Многие пакеты - от NumPy до Cryptography - требуют компиляции некоторого кода на C/C++/Cython/Rust/и т. д. Чтобы избавить вас от необходимости компилировать все с нуля, специалисты по сопровождению могут загрузить скомпилированную версию кода - «wheels» - в указатель пакетов Python. Если pip
видит wheels, которое будет работать с вашей конкретной версией Python и версией операционной системы, он загрузит его вместо исходного кода.
Для Linux, существует несколько вариантов wheels: manylinux1
, manylinux2010
, и manylinux2014
. Вы можете увидеть, какой вариант используется в имени файла загружаемого wheels.
Проблема в том, что старые версии pip
не поддерживаются manylinux2010
, и уж точно не manylinux2014
. В Ubuntu 18.04 pip
слишком стар, поэтому он знает только о manylinux1
. Это объясняет две проблемы, которые мы видели:
- Если проверить имеющиеся файлы списков для PyArrow 3.0.0 на PyPI, вы увидите , что wheels есть только
manylinux2010
иmanylinux2014
. Поэтому pip решил вернуться к пакету исходного кода, который требует компиляции. - Если вы проверите файлы PyPI для Fil, вы увидите, что есть
manylinux2010
, а исходных пакетов нет вообще; поскольку сборка из исходных текстов немного сложна, я распространяю только скомпилированные пакеты. Это означает, чтоpip
продолжает возвращаться к более старым версиям пакета, пока не найдет ту, в которой естьmanylinux1
.
Решение: обновление pip
Чтобы получить самые последние и лучшие пакеты без компиляции, вам необходимо обновить до последней версии pip
. Как вы это делаете, зависит от вашего окружения.
В общем, можно выполнить pip install --upgrade pip
.
Однако в некоторых средах могут возникать проблемы. Например, если вы посмотрите выше, как мы настраиваем Python в Ubuntu 18.04, мы установили pip
из системного пакета.
Проблема в том, что перезапись случайных файлов из системного пакета - плохая идея. Если вы не работаете в среде, которую вы можете при необходимости перестроить с нуля - например, образ Docker - вам никогда не следует запускать pip install
с правами root или с помощью sudo
для изменения системных пакетов.
Поэтому вместо этого в Ubuntu 18.04 вы можете получить pip через загрузку:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py
Или вы можете создать virtualenv, а затем обновить его pip
, выполнив pip install --upgrade pip
:
root@1a43d55f0524:/# python3 -m venv myvenv
root@1a43d55f0524:/# . myvenv/bin/activate
(myvenv) root@1a43d55f0524:/# pip --version
pip 9.0.1 from /myvenv/lib/python3.6/site-packages (python 3.6)
(myvenv) root@1a43d55f0524:/# pip install --upgrade pip
Collecting pip
Using cached https://files.pythonhosted.org/packages/fe/ef/60d7ba03b5c442309ef42e7d69959f73aacccd0d86008362a681c4698e83/pip-21.0.1-py3-none-any.whl
Installing collected packages: pip
Found existing installation: pip 9.0.1
Uninstalling pip-9.0.1:
Successfully uninstalled pip-9.0.1
Successfully installed pip-21.0.1
Теперь, когда у нас есть более новая версия pip
, мы можем легко установить последние версии cryptography
и filprofiler
:
(myvenv) root@1a43d55f0524:/# pip install cryptography filprofiler
Collecting cryptography
Downloading cryptography-3.4.6-cp36-abi3-manylinux2014_x86_64.whl (3.2 MB)
|################################| 3.2 MB 4.5 MB/s
...
Installing collected packages: pycparser, threadpoolctl, cffi, filprofiler, cryptography
Successfully installed cffi-1.14.5 cryptography-3.4.6 filprofiler-0.14.1 pycparser-2.20 threadpoolctl-2.1.0
Обратите внимание, что мы загрузили пакет manylinux2014
для cryptography
.
Почему существует так много вариаций manylinux?
Скомпилированные расширения Python в Linux связываются со стандартной библиотекой C, а в wheels, в частности, они связываются с GNU Libc, также известной как glibc. Вы можете увидеть, с какими библиотеками связана исполняемая или разделяемая библиотека, с помощью утилиты ldd
:
root@1a43d55f0524:/# cd myenv/lib/python3.6/site-packages
root@1a43d55f0524:/# ldd cryptography/hazmat/bindings/_openssl.abi3.so
linux-vdso.so.1 (0x00007ffdbea7b000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fba7b1bf000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fba7adce000)
/lib64/ld-linux-x86-64.so.2 (0x00007fba7b7b0000)
Обратите внимание, что скомпилированное расширение Python полагается, среди прочего, на glibc /lib/x86_64-linux-gnu/libc.so.6
.
Если вы компилируете свой код с более новой версией glibc, ему могут потребоваться новые API или символы, которые недоступны в старых версиях. А это означает, что ваш код не будет работать с более старыми версиями glibc, то есть со старыми дистрибутивами Linux.
Есть несколько различных решений этой проблемы. Conda решает эту проблему, скомпилировав все свои пакеты по старой версии заголовков glibc, которые она включает; в основном он имеет настраиваемую настройку компиляции, предназначенную для работы с широким спектром выпусков Linux.
Бинарные wheels PyPI решают эту проблему путем компиляции в старых версиях Linux, которые, соответственно, имеют старые версии glibc. Поскольку он скомпилирован для старой версии, он будет работать и с любой более новой версией.
- Пакеты manylinux1 построены на CentOS 5.
- Пакеты manylinux2010 построены на CentOS 6.
- Пакеты manylinux2014 построены на CentOS 7.
Мотивация для каждого нового варианта - это окончание срока службы каждой версии CentOS. И каждый новый вариант требует соответствующей новой версии pip
. Вы можете узнать больше в PEP-571 и PEP-599.
Обновите свой pip!
Независимо от того, настраиваете ли вы среду разработки или пишете свой Dockerfile
, обязательно обновите pip
. В противном случае вам будет намного сложнее устанавливать пакеты.