В Python 3.8 предлагается добавить альтернативу виртуальным окружениям — локальную директорию с пакетами PEP 582 Python local packages directory.
Данный PEP предлагает добавить в Python механизм автоматического обнаружения директории __pypackages__
и использовать её при импорте в качестве источника установленных пакетов. Директория __pypackages__
будет иметь больший приоритет при импорте, чем глобальные или пользовательские директории с пакетами. Это позволит исключить создание, активацию или деактивацию виртуальных окружений.
Вот так будет выглядеть в Python 3.8 структура пакета с использованием __pypackages__
:
foo
__pypackages__
3.8
lib
bottle
myscript.py
В статье я расскажу как использовать локальную директорию с пакетами не дожидаясь выхода Python 3.8.
В статье описан базовый пример, проверенный в Linux, Python 3.5. Для других платформ, возможно, понадобится внести изменения.
Установка пакетов в локальную директорию
Установка почти не отличается от обычной установки пакетов с помощью pip, за исключением дополнительной опции --target
. В ней указываем полный или относительный путь до директории с локальными пакетами.
pip3 install --target="$PWD/__pypackages__/3.5/lib/" bar
$PWD — переменная с текущей рабочей директорией.
Будет создано следующее дерево директорий:
foo
__pypackages__
3.5
lib
bar
myscript.py
Версию Python и вложенные директории приходиться указывать вручную.
Так же могут возникнуть проблемы, если нужно установить пакеты с бинарным кодом и под разные архитектуры. У меня таких пакетов не было, но как решение можно добавить еще архитектуру в структуру директорий.
Есть еще один способ установки пакетов в конкретную директорию :
pip3 install --ignore-installed --install-option="--prefix=$PWD/__pypackages__" --install-option="--no-compile" bar
Но нужно обязательно указывать полный путь до места установки и дерево директорий будет отличаться от предложенной в PEP 582:
foo
__pypackages__
lib
python3.5
site-packages
bar
myscript.py
Использование локальной директории с пакетами
После установки пакетов осталось указать интерпретатору где искать зависимости.
Для этого нужно внести в список sys.path
путь до локальной директории с пакетами. Добавить путь достаточно в главный (загружаемый первым) модуль, в остальные добавлять не обязательно. После этого можно импортировать установленные локально пакеты.
import os
import sys
_PATH = '/__pypackages__/3.5/lib/'
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + _PATH)
import bar
Единственное условие — главный модуль должен быть на том же уровне вложенности, что и директория __pypackages__
.
Еще один способ указать Python, где искать пакеты — это выставить переменную окружения перед запуском скрипта.
PYTHONPATH="$PWD/__pypackages__/3.5/lib/:$PYTHONPATH" python3 ./myscript.py
Таким нехитрым способом можно добиться схожего с PEP 582 функционала уже сейчас.
Автор: arghhh