Python Project Template
Иметь свои шаблон необходимо, но стоит сразу обратить внимание на то, что нужно добавлять туда, а что нет. В этой статье я расскажу какие преимущества использования шаблона проекта для Python и как его создать с помощью cookiecutter. Также я расскажу про структуру проекта и какие инструменты я использую в своем шаблоне и почему.
Создание шаблона проекта позволяет сэкономить время на настройку проекта, а также сделать его структуру более удобной для разработки. Базовые рутинные вещи должны быть вынесены в шаблон, например, конфигурация линтеров, иначе они будут переходить из проекта в проект, тянув за собой все исторические моменты предыдущего. Если вы хотите всегда держать уровень своих проектов, то вам следует сделать шаблон, который будет использоваться в будущем.
Cookiecutter
Пару слов про cookiecutter. Это инструмент, который позволяет создавать проекты из шаблонов. Шаблон представляет собой git репозиторий, в котором есть файл cookiecutter.json
, в котором описаны переменные, которые нужно будет заполнить при создании проекта. После заполнения переменных cookiecutter клонирует репозиторий и заменяет переменные на значения, которые вы ввели. Также cookiecutter может запустить скрипты, которые могут сделать какие-то дополнительные действия. Например, cookiecutter может создать git репозиторий, установить зависимости, запустить тесты, удалить лишние файлы и т.д.
Фичи, который мне не хватает это группа настроек. Например, я хочу сделать группу настроек для линтеров, чтобы можно было выбрать какие линтеры использовать или не использовать их вообще. Возможно в будущем такая фича появится.
Что должно быть в шаблоне?
Во-первых, нужно определиться для каких целей вам нужен шаблон проекта. Это может быть back-end приложение, библиотека или какая-нибудь игра. Я буду рассказывать только про шаблон для библиотеки.
Библиотеки Python — это файлы с шаблонами кода. Их создали для того, чтобы люди не набирали каждый раз заново один и тот же код.
Дальше определеитесь с набором инструментов, которые вы постоянно используете или хотели бы использовать. Это могут быть базовые библиотеки для проверки кода или запуска тестов. У этих ребят (PyCQA) есть то, что может вас заинтересовать.
Что еще можно добавить в проект:
- mypy
- black
- pyright
- ruff
- pytest
Пример готового шаблона
Я в какой-то момент захотел сделать свой шаблон проекта для Python. Вы можете найти его здесь.
Причина почему я сделал свой шаблон проекта, а не использовал готовый, заключается в том, что я хотел сделать его максимально простым и удобным для себя.
Что я хотел видеть в шаблоне проекта:
- Проверка кода: mypy, black
- Запуск тестов: pytest
- Публикация пакета в PyPI
- Публикация документации на Github Pages
Автоматические релизы
Этот процесс рутинный и его надо автоматизировать! Разработчики часто не хотят делать релизы, потому что нужно читать инструкции и делать все в правильном порядке. Потратив немного времени на атоматизации, вы сможете сэкономить намного больше в будущем.
Я эксперементировал с разными инструментами и добавлял их в шаблон проекта. Начинал с git-changelog, auto-changelog, gitlint и бампил версию с помощью poetry. Все это находилось в одной инструкции Makefile.
.PHONY: changelog
changelog:
auto-changelog -v $(v)
.PHONY: bump
bump:
poetry version $(v)
make changelog v=$(v)
git add . && git commit -m "bump: version $(v)"
git tag -m "" -a $(v)
Я случайно наткнулся на commitizen. Люблю github, всегда предлагает интересные проекты, а я их смотрю вместо постов из какой-либо сети.
Commitizen — тулза для автоматического изменения версии проекта в разных файлах, changelog-а и созданием тега в git. Чтобы она работала правильно, нужно использовать conventional commits. Хорошая практика, но нужно проверять каждый коммит, чтобы он соответствовал правилам. Себя я еще могу контролировать, но PR-ы от других людей могут нарушать условия. Поэтому я добавил джобу в github actions. Для локальной разработки можно использовать pre-commit и добавить туда проверку от commitizen, до него я использовал gitlint.
Плюсом к этому всему, джоба в гитхабе от commitizen может по триггеру автоматечески создавать коммит, ставить тэг и, таким образом, можно быстро проводить релизы. Триггером может служить мердж в мастер или ручной запуск джобы. Работая над разными проектами, понимаешь какие вещи нужно автоматизировать и просто добавляешь их в шаблон.
Проблема с Github Actions, которая меня немного напрягает, что гитхаб не триггерит какую-либо джобу после изменений, созданных другой джобой. Например, если commitizen создает релизный тег через джобу, то другая джоба не запустится, которая должна триггериться на новые теги. Разработчики гитхаба специально сделали такое поведение, чтобы не было какого-то автоматического конвейра, который может сломаться, если не провалидировать автоматизацию. Забаный факт, но такое поведение есть только, если вы используете токен, выписанный гитхаб для пуша новых коммитов. Если создатите токен своего аккаунта и будете использовать его вместо дефолтного, то джобы будут триггериться друг другом.
Публикацию пакета в pypi провожу с помощью poetry.
Poetry — это менеджер зависимостей
Тут тоже ничего сложного. Добавляю токен от pypi в github secrets. Рекомендую для каждой либы создавать отдельный токен, pypi так умеет. Далее по тригеру запускается джоба в github actions. Триггером обычно служит тэг новый версии, но вы можете запустить джобу руками. Далее poetry получает токен и делает всю работу по сборке и публикации пакета.
Cоздание changelog-а
Про changelog можно почитать на wiki.
Я понимал, что changelog можно генерировать из сообщений коммитов в репе. Хотя, здесь (keepachangelog) написано обратное.
Don’t let your friends dump git logs into changelogs.
Я согласен с ними, но я думаю грамотное оформление каждого коммита, может упростить ведение журнала изменений, одно должно дополнять другое. В начале я использовал git-changelog, но для меня минусом стало, что инструмент генерирует весь журнал с нуля, то есть "одно должно дополнять другое" уже не работает. Также, в некоторых проектах, где часть коммитов не соответствовала формату conventional commits, не было информации между версиями вообще. git-changelog собирал журнал только по тегам. И, чтобы создать список изменений, сначала нужно создать тэг, а потом только сгенерить changelog. Это было не красиво, так как в тэге пропадала информация из файла changelog, она появлялась только в следующем коммите.
Попробовал auto-changelog, в котором можно было передавать версию через аргумент и включать измененный файл в тэг.
Со временем commitizen полностью вытеснил их. Как раз в нем изменения о новой версии добавляются в файл, а не перетираются все. Также он сначала добавляет изменения в changelog, только потом ставит тэг.
Conventional commits
Тут коротко. Сразу добавляйте в проект эту практику. Самое главное добавьте проверку коммита в ci. Для этого следует все изменения заносить только через PR/MR. В своих проектах, где вы работаете один, вам поможет pre-commit, если вы любите сразу пушить в мастер ветку.
Сложная конфигурация проекта
В одном из pull request-ов в свой репозиторий, один парень сказал, что конфигурация репы очень сложная для проекта такого размера. Сложно не согласиться с этим. Конечно, для меня это кажется простым, потому что я придумал и создал его. Поэтому нужно все документировать до мелочей в файле CONTRIBUTING.md вашего проекта. Люди не должны гадать как работать с вашим проектом, даже если в нем использованы популярные практики из мира разработки.
Итог
В заключении, я рекомендую создавать и использовать шаблоны проектов у себя в команде или только для личных целей. По шаблону можно оценить каким практикам придерживается человек и на интервью или в резюме вы можете им поделиться, чтобы люди поняли вас лучше.