[!NOTE] Автоматический перевод Эта статья была автоматически переведена с оригинальной английской версии.

pyproject.toml Руководство: пакетизация в Python, зависимости и настройка инструментов

старые проекты на Python часто размещают конфигурацию по всему кодовому базу setup.py, setup.cfg, файлы с требованиями, MANIFEST.in, а также отдельные файлы для инструментов разработки. pyproject.toml это предоставляет таким проблемам единое пространство для обсуждения, хотя оно и не заменяет все проектные файлы и не делает каждый раздел частью единого стандарта.

В данном руководстве рассматривается файл поэтапно — от параметров конфигурации сборки до метаданных проекта и настроек инструментов. Для обеспечения понятности его структуры рекомендуется выделить четыре группы ответственных лиц: те, кто осуществляет сборку проекта, те, кто публикует его результаты, те, кому необходимы локальные ресурсы для работы над проектом, и те, кто настраивает отдельные инструменты.

Кратко. Используйте. [build-system] для бэкенд, отвечающего за сбор дистрибутива, [project] для опубликованных метаданных и требований рантайм. [dependency-groups] для непубликуемых сред разработки, и [tool.*] Только там, где это прямо указано в документации данного инструмента. Декларация зависимостей — это не файл блокировки версий.

Один файл, четыре владельца

Четыре границы принадлежности в pyproject.toml

Три стандарта упаковки определили основную структуру:

Авторы инструментов также могут зарезервировать пространство имён ниже. [tool]. Эта область является традиционной, а не универсальной: каждый инструмент определяет собственные ключи и способы работы.

Вот небольшая упакованная библиотека:

[build-system]
requires = ["hatchling>=1.26"]
build-backend = "hatchling.build"

[project]
name = "weather-client"
version = "0.1.0"
description = "A small weather API client"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
  "httpx>=0.27",
]

[project.optional-dependencies]
cli = ["rich>=13"]

[project.scripts]
weather = "weather_client.cli:main"

[dependency-groups]
test = ["pytest>=8", "pytest-cov>=5"]
lint = ["ruff>=0.12"]

[tool.pytest.ini_options]
testpaths = ["tests"]

[tool.ruff]
line-length = 100
target-version = "py311"

Каждый список зависимостей отвечает на свой вопрос. Именно это различие является ключевым элементом файла.

[build-system]: как исходный код превращается в дистрибутив

сборка фронтенд подобная этой python -m buildpip, uv или другие инструменты запускают процесс сборки бэкенд. Сам бэкенд определяет, как исходный код преобразуется в формат sdist или wheel, а также какие файлы будут включены в эти результаты сборки.

[build-system]
requires = ["hatchling>=1.26"]
build-backend = "hatchling.build"

requires В этом репозитории присутствуют зависимости, необходимые для запуска бэкенд в его изолированной среде сборки. Они не входят в список зависимостей рантайм для вашего пакета.

Объявляется система сборки в тех случаях, когда проект генерирует дистрибутив или требует установки собственного кода в виде пакета. Проекты, не являющиеся пакетами, всё равно могут ею пользоваться. pyproject.toml; PEP 735 даже разрешает наличие файла, содержащего исключительно группы зависимостей. Менеджеры среды отличаются по способу обработки проектов без системы сборки, поэтому решение по этому вопросу следует принимать осознанно.

Выберите бэкенд из требований к сборке:

Скопируйте текущую рекомендуемую таблицу бэкенд из его документации. Не добавляйте ничего. wheel Чтобы формировать требования на основе привычки, бэкенд определяет, что необходимо.

[project]: данные, получаемые потребителями метаданных

Этот [project] Таблица отражает структуру распределения: её название, версию, совместимость с Python, зависимости рантайм, точки входа в приложение и другие метаданные индекса.

[project]
name = "weather-client"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["httpx>=0.27"]

Спецификаторы зависимостей представляют собой ограничения для резолвера, а не условия снапшот конкретной среды. Они включаются в метаданные форматов wheel и sdist, что позволяет установщикам нижнего уровня объединять их с требованиями из других пакетов.

Дополнительные компоненты представляют собой публичный интерфейс установки.

[project.optional-dependencies] определяет дополнительные параметры, которые могут быть запрошены потребителями:

[project.optional-dependencies]
cli = ["rich>=13"]
postgres = ["psycopg[binary]>=3.2"]

Потребитель может установить weather-client[cli]. Поскольку публикуются дополнительные названия и требования, рассматривайте их как функциональные возможности продукта. Не используйте дополнительные именованные элементы. dev исключительно для хранения инструментов всех участников разработки.

Точки входа связывают установленные команды с интерпретатором Python

[project.scripts]
weather = "weather_client.cli:main"

После установки дистрибутива среда становится доступной для использования. weather, которое импортирует и вызывает weather_client.cli:main. Тестируйте команду с использованием готового пакета в формате wheel, а не только из корня репозитория — именно этот wheel и поступает к пользователям.

[dependency-groups]: локальные, непубликованные среды

Группы зависимостей согласно PEP 735 предназначены для описания сред разработки или неявляющихся пакетами сред без их публикации в качестве метаданных пакета.

[dependency-groups]
test = ["pytest>=8", "pytest-cov>=5"]
lint = ["ruff>=0.12"]
dev = [
  { include-group = "test" },
  { include-group = "lint" },
]

