Как упаковать Python код в дистрибутив: обзор методов
Основные подходы к сборке
Как собрать пакет с помощью современного инструмента python -m build?
Стандартный способ сборки пакетов, рекомендованный PEP 517 и PEP 518, предполагает использование модуля build. Он позволяет создавать как исходные дистрибутивы (sdist), так и колеса (wheels) на основе конфигурации из файла pyproject.toml.
Пошаговая инструкция
- Установите пакет build:
pip install buildPip upgrade package python (обновление пакета через pip)
- Создайте файл pyproject.toml в корне проекта (пример ниже).
- Выполните команду сборки из корня проекта:
python -m buildPython pip update package (обновление пакета через pip update)
- Готовые дистрибутивы появятся в папке dist/.
Пример минимального pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mypackage"
version = "0.1.0"
description = "Пример простого пакета"
authors = [{name = "Иван Иванов", email = "ivan@example.com"}]
readme = "README.md"
requires-python = ">=3.8"
Python build package (сборка пакета python)
После выполнения команды python -m build в папке dist/ появятся файлы mypackage-0.1.0.tar.gz и mypackage-0.1.0-py3-none-any.whl.
Типичные проблемы и их решение:
- Ошибка "ModuleNotFoundError: No module named 'build'" - забыли установить пакет build. Решение: выполните pip install build.
- Ошибка синтаксиса в pyproject.toml - например, неправильно указана версия Python. Проверьте формат TOML (используйте двойные кавычки для строк, квадратные скобки для таблиц).
- Сборка завершается, но пакет не содержит нужных файлов - отсутствует MANIFEST.in или не настроено включение дополнительных файлов. Добавьте в pyproject.toml секцию [tool.setuptools.packages.find] или явно укажите пакеты.
Цель использования: создание универсальных дистрибутивов, совместимых с современными индексами пакетов (PyPI). Рекомендуется для новых проектов.
Вариант 1: Традиционный setup.py
Как собрать пакет с помощью скрипта setup.py?
Классический метод, который работает, если в проекте присутствует файл setup.py с вызовом функции setup() из setuptools. Для сборки используются команды sdist и bdist_wheel.
# setup.py
from setuptools import setup, find_packages
setup(
name='mypackage',
version='0.1.0',
packages=find_packages(),
install_requires=[],
)
Python download package (скачивание пакета python)
Команды для сборки:
python setup.py sdist bdist_wheel
Python pip install local package (установка локального пакета через pip)
Возможные проблемы:
- Команда bdist_wheel может отсутствовать, если не установлен пакет wheel. Установите его: pip install wheel.
- При использовании с современными версиями setuptools может потребоваться явно указать pyproject.toml даже при наличии setup.py.
Случаи использования: проекты, требующие выполнения произвольного кода в процессе сборки (например, генерация файлов). В современных проектах рекомендуется постепенно переходить на pyproject.toml.
Вариант 2: Настройка через setup.cfg
Как собрать пакет, используя декларативную конфигурацию в setup.cfg?
Альтернатива setup.py - файл setup.cfg, который содержит метаданные и конфигурацию. При этом в проекте всё равно должен присутствовать минимальный setup.py для обратной совместимости.
# setup.cfg
[metadata]
name = mypackage
version = 0.1.0
description = Пример пакета
[options]
packages = find:
Python install package version (установка пакета определенной версии в python)
Минимальный setup.py:
from setuptools import setup
setup()
модули python linux (модули python в linux)
Сборка выполняется аналогично: python setup.py sdist bdist_wheel или python -m build (если добавлен pyproject.toml).
Цель: разделение конфигурации и кода, упрощение поддержки.
Вариант 3: Использование pyproject.toml без setup.py
Как собрать пакет, используя только pyproject.toml, без setup.py?
Полностью современный подход, соответствующий PEP 517/518. В pyproject.toml указываются система сборки и метаданные, а setup.py не требуется.
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mypackage"
version = "0.1.0"
description = "Пакет без setup.py"
Сборка выполняется командой python -m build. Этот метод особенно удобен для проектов, не требующих динамической генерации.
Ошибки:
- Если в pyproject.toml отсутствует обязательная секция [project], сборка завершится с ошибкой ValueError. Проверьте наличие полей name и version.
Расширенные примеры сборки пакетов
Пример 1: Сборка с указанием дополнительных файлов через MANIFEST.in
Если пакет содержит не только .py-файлы, но и статические ресурсы (изображения, конфиги), их необходимо явно включить.
# MANIFEST.in
include README.md
include mypackage/data/*.json
recursive-include mypackage/templates *
После добавления MANIFEST.in повторите сборку:
python -m build
# Результат: файлы из MANIFEST.in попадают в sdist и wheel
Пример 2: Сборка только исходного дистрибутива (sdist)
Иногда требуется только tar.gz. Используйте флаг --sdist:
python -m build --sdist
# В папке dist/ появится только mypackage-0.1.0.tar.gz
Пример 3: Сборка с указанием версии из переменной окружения
Можно передать версию динамически, используя скрипт, который изменяет pyproject.toml перед сборкой. Например, с помощью sed:
#!/bin/bash
VERSION="0.2.0"
sed -i "s/version = \".*\"/version = \"$VERSION\"/" pyproject.toml
python -m build
Пример 4: Сборка пакета с зависимостями, указанными в pyproject.toml
[project]
dependencies = [
"requests>=2.25",
"click>=8.0",
]
В процессе сборки зависимости не устанавливаются, они будут подтянуты при установке пакета через pip. Сборка проходит стандартно.
Пример 5: Использование альтернативного бэкенда сборки (Flit)
Вместо setuptools можно применить Flit, который требует меньше конфигурации.
# pyproject.toml
[build-system]
requires = ["flit_core>=3.2"]
build-backend = "flit_core.buildapi"
[project]
name = "mypackage"
version = "0.1.0"
Сборка:
python -m build
Такой подход подходит для простых пакетов без сложных расширений на C.
Пример 6: Сборка пакета с нативным расширением (C extension) через setuptools
# setup.py (обязательно для расширений)
from setuptools import setup, Extension
module = Extension('mypackage.hello', sources=['hello.c'])
setup(
name='mypackage',
version='0.1.0',
ext_modules=[module],
)
Сборка:
python setup.py build_ext --inplace
python -m build
Результат - колесо, содержащее скомпилированный бинарный модуль под конкретную платформу.
Пример 7: Проверка содержимого собранного колеса
python -m build
cd dist
unzip -l mypackage-0.1.0-py3-none-any.whl
Archive: mypackage-0.1.0-py3-none-any.whl
Length Date Time Name
--------- ---------- ----- ----
0 12-01-2025 10:00 mypackage/__init__.py
165 12-01-2025 10:00 mypackage/__init__.py
...
Это позволяет убедиться, что в дистрибутив попали все нужные файлы.