Сборка дистрибутивов Python с помощью build
Сборка Python проектов с помощью build
Инструмент build (пакет build) представляет собой стандартный способ генерации дистрибутивов Python пакетов. Он использует спецификацию pyproject.toml для определения бэкенда сборки и создаёт исходные архивы (sdist) и колеса (wheel) в папке dist/.
Установка
Установка выполняется через pip:
pip install buildPython build (сборка python-проектов с помощью build)
Базовая команда
Для сборки проекта необходимо перейти в корневую директорию (где лежит pyproject.toml) и выполнить:
python -m build
После выполнения в папке dist/ появятся файлы имя_проекта-версия.tar.gz и имя_проекта-версия-py3-none-any.whl.
Минимальная конфигурация pyproject.toml
Для использования setuptools в качестве бэкенда:
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
Если файл pyproject.toml отсутствует, build всё равно попытается собрать проект, используя legacy поведение (вызов setup.py), но это не рекомендуется.
Пошаговое пояснение
buildчитает[build-system]изpyproject.toml.- Устанавливает зависимости, указанные в
requires, в изолированное виртуальное окружение (по умолчанию). - Вызывает бэкенд (например,
setuptools.build_meta) для создания сначала sdist, затем из него wheel. - Помещает результаты в
dist/.
Цель использования – универсальная и повторяемая сборка, соответствующая PEP 517/518. Применяется для публикации на PyPI, тестирования дистрибутивов и интеграции в CI/CD.
Типичная ошибка: Missing build-backend
Если в pyproject.toml не указан build-backend, build может завершиться с ошибкой:
ERROR Backend 'setuptools' is not available
Решение: добавить в [build-system] строчку build-backend = "setuptools.build_meta" (или другой бэкенд).
Как собрать только wheel или только sdist?
По умолчанию создаются оба дистрибутива. Для выбора одного из них используются флаги --wheel или --sdist:
python -m build --wheel
python -m build --sdist
Результат: в папке dist/ окажется только один файл соответствующего формата. Это удобно, когда требуется только колесо для быстрой установки или только исходный архив для аудита.
Проблема: при использовании --sdist может возникнуть ошибка, если бэкенд не поддерживает создание sdist (например, некоторые минимальные бэкенды). В таком случае следует убедиться, что выбранный бэкенд поддерживает оба формата.
Как настроить сборку с другим бэкендом (Flit, Hatch, Poetry)?
Достаточно изменить секцию [build-system] в pyproject.toml. Команда python -m build остаётся той же.
Для Flit:
[build-system]
requires = ["flit_core"]
build-backend = "flit_core.buildapi"
Для Hatch:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Для Poetry (через poetry-core):
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Ошибка: если бэкенд не установлен, build автоматически загрузит его из requires в изолированное окружение. Однако при использовании --no-isolation нужно предварительно установить бэкенд в текущее окружение.
Как ускорить сборку, избегая изоляции?
Флаг --no-isolation отключает создание временного изолированного окружения. Сборка выполняется в текущем окружении, что быстрее, но требует предустановленных зависимостей.
python -m build --no-isolation
Если какая-либо зависимость из requires отсутствует, сборка завершится с ошибкой ModuleNotFoundError. Решение: установить все необходимые пакеты заранее (pip install setuptools wheel и т.д.).
Как изменить выходную директорию?
Параметр --outdir (или -o) позволяет указать другую папку для готовых дистрибутивов:
python -m build --outdir ./build_output
Результат: файлы будут помещены в ./build_output/ вместо ./dist/.
Как использовать build со старым проектом без pyproject.toml?
build поддерживает legacy сборку, основанную на setup.py. Если pyproject.toml отсутствует, команда python -m build автоматически переключится на поведение, аналогичное python setup.py sdist bdist_wheel.
# В проекте есть setup.py, но нет pyproject.toml
python -m build
Однако рекомендуется добавить pyproject.toml для явного указания бэкенда и зависимостей сборки.
При legacy сборке могут возникнуть предупреждения о депрекации. Для чистого опыта стоит создать минимальный pyproject.toml.
Как автоматизировать сборку в CI (GitHub Actions)?
Пример рабочего процесса для GitHub Actions:
# .github/workflows/build.yml
name: Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install build
run: pip install build
- name: Build package
run: python -m build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
После каждого пуша создаются дистрибутивы, которые можно скачать или использовать для публикации.
Расширенные примеры использования build
Пример pyproject.toml с динамической версией (setuptools-scm)
Использование setuptools-scm позволяет извлекать версию из git тегов.
[build-system]
requires = ["setuptools>=64", "setuptools-scm>=8"]
build-backend = "setuptools.build_meta"
[project]
name = "mypackage"
dynamic = ["version"]
[tool.setuptools_scm]
Выполняем сборку:
git tag v1.0.0
python -m build
Результат (версия из тега):
mypackage-1.0.0.tar.gz, mypackage-1.0.0-py3-none-any.whl
Если тегов нет, версия будет вычислена из коммита (например, 1.0.0.dev1+gabc1234).
Сборка C-расширений с scikit-build-core
scikit-build-core – современный бэкенд для проектов с нативным кодом на базе CMake.
[build-system]
requires = ["scikit-build-core>=0.9"]
build-backend = "scikit_build_core.build"
[project]
name = "mycextension"
version = "0.1.0"
Предположим, в проекте есть каталог src/ с кодом на C. Сборка:
python -m build
Результат – колесо с платформенной меткой, например mycextension-0.1.0-cp311-cp311-linux_x86_64.whl.
Ошибка: если CMake не установлен, сборка прервется. Решение: установить CMake и компилятор (gcc, MSVC).
Программная сборка с использованием build.api
Модуль build предоставляет API для интеграции сборки в собственные скрипты.
from build import ProjectBuilder
from build.env import DefaultIsolatedEnv
import tempfile
# Создаем временную директорию для вывода
with tempfile.TemporaryDirectory() as tmpdir:
builder = ProjectBuilder('/path/to/project')
with DefaultIsolatedEnv(builder) as env:
env.install(builder.build_system_requires)
env.install(builder.get_requires_for_build('wheel'))
builder.build('wheel', tmpdir, env)
print('Wheel built in', tmpdir)
Результат: в tmpdir появится файл колеса. Такой подход используется в инструментах непрерывной интеграции или в сложных рабочих процессах.
Сборка с пользовательским скриптом предварительной обработки
Можно комбинировать build с любыми пре- и пост-скриптами, например, для генерации кода.
# prepare_build.sh
#!/bin/bash
python generate_code.py
python -m build
Выполнение:
bash prepare_build.sh
Такой скрипт можно включить в Makefile или в конфигурацию CI.
Сборка с проверкой лицензий (hatch-licenses)
Для бэкенда Hatch доступны плагины, например hatch-licenses, который собирает информацию о лицензиях зависимостей.
[build-system]
requires = ["hatchling", "hatch-licenses"]
build-backend = "hatchling.build"
[tool.hatch.licenses]
include = ["dependencies"]
После сборки в дистрибутив будет включён файл с лицензиями. Команда python -m build остаётся неизменной.
Сборка с указанием версии Python и платформы (cross-compilation)
Хотя build сам не кросскомпилирует, можно использовать переменные окружения для контроля. Например, для сборки колеса под другой интерпретатор с помощью cibuildwheel, который внутри использует build.
# Пример конфигурации pyproject.toml для cibuildwheel
[tool.cibuildwheel]
build = "cp311-*"
# Внутри cibuildwheel вызывает: python -m build --wheel
Это расширенный сценарий для много платформенной публикации.