Это правильный предел для тестов, инструментов проверки кода, генераторов документации и подобных инструментов для участников разработки. Он также полезен для приложений или ноутбуков, которые не создают распространяемую версию.

Группы зависимостей представляют собой стандартизированные данные, однако интерфейсы установщиков по-прежнему различаются. Определите, как менеджер среды, выбранный вами, производит их установку, блокировку и разрешение. PEP 735 не содержит определения универсального интерфейса командной строки.

[tool.*]: конфигурация, принадлежащая одному инструменту

Таблицы инструментов не имеют общей схемы:

[tool.pytest.ini_options]
addopts = "-ra"
testpaths = ["tests"]

[tool.ruff]
line-length = 100

использовать [tool.*] Таблицы включаются лишь в том случае, если это прямо описано в документации инструмента. Некоторые настройки по‑прежнему сохраняются в отдельных файлах: это связано с тем, что они используются другой экосистемой, требуют другого формата, или их структура выглядит более понятной в изолированном виде. pyproject.toml это точка координации, а не требование к централизации всего.

Клиенты конфигурации, работающие с файлом pyproject.toml

Декларации, блокировки и файлы требований решают разные задачи

Наиболее частой причиной путаницы является рассмотрение каждого артефакта зависимостей как потенциального источника истины, конкурирующего с другими.

АртефактОсновная цельТипичное содержимое
[project.dependencies]Опубликован контракт рантаймПрямые требования и допустимые диапазоны
[project.optional-dependencies]Опубликованные функции с возможностью активации пользователемДополнительные функции для конечных пользователей
[dependency-groups]Непубликованные локальные средыгруппы тестирования, проверки формата кода, документации или приложений
файл блокировкиВоссоздать среду с уже решёнными зависимостямиТочные версии, источники и метаданные разрешения
requirements.txtвходные данные для установки совместимой с pipТребования вместе с опциями, ограничениями, URL-адресами или хэшами, специфичными для инструмента pip

Библиотека обычно публикует совместимые ограничения и тесты, относящиеся к определённому диапазону версий. Приложение же, как правило, сохраняет файл блокировки менеджера среды. Точные версии компонентов должны указываться в готовом артефакте деплой, а не просто в публичных метаданных библиотеки.

Сохраняйте файл с требованиями в тех случаях, когда интеграция требует формата или функционала pip. Если проект, управляемый uv, нуждается в таком файле, экспортируйте его из файла lock вместо того, чтобы поддерживать два независимых набора зависимостей:

uv export --format requirements.txt --output-file requirements.txt

Экспорт представляет собой результат генерации совместимого формата. Исходный код остается финальной версией, используемой в данном рабочем процессе.

Миграция, сохраняющая поведение системы

Миграция с упором на верификацию в формат pyproject.toml

Не начинайте с удаления. setup.py или requirements.txt. Сначала определите, какую функцию выполняет каждый существующий файл.

  1. Логика сборки инвентаря, метаданные, требования к рантайм, дополнительные элементы, среды разработки, настройки инструментов, данные пакетов и точки входа.
  2. Выбор бэкенд, способного воспроизвести текущую структуру включения файлов, скомпилированные результаты и возможность редактирования установленных версий.
  3. Перенос статических опубликованных метаданных в [project]; обязательно указывайте те поля, которые действительно являются динамическими.
  4. Переместите требования, предназначенные исключительно для участников, в [dependency-groups], без публичных дополнений.
  5. Перемещайте настройки инструмента только туда, где он поддерживает эквивалентную семантику.
  6. Соберите как sdist, так и wheel, проверьте их содержимое и установите wheel в чистую среду.
  7. Запустите точки входа, тесты, проверки импорта и сам путь деплой.
  8. Удаляйте старые конфигурации только после того, как результаты сборки и поведение совпадут.

MANIFEST.in В некоторых конфигурациях setuptools он всё ещё может понадобиться, а также в небольших случаях. setup.py Это может оставаться действительным для программного режима сборки. Модернизация представляет собой смену владельца, а не соревнование за удаление файлов.

Современный рабочий процесс обработки ультрафиолетом

uv различает приложения и библиотеки при создании проекта:

# Non-library application template
uv init weather-app

# Packaged library with a src layout and build system
uv init --lib weather-client

uv init создаёт файлы проекта. Первая операция с проектом, такая как uv run, uv sync, или uv lock создаёт файл блокировки и персистентные данные .venv по мере необходимости.

cd weather-client
uv add httpx
uv add --group test pytest pytest-cov
uv run pytest
uv build

В настоящее время uv помещает требования к локальной разработке в стандартизированные группы зависимостей. Его встроенный механизм uv_build бэкенд представляет собой один из вариантов для проектов, написанных исключительно на Python; для компилируемых расширений требуется соответствующая альтернатива, такая как maturin или scikit-build-core.

Заключение

pyproject.toml Всё становится понятно, когда у каждой таблицы есть одна целевая аудитория. Реализация изоляции относится к [build-system]. Опубликованное поведение относится к [project]. Среды разработчиков относятся к [dependency-groups]. Переключатели инструментов принадлежат тому инструменту, который их определяет.

Как только эти границы становятся стабильными, файл становится проще для анализа, и во время миграций больше не возникает путаницы между метаданными пакетов и конфигурацией среды, определённой на конкретном устройстве.

Список литературы