2019-01-24

PBR - "Разумная" сборка Python-пакетов

Начнём с теории, а уже потом перейдём к практике.

link Wheel

Стандарт Wheel (описан в PEP-427) в 2012-ом году пришёл на замену Egg, и с тех пор стал самым популярным форматом для распространения готовых пакетов. Говоря простым языком, wheel-пакет - это ZIP-архив, с расширением .whl, в который упаковано всё, что необходимо для работы приложения или библиотеки на языке Python. Достаточно извлечь все файлы, которые хранятся внутри этого .whl-архива с помощью стандартного архиватора и можно работать с привычными .py файлами и ресурсами для них.

Естественно, в большинстве случаев требуется установка зависимостей, или какая-то иная работа в конечном окружение. Для этого в менеджер зависимостей pip была добавлена поддержка wheel-пакетов.

При вызове следующей команды:

    pip install requests
  

pip сделает следующее:

  • скачает с PyPI необходимый *.whl-файл (учтя платформу и архитектуру системы)
  • распакует содержимое архива в соответствующие директории
  • скомпилирует .py в платформо-зависимые .pyc
  • установит необходимые зависимости

За выполнение большей части работы по установке библиотеки отвечает пакет setuptools.

Настройки, необходимые для установки пакета, хранятся в двух файлах:

  • setup.py - содержит функции и параметры необходимые для установки пакета
  • setup.cfg - хранит значения по умолчанию для аргументов команд объявленных в setup.py

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

Кроме вышеописанных файлов, wheel-пакет может включать в себя дополнительные ресурсы: ChangeLog (список изменений в проекте), файл AUTHORS, подробное описание пакета и тд.

link PBR

Для снижения объёма "ручной" работы при подготовке wheel-пакета, разработчики из OpenStack подготовили специализированный инструмент - PBR (Python Build Reasonableness). PBR выполняют следующую работу:

  • генерирует версию пакета на основание git-лога
  • формирует файл AUTHORS на основание git-лога
  • генерирует файл ChangeLog на основание git-лога
  • формирует manifest на основание файлов в папке .git и нескольких стандартных файлов
  • генерирует заметки к релизу, используя reno
  • сохраняет зависимости пакета в requirements.txt
  • использует файл README для заполнения параметра long_description
  • локализует все пакеты расположенные ниже корневой директории
  • генерирует Sphinx Autodoc файлы для всего модуля

link Использование

Вся прелесть работы с PBR заключается в простоте его использования.

Для сборки пакета необходимо создать файлы setup.py и setup.cfg в корневой директории проекта.

Пример setup.py (можно использовать без изменений):

    #!/usr/bin/env python

from setuptools import setup

setup(
    setup_requires=['pbr'],
    pbr=True,
)
  

Пример setup.cfg:

    [metadata]
name = project-name

[files]
packages = project-name

[entry_points]
console_scripts =
    script-name = python.module:main
  

Следующие атрибуты файла setup.cfg нужно привести в соответствие с вашими проектом:

  • project-name - имя пакета
  • script-name - имя стартового скрипта, будет доступно как команда для запуска после установки пакета
  • package.subpackage.module:main - путь до функции main, расположенной в модуле по пути package/subpackage/module.py

Сборку проекта можно запустить, вызвав команду:

    python setup.py bdist_wheel
  

Результатом выполнения команды будет файл с расширением *.whl в директории ./dist/. Например: ./dist/project-name-0.0.1.dev195-py3-none-any.whl

Можно установить этот wheel-пакет, просто скопировав его на нужный компьютер, и запустить pip install, передав путь до файла.

Например:

    pip install ./dist/project-name-0.0.1.dev195-py3-none-any.whl
  

После установки wheel-пакета в систему, можно будет вызвать команду, которую мы объявили в setup.cfg:

    script-name
  

Это приведёт к запуску функции main из package.subpackage.module.

Выше описанный сценарий использования PBR может помочь при сборке Docker-образов и публикации пакетов на внутренний или основной PyPI.

Если вас заинтересовала тема затронутая в этой статье, рекомендую ознакомиться со следующими материалами: