Сборка дистрибутивов Python с помощью build

Раздел: Разработка на Python -> Инструменты сборки

Сборка Python проектов с помощью build

Инструмент build (пакет build) представляет собой стандартный способ генерации дистрибутивов Python пакетов. Он использует спецификацию pyproject.toml для определения бэкенда сборки и создаёт исходные архивы (sdist) и колеса (wheel) в папке dist/.

Установка

Установка выполняется через pip:

pip install build

Python 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), но это не рекомендуется.

Пошаговое пояснение

  1. build читает [build-system] из pyproject.toml.
  2. Устанавливает зависимости, указанные в requires, в изолированное виртуальное окружение (по умолчанию).
  3. Вызывает бэкенд (например, setuptools.build_meta) для создания сначала sdist, затем из него wheel.
  4. Помещает результаты в 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

Это расширенный сценарий для много платформенной публикации.

Сборка Python-проектов с помощью build - comments

En
Python build (python)