Как собрать PEX-файл с подмодулями Python для публикации
Узнайте, как упаковать проект Python с подмодулями в один исполняемый PEX-файл, используя флаг -f и точку входа, чтобы обеспечить успешную дистрибуцию.
Как упаковать проект Python, содержащий подмодули, в один PEX‑файл для распространения?
Мой проект имеет следующую структуру:
<folder>\
project.py
submodule1\
file1.py
file2.py
submodule2\
file3.py
...
Запуск python project.py из каталога работает нормально, но я хочу раздавать проект как один исполняемый файл с помощью PEX.
Я пробовал следующие подходы безуспешно:
-
pex -r requirements.txt -o x.pex– это создаёт виртуальное окружение с нужными пакетами, но не включает исходный код моего проекта. -
pex -r requirements.txt -c whateverиpex -r requirements.txt -e whatever– тоже не дали ожидаемого результата. -
После добавления
setup.pyя выполнилpex . -o x.pex, но всё равно не могу запустить программу с опциями-cили-e.
Есть ли простой способ создать PEX‑файл, который объединит как исходники проекта, так и виртуальное окружение, чтобы он работал так же, как python project.py? Например:
pex -r requirements.txt project.py -o x.pex
Какой правильный подход для упаковки проекта Python с подмодулями в один PEX‑файл, который можно запустить напрямую?
Чтобы упаковать проект Python с подмодулями в один PEX‑файл, необходимо использовать правильную структуру команды, которая включает ваш локальный код проекта и задаёт корректную точку входа. Ключевой момент – сообщить PEX включить текущий каталог (.), установить точку входа в ваш основной модуль и включить все зависимости.
Правильный подход:
pex -f . -r requirements.txt -e project -o myproject.pex
Затем запустите его:
./myproject.pex
Содержание
- Понимание основ упаковки PEX
- Настройка структуры проекта
- Правильная структура команды PEX
- Опции конфигурации точки входа
- Устранение распространённых проблем
- Продвинутые техники для сложных проектов
Понимание основ упаковки PEX
PEX (Python EXecutable) – это самодостаточные Python‑приложения, которые объединяют ваш код и все зависимости в один исполняемый файл. В отличие от предыдущих попыток, ключевой момент – явно указать PEX включить локальный код проекта с помощью флага -f (find‑links).
Согласно документации PEX, флаг -f «обеспечивает включение текущего каталога в путь поиска, что позволяет загружать локальные модули». Именно поэтому предыдущие попытки не сработали – они не включали ваш локальный код в PEX‑файл.
По умолчанию
bdist_pexсоздаёт исполняемый файл, используя консольный скрипт с тем же именем, что и пакет.
Настройка структуры проекта
Для того чтобы структура вашего проекта корректно работала с PEX, необходимо убедиться, что она соответствует стандартным соглашениям Python‑пакетирования. Ваша структура в порядке, но стоит добавить файл setup.py в корень:
<folder>/
setup.py
project.py
submodule1/
__init__.py
file1.py
file2.py
submodule2/
__init__.py
file3.py
requirements.txt
setup.py должен выглядеть так:
from setuptools import setup, find_packages
setup(
name="myproject",
version="0.1.0",
packages=find_packages(),
install_requires=[
# зависимости перечислены здесь или в requirements.txt
],
entry_points={
'console_scripts': [
'myproject=project:main',
],
},
)
Как отмечено в руководстве по упаковке Python, «необходимо включить корректный setup.py для ваших модулей. Это необходимо, чтобы указать точку входа приложения».
Правильная структура команды PEX
Базовая структура команды
Основная команда для правильной упаковки вашего проекта:
pex -f . -r requirements.txt -e project -o myproject.pex
Разберём каждый компонент:
-f .– критически важно! Это указывает PEX включить текущий каталог в путь поиска, делая локальные модули доступными.-r requirements.txt– указывает файл зависимостей.-e project– задаёт точку входа в модульproject(илиproject:main, если у вас конкретная функция).-o myproject.pex– указывает имя выходного файла.
Альтернативные форматы точки входа
Вы можете задать точку входа разными способами, как указано в документации PEX:
- Точка входа в модуль:
-e project(запускает модуль). - Точка входа в функцию:
-e project:main(запускает функциюmainвproject.py). - Консольный скрипт:
-c myproject(использует консольный скрипт, определённый вsetup.py).
Согласно Stack Overflow, «Чтобы задать точку входа в .py файл при создании PEX, используйте -c command!».
Опции конфигурации точки входа
Опция 1: Точка входа в модуль
Если ваш project.py содержит код, который можно запустить как модуль:
pex -f . -r requirements.txt -e project -o myproject.pex
Запуск:
./myproject.pex
Опция 2: Точка входа в конкретную функцию
Если у вас есть конкретная функция в project.py:
pex -f . -r requirements.txt -e project:main -o myproject.pex
Запуск:
./myproject.pex
Опция 3: Точка входа в консольный скрипт
Используя подход с консольным скриптом и setup.py:
pex -f . -r requirements.txt -c myproject -o myproject.pex
Запуск:
./myproject.pex
Как объясняется в документации PEX, «проекты, указывающие console_scripts в своей конфигурации, могут создавать автономные исполняемые файлы для этих точек входа».
Устранение распространённых проблем
Проблема: Отсутствие локальных модулей
Проблема: В вашем PEX‑файле отсутствует код проекта.
Решение: Всегда используйте -f ., чтобы включить текущий каталог. Согласно исследованиям, «это было сложно понять по нескольким причинам. Изучив документацию, я смог вывести, что правильная команда в моём случае должна выглядеть примерно так: pex .».
Проблема: Точка входа не найдена
Проблема: Вы получаете ошибки «module not found» при запуске PEX.
Решение: Убедитесь, что синтаксис точки входа правильный:
- Используйте
-e projectдля всего модуля. - Используйте
-e project:mainдля конкретной функции. - Проверьте, что имя модуля соответствует структуре файлов.
Проблема: Подмодули недоступны
Проблема: Подмодули не импортируются при запуске из PEX.
Решение: Убедитесь:
- Каждый подмодуль имеет файл
__init__.py. - Точка входа корректно импортирует и использует подмодули.
- Вы используете
-f ., чтобы включить весь локальный код.
Как отмечено в GitHub issues, «я не могу динамически импортировать подмодули внутри PEX, потому что моя функция обнаружения ищет локальную файловую систему, а не папки внутри PEX».
Продвинутые техники для сложных проектов
Множественные точки входа
Если вам нужны несколько точек входа, укажите их в setup.py:
entry_points={
'console_scripts': [
'tool1=project:function1',
'tool2=submodule1:function2',
],
}
Использование PEX_PATH для внедрения модулей во время выполнения
Для сложных сценариев вы можете использовать переменную окружения PEX_PATH, как упомянуто в документации PEXI: «Добавлена поддержка переменной окружения PEX_PATH, которая позволяет объединять среды PEX во время выполнения. Это можно использовать для внедрения плагинов, точек входа или модулей из одного PEX в другой без явной сборки их вместе».
Создание из виртуального окружения
Если у вас уже есть виртуальное окружение, вы можете заморозить его в PEX:
pex -r <(pip freeze) -f . -e project -o myproject.pex
Как отмечено в документации PEX, «вывод pip freeze (список закреплённых зависимостей) можно передать напрямую в pex. Это удобно для заморозки виртуального окружения в PEX‑файл».
Заключение
Чтобы успешно упаковать ваш Python‑проект с подмодулями в один PEX‑файл:
- Используйте
-f .– это самый критический шаг, который вы пропустили. - Настройте правильные точки входа с помощью
-e project:mainили-c myproject. - Включите
setup.pyс корректной конфигурацией пакета. - Используйте правильную структуру команды:
pex -f . -r requirements.txt -e project:main -o myproject.pex. - Проверьте ваш PEX, чтобы убедиться, что все подмодули доступны.
Ключевой вывод: PEX требует явных инструкций для включения вашего локального кода. Без -f . он будет упаковывать только зависимости, но не ваш фактический проект. После освоения этого шаблона вы сможете создавать надёжные, портативные Python‑исполняемые файлы, которые работают точно так же, как python project.py, но со всеми зависимостями в одном файле.