Лучший способ поделиться своим проектом Python и позволить другим установить его — создать и распространить пакет.
Например, чтобы поделиться библиотекой с другими разработчиками для использования в своих приложениях или для таких инструментов разработки, как «py.test».
Преимуществом этого метода распространения является хорошо зарекомендовавшая себя экосистема таких инструментов, как PyPI и pip , которые позволяют другим разработчикам легко загружать и устанавливать ваш пакет либо для случайных экспериментов, либо как часть больших профессиональных систем.
Упаковка в этом контексте означает две вещи: создание пакета + распространение пакета.
В этой статье я расскажу о лучших практиках создания пакета Python.
То, что следует ниже, справедливо, если вы пишете простой пакет, такой как чистый пакет Python. Если у вас есть пакет Python с более сложными потребностями, вам все равно следует использовать сборки на основе pyproject.toml и настроить метаданные проекта, как указано ниже. Однако при выборе серверной части у вас могут возникнуть дополнительные соображения.
Что такое пакет Python?
Пакеты Python — это, по сути, пакеты кода Python (обычно в виде сжатого файлового архива) в определенном формате, который можно распространять среди других людей и устанавливать с помощью такого инструмента, как pip .
В настоящее время в основном используются два типа пакетов Python:
- Пакеты исходного кода ( .tar.gz): снимок исходного кода с файлом манифеста, который включает такие метаданные, как имя, версия, сводка, автор и т. д.
- Пакеты колес ( .whl): улучшение формата Egg и теперь наиболее рекомендуемый формат.
Теперь вопрос в том, как нам объединить наш исходный код в распространяемый пакет Python? Продолжайте читать, чтобы узнать, как (и лучший способ!).
Что же тогда представляют собой « новые стандарты »? Что ж… приветствуем упаковку на основе pyproject.toml !
Строительство по «старым стандартам» и почему этого следует избегать
«Старым» способом вы используете сторонний инструмент (обычно setuptools) вместе с файлами setup.py и setup.cfg для сборки вашего пакета (по сути, это синяя часть на диаграмме ниже).
Это так же просто, как выполнить следующую команду:
Где sdist означает распространение исходного кода, а bdist_wheel , ну… это означает двоичный пакет, использующий формат колеса.
Пока все так просто, правда? Но подождите… каковы две основные проблемы «старой» процедуры строительства?
Помните, что «старым» способом упаковки был файл setup.py . Вы должны написать вызов функции setup, импортированной из пакета setuptools, которая определяет все метаданные вашего пакета.
Во-первых, это были неструктурированные данные! Вам пришлось запустить этот скрипт Python setup.py , чтобы даже прочитать эти данные, поскольку они были указаны в коде. Это было сложнее, чем должно было быть, и не было большого количества направляющих для предотвращения плохой практики. Поскольку это был сценарий, люди могли писать произвольный код для динамического выполнения произвольных действий .
Другая проблема с файлами setup.py заключалась в зависимостях во время сборки.
Рассмотрим следующую ситуацию: допустим, у вас есть пакет, для сборки которого требуется PyTorch с расширениями C++ и CUDA. Вы можете импортировать данные из факела в свой setup.py . Это означало, что вам нужно было установить Torch в своей среде, прежде чем вы сможете получить pip installпакет из исходного кода. Хуже того, простого указания torch в качестве обязательной зависимости было недостаточно! Даже размещения факела вместе с вашим пакетом в requirements.txtфайле было недостаточно! Pip не смог даже проверить зависимости этого пакета: pip нужно было бы запустить setup.py, чтобы получить зависимости, но setup.py не смог запуститься, потому что ему нужно импортировать torch. Зачем вам нужно устанавливать зависимости и запускать код только для того, чтобы прочитать кучу статических метаданных? Почему для установки пакета Python требуется так много шагов? Кроме того, если вам нужны были определенные зависимости только для сборки, а не во время выполнения, вашим пользователям будет неприятно устанавливать и использовать эти зависимости в своих средах.
По этой и другим причинам вам следует создавать пакет Python с использованием новых стандартов.
Строительство по «новым стандартам»
«Новые стандарты» относятся к стандартизированному способу указания метаданных пакета (таких как имя пакета, автор, зависимости) в файле pyproject.toml и способу создания пакетов из исходного кода с использованием этих метаданных (называемому серверной частью ) . . Вы часто видите это под названием «сборки на основе pyproject.toml».
Эти два компонента основаны на двух основных PEP (предложениях по улучшению Python), которые по сути представляют собой проектные документы о новых стандартах или функциях Python. Это PEP 517 и PEP 621 .
Pyproject.toml и PEP 621
Этот pyproject.tomlфайл действует как файл конфигурации для инструментов, связанных с упаковкой (а также других инструментов). Он содержит метаданные пакета, такие как имя пакета, автор, зависимости и т. д.
Файл pyproject.tomlнаписан на TOML . В настоящее время указаны три таблицы (способ TOML для ссылки на раздел), а именно [build-system] , [project] и [tool] . Остальные таблицы зарезервированы для использования в будущем ( [tool]таблица должна использоваться в конфигурации конкретного инструмента).
Определение того, что подпадает под это, [project]стандартизирует PEP 621.
Серверная часть и PEP 517
Вы можете задаться вопросом: что такое серверная часть?
Бэкэнд — это программа, которая читает ваш pyproject.tomlисходный код и фактически превращает его в архив пакета, который можно установить или распространить. Интерфейс — это просто пользовательский интерфейс (обычно программа командной строки), который вызывает серверную часть .
- Примеры интерфейсов: pip, build, поэтика, люк, pdm, flit.
- Примеры бэкэндов: setuptools (>=61), поэтическое ядро, инкубатор, pdm-бэкэнд, flit-core.
Разделение этих двух частей в рабочем процессе сборки означает, что в принципе вы можете смешивать и сочетать интерфейсы и серверы. Но это пища для следующего поста :-)
Чтобы использовать конкретный бэкэнд, просто включите в свой раздел «build-system» pyproject.toml, который выглядит следующим образом:
В приведенном выше примере в качестве бэкэнда используется flit. Проверьте документацию выбранного вами бэкэнда, чтобы узнать, как указать его в файле pyproject.toml . Ниже вы можете увидеть некоторые примеры серверной части и способы их указания в файле pyproject.toml .
В PEP 517, среди прочего, указаны обязательные перехватчики (такие как build_wheel или build_sdist). По сути, это интерфейс, который должен реализовать серверная часть.
Таким образом, серверные части, реализующие спецификацию PEP 517, обычно называются «бэкэндами PEP 517».
Теперь вопрос: как мне выбрать серверную часть сборки?
Если вы пишете простой пакет на чистом Python, вы получите более или менее тот же результат с любым сервером, совместимым как с PEP 517 ( [build-system]), так и с PEP 621 ( [project]).
Однако, на мой взгляд, есть два основных момента, которые должны определить, какой бэкэнд вы выберете:
- Дополнительные функции, связанные с процессом сборки, такие как настройка того, какие дополнительные файлы будут включены в собранный пакет, запуск кода во время сборки и способы обработки заполнения динамических полей. Наиболее часто поддерживаемое динамическое поле — это версия пакета; многие серверные части поддерживают чтение из исходного кода или системы контроля версий репозитория. Если вам нужны или нужны такие функции, вам понадобится серверная часть сборки, которая их поддерживает. Затем вам нужно будет установить для него конфигурацию, специфичную для серверного инструмента pyproject.toml. Например, вы можете включить это в свой код pyproject.toml, чтобы сообщить hatchlingсерверной части, как включать или исключать файлы из вашей сборки:
- Интеграция с внешними системами , которые предоставляют дополнительные функции управления проектами и рабочими процессами. Многие из этих серверных частей тесно связаны с мощными программами управления рабочими процессами. Примеры: поэзия/поэзия-ядро, люк/хатчлинг, pdm/pdm-backend. Эти интерфейсы на самом деле делают гораздо больше, чем просто служат интерфейсом для процесса сборки. Многие из них представляют собой комплексные инструменты управления рабочими процессами для проектов Python. Они включают в себя такие функциональные возможности, как:
- Создание и управление виртуальными средами.
- Команды для управления и установки ваших зависимостей.
- Файлы блокировки зависимостей
- Команды для загрузки вашего пакета в PyPI.
Ниже вы можете увидеть пример полного файла pyproject.toml, использующего PDM в качестве бэкэнда.
Как вы видете:
- Проект соответствует PEP 621 (раздел [project]).
- Серверная часть — это PDM, которая представляет собой серверную часть PEP 517 (раздел [build-system]).
- Есть специфические особенности сборки (разделы[tool.pdm.*]
Краткое содержание
Если вы хотите создать пакет Python, используя современные стандарты упаковки:
- Объявите серверную часть сборки в [build-system]таблице вашего pyproject.tomlфайла.
- Объявите метаданные вашего проекта в [project]таблице вашего pyproject.tomlфайла.
Чтобы выбрать серверную часть для использования:
- Если у вас простой проект, это не имеет большого значения. Выберите любой бэкэнд, поддерживающий PEP 517 и PEP 621. В настоящее время популярные варианты включают flit-core, Hatchling, pdm-backend и setuptools (>=61). На момент написания Poetry соответствует стандарту PEP 517, но не соответствует PEP 621.
- Если вам нужны более сложные функции сборки, сравните функции, специфичные для сборки, которые настраиваются в [tool.*]таблицах pyproject.toml.
- Если вам нужен комплексный инструмент рабочего процесса, который управляет другими вещами, такими как виртуальные среды и зависимости, сравните инструменты по этим функциям. Poetry, Hatch и PDM в настоящее время довольно популярны, хотя Poetry еще не соответствует всем стандартам.
Лично мне нравится PDM по разным причинам. Он совместим как с PEP 517, так и с PEP 621 и предоставляет удобные функции во время сборки, а также мощный интерфейс с несколькими вариантами управления рабочими процессами.
Надеюсь, это помогло прояснить текущий статус стандартов упаковки в Python и… удачной упаковки! :-)
Тут можно посмотреть интересные статьи по Python.
Спасибо, что прочитали статью.
Буду благодарен, если подпишитесь на канал и поделитесь статьей в социальных сетях.