Вопрос или проблема
Как мы знаем из предыдущих данных, каталог /usr/local зарезервирован для пользователей, чтобы избежать вмешательства в /usr напрямую. Менеджер пакетов apt ничего не трогает в этом каталоге:
$ dpkg -S /usr/local
dpkg-query: no path found matching pattern /usr/local
То есть, это пространство имен специально зарезервировано для установки пользователями с помощью make install PREFIX=/usr/local и аналогичных команд, что позволяет хорошему сосуществованию программного обеспечения, управляемого apt, с программным обеспечением, управляемым администратором системы. (Также см. /opt против /usr/local.)
Несмотря на стандарты, python 3.12 нарушает эту традицию. Например, я раньше мог создавать образы с предустановленным awscli просто с помощью:
pip install –prefix=/usr/local awscli
С python 3.12 это больше не работает†.
… Честно говоря, мне всё равно на эволюцию Python, отказ от distutils (где, как я полагаю, раньше обрабатывался –prefix=/usr/local), документация, удаляющая даже упоминания о установках в /usr/local (сравните 3.10 и 3.12) и так далее. Мы не можем отменить эти выборы со стороны разработчиков; они уже сделаны. Что меня интересует, так это:
как установить пакеты pip напрямую на ОС (не в песочнице venv);
так, чтобы это не мешало dpkg (/usr/local справляется с этой задачей идеально для моих нужд);
так, чтобы установленные библиотеки можно было импортировать в python repl (любого пользователя) сразу после установки;
так, чтобы установленные исполняемые файлы находились в /usr/local/bin/ и были доступны сразу.
На данный момент, варианты, которые я вижу:
pip install –break-system-packages –prefix=/usr/local foo bar
–break-system-packages выглядит страшно для проведения проверки, несмотря на то, что не имеет смысла;
pip install –target=/usr/local/lib/python3.12/dist-packages/ foo bar
почти работает, как ожидалось — не связывает исполняемые файлы с /usr/local/bin.
Есть ли другие варианты?
Ссылки:
Совет Debian
Обсуждение на Reddit
Обсуждение на SO
PEP-668
† это в конечном итоге требует зловещего флага –break-system-packages, который выглядит страшно, но не имеет смысла в контексте классического префикса /usr/local.
Странным образом, в Debian и Devuan префикс, необходимый для установки в /usr/local, — это /usr. В то время как –prefix=/usr/local устанавливает в /usr/local/local/bin ¯\_(ツ)_/¯. Это:
pip install –prefix=/usr awscli
даёт желаемый результат, а именно:
исполняемый файл /usr/local/bin/aws,
python -c ‘import botocore’ работает,
для всех пользователей образа контейнера.
Предостережения
Лучше быть уверенным, что пересечение между установленными пакетами apt и pip пусто и останется таким. Это связано с тем, что как /usr, так и /usr/local образуют одну “установку python”; интерпретатор видит пакеты, установленные в обоих. (apt в /usr; pip в /usr/local). Таким образом, в терминах PEP-668 может произойти наложение пакетов:
системный инструмент foo зависит от common == 1.*;
вы устанавливаете pip bar, который требует common >= 2.0;
системный инструмент foo теперь сломан, потому что версия common v1 была наложена.
В общем, советы по этой проблеме:
1. Используйте пакет apt, если возможно
Для простых нужд, вам может не понадобиться pip. Например, (какая-то версия) requests может быть установлена с помощью
sudo apt install python3-requests
2. Используйте venv, виртуальную среду
Создать отдельную “установку python”, т.е. venv с полностью изолированным набором пакетов, довольно просто.
sudo apt install python3-venv
python3 -m venv my-shiny-awesome-sandbox
source my-shiny-awesome-sandbox/bin/activate
pip list #– пусто
pip install ….
Тогда вам не нужно беспокоиться о взаимодействиях с системными пакетами. Вместо этого вы заботитесь о поддержании и активации venv.
3. Используйте pipx
sudo apt install pipx
pipx run pycowsay moo
Этот инструмент концептуально поддерживает неявную скрытую venv. Поскольку pipx ориентирован на приложения (точки входа console_scripts), с его помощью не просто установить библиотеки, которые вы могли бы использовать в своих собственных скриптах.
4. Укажите –break-system-packages
sudo pip install –break-system-packages awscli
Это установит в /usr/local. Вы получите как скрипты входных точек, так и библиотеки. Предостережение заключается в том, что вы рискуете смешать пакеты apt с пакетами pip, если не будете осторожны. Поэтому название опции намеренно пугающее.
pip install –user также можно «починить» с помощью:
dpkg-divert –rename –add /usr/lib/python3.12/EXTERNALLY-MANAGED
— как объясняется в /usr/share/doc/python3.12/README.venv.
Ответ или решение
К вопросу установки пакетов с помощью pip в директорию /usr/local, необходимо учитывать несколько ключевых моментов, особенно в контексте изменений, произошедших с Python версии 3.12. В этом ответе я изложу основные аспекты, а также предложу несколько рекомендаций по вашему запросу.
1. Проблема с установкой пакетов через pip в /usr/local
Как вы правильно отметили, каталог /usr/local является стандартной локацией для установки пользовательского программного обеспечения и, согласно иерархии файловой системы Unix (Filesystem Hierarchy Standard, FHS), его использование подразумевает наличие действующих правил для избежания конфликтов с системными пакетами, управляемыми пакетным менеджером, таким как apt.
С переходом на Python 3.12 произошли значительные изменения, которые затруднили установку пакетов через pip в /usr/local. Ранее можно было использовать флаг --prefix=/usr/local
, чтобы все компоненты, включая исполняемые файлы и библиотеки, устанавливались в соответствующие директории и были доступны для всех пользователей.
2. Рекомендации для установки пакетов
Исходя из имеющихся проблем, вот несколько практических рекомендаций:
-
Используйте apt-пакеты, когда это возможно: Если ваши нужды позволяют, рекомендуется использовать apt для установки Python-библиотек. Например, библиотеку requests можно установить командой:
sudo apt install python3-requests
Это позволит избежать возможных конфликтов между пакетами pip и apt.
-
Создавайте виртуальные окружения (venv): Для работы с изолированным набором пакетов вы можете создать виртуальное окружение. Это также поможет избежать проблем с взаимодействием между системными пакетами.
sudo apt install python3-venv python3 -m venv my-env source my-env/bin/activate pip install <package-name>
-
Используйте pipx для установки однопользовательских приложений: Если вы планируете установить консольные приложения, вы можете использовать pipx. Он автоматически создает виртуальное окружение для каждого приложения, что исключает конфликты.
sudo apt install pipx pipx install <app-name>
-
Тем не менее, если необходимо использовать pip для установки в /usr/local, действуйте осторожно: Если вы решите использовать флаг
--break-system-packages
, будьте внимательны. Этот флаг позволяет установить пакеты в /usr/local, но может привести к конфликтам. Используйте команду:sudo pip install --break-system-packages --prefix=/usr <package-name>
Убедитесь, что вы тщательно проверяете, какие зависимости используются в пакетах, чтобы избежать ситуации, когда pip-пакеты затеняют системные.
3. Заключение
Таким образом, несмотря на изменения в Python 3.12, вы все еще можете выполнять установку пакетов в /usr/local, однако это требует аккуратного подхода и полной осведомленности о потенциальных конфликтах. Всегда полезно делать резервные копии и внимательно следить за зависимостями пакетов. Помните, что в большинстве случаев использование apt или venv является более безопасным и надежным решением, чем смешивание системных и упакованных зависимостей с помощью pip в глобальной среде.