Правильное управление пакетами Python
Не становитесь жертвой опасностей управления пакетами Python.
Индекс пакетов Python (PyPI) индексирует потрясающий набор библиотек и приложений, охватывающий все мыслимые варианты использования. Однако, когда дело доходит до установки и использования этих пакетов, новички часто сталкиваются с проблемами, связанными с отсутствием разрешений, несовместимыми зависимостями библиотек и неожиданными сбоями при установке.
Дзен Python гласит: «Должен быть один — и желательно только один — очевидный способ сделать это». Конечно, это не всегда так, когда дело доходит до установки пакетов Python. Однако существуют некоторые инструменты и методы, которые можно считать передовыми практиками. Знание этого поможет вам выбрать правильный инструмент для конкретной ситуации.
Установка приложений в масштабе всей системы
pip — это де-факто менеджер пакетов в мире Python. Он может устанавливать пакеты из многих источников, но PyPI является основным источником пакетов, в котором он используется. При установке пакетов pip сначала разрешает зависимости, проверяет, установлены ли они уже в системе, и, если нет, устанавливает их. Как только все зависимости будут удовлетворены, он приступает к установке запрошенных пакетов. По умолчанию все это происходит глобально, все устанавливается на компьютер в одном месте, зависящем от операционной системы.
Python 3.7 ищет пакеты в системе Arch Linux в следующих местах:
$ python3.7 -c "import sys; print('\n'.join(sys.path))"
/usr/lib/python37.zip
/usr/lib/python3.7
/usr/lib/python3.7/lib-dynload
/usr/lib/python3.7/site-packages
Одна из проблем глобальных установок заключается в том, что для данного интерпретатора Python одновременно может быть установлена только одна версия пакета. Это может вызвать проблемы, если пакет является зависимостью нескольких библиотек или приложений, но им требуются разные версии этой зависимости. Даже если кажется, что все работает нормально, вполне возможно, что обновление зависимости (даже случайное при установке другого пакета) приведет к поломке этих приложений или библиотек в будущем.
Другая потенциальная проблема заключается в том, что большинство Unix-подобных дистрибутивов управляют пакетами Python с помощью встроенного менеджера пакетов (dnf, apt, pacman, brew и т. д.), а некоторые из этих инструментов устанавливаются в места, недоступные для записи пользователем.
$ python3.7 -m pip install pytest
Collecting pytest
Downloading...
[...]
Installing collected packages: atomicwrites, pluggy, py, more-itertools, pytest
Could not install packages due to an EnvironmentError: [Error 13] Permission denied:
'/usr/lib/python3.7/site-packages/site-packages/atomicwrites-x.y.z.dist-info'
Consider using '--user' option or check the permissions.
$
Это не удается, поскольку мы запускаем pip install от имени пользователя без полномочий root и у нас нет прав на запись в каталог site-packages.
Технически это можно обойти, запустив pip от имени пользователя root (с помощью команды sudo) или администратора. Однако одна проблема заключается в том, что мы только что установили несколько пакетов Python в папку, принадлежащую менеджеру пакетов дистрибутива Linux, что делает его внутреннюю базу данных и установку несовместимыми. Это, скорее всего, вызовет проблемы каждый раз, когда мы попытаемся установить, обновить или удалить любую из этих зависимостей с помощью менеджера пакетов.
В качестве примера давайте попробуем установить pytest еще раз, но теперь с помощью менеджера пакетов моей системы pacman:
$ sudo pacman -S community/python-pytest
resolving dependencies...
looking for conflicting packages...
[...]
python-py: /usr/lib/site-packages/py/_pycache_/_metainfo.cpython-37.pyc exists in filesystem
python-py: /usr/lib/site-packages/py/_pycache_/_builtin.cpython-37.pyc exists in filesystem
python-py: /usr/lib/site-packages/py/_pycache_/_error.cpython-37.pyc exists in filesystem
Другая потенциальная проблема заключается в том, что операционная система может использовать Python для системных инструментов, и мы можем легко сломать их, изменив пакеты Python вне системного менеджера пакетов. Это может привести к неработоспособности системы, и восстановление из резервной копии или полная переустановка — единственный способ исправить ситуацию.
sudo pip install: плохая идея
Есть еще одна причина, по которой запускать pip install от имени пользователя root — плохая идея. Чтобы объяснить это, нам сначала нужно посмотреть, как упаковываются библиотеки и приложения Python.
Большинство библиотек и приложений Python сегодня используют инструменты настройки в качестве системы сборки. Для setuptools требуется файл setup.py в корне проекта, который описывает метаданные пакета и может содержать произвольный код Python для настройки процесса сборки. Когда пакет устанавливается из исходного дистрибутива, этот файл запускается для выполнения установки и выполнения таких задач, как проверка системы, сборка пакета и т. д.
Выполнение setup.py с правами root означает, что мы можем эффективно открыть систему для вредоносного кода или ошибок. Это гораздо более вероятно, чем вы думаете. Например, в 2017 году в PyPI было загружено несколько пакетов с именами, напоминающими популярные библиотеки Python. Загруженный код собирал системную и пользовательскую информацию и загружал ее на удаленный сервер. Вскоре после этого эти пакеты были изъяты. Однако такого рода инциденты с «опечатками» могут произойти в любое время, поскольку любой может загружать пакеты в PyPI, и не существует процесса проверки, позволяющего убедиться, что код не причиняет никакого вреда.
Фонд программного обеспечения Python (PSF) недавно объявил, что будет спонсировать работу по улучшению безопасности PyPI. Это должно затруднить проведение таких атак, как «питосквоттинг», и, мы надеемся, сделает это менее серьезной проблемой в будущем.
Помимо проблем безопасности, sudo pip install не решит всех проблем с зависимостями: вы по-прежнему можете установить только одну версию любой библиотеки, а это значит, что таким образом по-прежнему легко сломать приложения.
Давайте посмотрим на некоторые лучшие альтернативы.
Менеджеры пакетов ОС
Весьма вероятно, что «родной» менеджер пакетов, который мы используем в выбранной нами ОС, также может устанавливать пакеты Python. Вопрос в том, следует ли нам использовать pip или apt, dnf, pacman и так далее?
Ответ: это зависит.
pip обычно используется для установки пакетов непосредственно из PyPI, и авторы пакетов Python обычно загружают туда свои пакеты. Однако большинство сопровождающих пакетов не будут использовать PyPI, а вместо этого берут исходный код из исходного дистрибутива (sdist), созданного автором, или системы контроля версий (например, GitHub), при необходимости применяют исправления. а также протестировать и выпустить пакет для соответствующих платформ. По сравнению с моделью распространения PyPI у нее есть плюсы и минусы:
- Программное обеспечение, поддерживаемое собственными менеджерами пакетов, как правило, более стабильно и обычно лучше работает на данной платформе (хотя это не всегда так).
Это также означает, что для упаковки и тестирования исходного кода Python потребуется дополнительная работа:
- Выбор пакетов обычно намного меньше, чем предлагает PyPI.
- Обновления происходят медленнее, а менеджеры пакетов часто поставляют гораздо более старые версии.
Если пакет, который мы хотим использовать, доступен и мы не возражаем против более старых версий, менеджер пакетов предлагает удобный и безопасный способ установки пакетов Python. А поскольку эти пакеты устанавливаются в масштабе всей системы, они доступны всем пользователям системы. Это также означает, что мы можем использовать их только в том случае, если у нас есть необходимые разрешения для установки пакетов в системе.
Если мы хотим использовать что-то, что недоступно в выборе менеджера пакетов или слишком старое, или у нас просто нет необходимых разрешений для установки пакетов, мы можем вместо этого использовать pip.
Установка пользовательской схемы
pip поддерживает режим «пользовательской схемы», представленный в Python 2.6. Это позволяет устанавливать пакеты в папку, принадлежащую пользователю. В Linux это обычно ~/.local. Размещение ~/.local/bin/ в нашем PATH позволит иметь под рукой инструменты и скрипты Python и управлять ими без привилегий root.
$ python3.7 -m pip install --user black
Collecting black
Using cached
[...]
Installing collected packages: click, toml, black
The scripts black and blackd are installed in '/home/tux/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed black-x.y click-x.y toml-x.y.z
$
Однако это решение не решает проблему, если и когда нам понадобятся разные версии одного и того же пакета.
Войдите в виртуальную среду
Виртуальные среды предлагают изолированные установки пакетов Python, которые могут сосуществовать независимо в одной системе. Это дает те же преимущества, что и установка по пользовательской схеме, но также позволяет создавать автономные установки Python, в которых приложение не имеет общих зависимостей с каким-либо другим приложением. Virtualenv создает каталог, в котором хранится автономная установка Python, включая двоичный файл Python и основные инструменты для управления пакетами: setuptools, pip и колесо.
Создание виртуальных сред
virtualenv — это сторонний пакет, но в Python 3.3 пакет venv добавлен в стандартную библиотеку. В результате нам не нужно ничего устанавливать для использования виртуальных сред в современных версиях Python. Мы можем просто использовать python3.7 -m venv
После создания новой виртуальной среды мы должны активировать ее, предоставив сценарий activate в каталоге bin вновь созданной среды. Сценарий активации создает новую подоболочку и добавляет каталог bin в переменную среды PATH, что позволяет нам запускать двоичные файлы и сценарии из этого места. Это означает, что эта подоболочка будет использовать python, pip или любой другой инструмент, установленный в этом месте, вместо тех, которые установлены глобально в системе.
$ python3.7 -m venv test-env
$ . ./test-env/bin/activate
(test-env) $
После этого любая выполняемая нами команда будет использовать установку Python внутри виртуальной среды. Давайте установим несколько пакетов.
(test-env)$ python3.7 -m pip install --user black
Collecting black
Using cached
[...]
Installing collected packages: click, toml, black
Successfully installed black-x.y click-x.y toml-x.y.z
(test-env) $
Мы можем использовать black внутри виртуальной среды без каких-либо ручных изменений переменных среды, таких как PATH или PYTHONPATH.
(test-env) $ black --version
black, version x.y
(test-env) $ which black
/home/tux/test-env/bin/black
(test-env) $
Когда мы закончим с виртуальной средой, мы можем просто деактивировать ее с помощью функции деактивировать.
(test-env) $ deactivate
$
Виртуальные среды также можно использовать без сценария активации. Строка shebang скриптов, установленных в venv, будет переписана для использования интерпретатора Python внутри виртуальной среды. Таким образом, мы можем выполнить скрипт из любого места системы, используя полный путь к скрипту.
(test-env) $ head /home/tux/test-env/bin/black
#!/home/tux/test-env/bin/python3.7
# -*- coding: utf-8 -*-
import re
import sys
from black import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
(test-env) $
Мы можем просто запустить ~/test-env/bin/black из любого места системы, и все будет работать нормально.
Может быть полезно добавить некоторые часто используемые виртуальные среды в переменную среды PATH, чтобы мы могли быстро и легко использовать сценарии в них, не вводя полный путь:
export PATH=$PATH:~/test-env/bin
Теперь, когда мы выполняем black, он будет выбран из виртуальной среды (если только он не появится где-то ранее в PATH). Добавьте эту строку в файл инициализации вашей оболочки (например, ~/.bashrc), чтобы она автоматически устанавливалась во всех новых оболочках.
Виртуальные среды очень часто используются для разработки Python, поскольку каждый проект получает свою собственную среду, в которой можно установить все зависимости библиотеки, не мешая установке системы.
Я рекомендую ознакомиться с проектом virtualenvwrapper, который может помочь упростить распространенные рабочие процессы на основе virtualenv.
А что насчет Конды?
Conda — это инструмент управления пакетами, который может устанавливать пакеты, предоставленные Anaconda, в репозиторий repo.continuum.io. Он стал очень популярным, особенно в области науки о данных. Он предлагает простой способ создания сред, управления ими и установки в них пакетов. Одним из недостатков по сравнению с pip является то, что выбор пакетов намного меньше.
Рецепт успешного управления пакетами
- Никогда не запускайте sudo pip install.
- Если вы хотите сделать пакет доступным для всех пользователей машины, у вас есть соответствующие разрешения и пакет доступен, воспользуйтесь менеджером пакетов вашего дистрибутива (apt, yum ). , pacman, brew и т. д.).
- Если у вас нет прав root или в менеджере пакетов ОС нет нужного вам пакета, используйте pip install --user и добавьте каталог установки пользователя в PATH. > переменная среды.
- Если вы хотите, чтобы несколько версий одной и той же библиотеки сосуществовали, чтобы можно было разрабатывать Python или просто изолировать зависимости по какой-либо другой причине, используйте виртуальные среды.
Эта статья была первоначально опубликована в апреле 2019 года и обновлена редактором.