Пакетирование и деплоймент
Этапы формирования дистрибутива
- Разработка
- Сборка генератов
- Тестирование
- Сборка дистрибутивов
- Публикация исходников
- Публикация дистрибутивов
- Генерат
- файл, получающийся в процессе сборки дистрибутива
- Целевой генерат: генерат, входящий в дистрибутив
- Промежуточный генерат: генерат, не входящий ни в какой дистрибутив
Генераты не хранятся в репозитории, однако некоторые из них (например, документация, скомпилированные переводы и т. п.) используются при публикации.
Автоматизация сборки
Как понятие «сборка» стало «оркестрацией»
Интерпретируемые ЯП ⇒ нет понятия сборки
- Малые проекты: всё вручную
- Большие проекты: всё на CI-сервере
- Документация
- Тесты
- Проверка синтаксиса
- Git hooks вместо сборки
Универсальный инструмент сборки
Классический вариант: Make (его даже использует Sphinx). Однако это off-python зависимость).
На примере DoIt
- Архитектура:
- Задания
- Действия
- Обновление генератов (зависимость на файлы)
- Есть возможность определять, что такое «новое»
- Составные задания (зависимость на задания)
- Задания
- Позволяет запускать задания на языке командной строки
- Часто используемые примитивы на python
Синтаксис Python (это и есть программа на Python)
В нашем случае нуждается в автоматизации:
- Сборка документации
- Обновление и компиляция переводов
- Запуск тестов (в т. ч. проверка стиля)
- Сборка исходного дистрибутива
- Сборка бинарного дистрибутива (собственно модуля)
- (ещё не сделано, но тоже нужно) Публикация:
- Бинарного дистрибутива
- Исходного дистрибутива
- Документации
Сборка
Немного истории:
- Античность
Distutils — встроенный в Python инструмент
Появление Python Packaging Authority
Setuptools — развитие Distutils
a. k. a. setup.py
Появление других инструментов сборки: Poetry, pip-tools, PyBuilder и т. п.
Сборка бинарных и исходных дистрибутивов
Что умеет pip install:
- Скачать исходники, собрать и установить их
- Нужны сборочные зависимости
В случае модулей на Си это может быть очень непросто
- ⇒ часто встречаются прихаканные в исходниках бинарники (например, скомпилированные переводы)
- Скачать готовый пакет
Публиковать нужно и то, и то (лицензия, вопросы доработки и т. п.)
Пример: python -m build и что он создаёт
- sdist
- wheel
Для того, чтобы вместе с модулем упаковать какие-то дополнительные файлы, например, скомпилированные переводы, необходимо:
- Чтобы после сборки эти файлы (неважно, генераты или нет) оказались в каталоге с модулем
В секции options.package_data файла setup.cfg описать, какие файлы какому пакету принадлежат
Для того, чтобы упаковать в исходный дистрибутив дополнительные файлы (переводы, тесты и т. п.), их надо перечислить в заготовке файла-манифеста MANIFEST.in. Некоторые файлы включаются автоматически.
- Имеет смысл проследить за тем, чтобы в исходном дистрибутиве было всё, что лежит в репозитории
Пакетные зависимости
- Эксплуатационные зависимости
- Набор модулей, необходимых для эксплуатации приложения
- Обязательные и предполагаемые
- Включённые в python-инфраструктуру и все остальные
- Сборочные зависимости
Набор модулей и ПО, необходимый для разработки
+ Средства сборки
+ Средства тестирования
- Возможно, часть эксплуатационных зависимостей замещена квазиобъектами
Отслеживание зависимостей
- Скопировать в чистое окружение и тупо запускать и добавлять в зависимости всё, из-за отсутствия чего падает)
Сделать pip freeze и угадать, что из этого всего понадобится при запуске
Соблюдать дисциплину с помощью pipenv:
Для установки чего не попадя — pip install что ни попадя
Для установки эксплуатационных зависимостей — pipenv install эксплуатационные зависимости (записывается в Pipfile; pipenv install работает даже если был сделан pip install)
Для установки сборочных зависимостей — pipenv install -d сборочные зависимости)
Эксплуатационные зависимости
Хранятся в setup.cfg
- можно отследить по наличию import-ов в модуле.
В т. ч. автоматически: pymin-reqs или pip-check-reqs
- Сборочные зависимости
Хранятся в pyproject.toml, потому что определяют инструменты сборки
Можно отследить путём трассировки import-ов. ш
Но инструмента такого, похоже, нет!
Прототип инструмента, отслеживающего сборочные заивсимости
Matches filepaths to pip package. скрестить с PYTHONVERBOSE=import …
Недостаток: you must not use pip’s internal APIs in this way
Пример такого инструмента: pip запускается из командной строки. Выдаёт довольно адекватную информацию, как минимум про репозиторий с примером
Составить словарь: какому из установленных пакетов какой файл принадлежит ( эта задача почему-то ещё не решена)
Учитывать только пакеты, установленные непосредственно, а не по зависимостям (например, с помощью pip list --not-required)
Запустить все инструменты сборки и тестирования с трассировкой (PYTHONVERBOSE=import python … или python -v …)
- Проанализировать журнал трассировки на предмет использования файлов, принадлежащих пакетам из локального окружения
Возможны ситуации, когда для сборки требуется инструмент, который был поставлен автоматом по зависимости, а то, что его требовало, для сборки не нужно.
Строгие VS нестрогие зависимости на версии
- Для публикации: скорее всего, нестрогие
- Для разработки (особенно совместной) — лучше строгие
Точки входа
Для запуска python -m модуль в нём должен присутствовать __main__.py
Для создания стартового сценария в setup.cfg необходимо описать точки входа
Пример
Д/З
- Обеспечить в семестровом проекте сборку wheel и установку из wheel (с полной функциональностью)
- Если для деплоймента проекта wheel неудобен, обосновать это, и разработать и автоматизировать свою схему деплоймента