urfu-daddy/CONTRIBUTE.md

14 KiB
Raw Blame History

Инструкция по внесению изменений в проект.

Введение.

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

Все изменения исходного кода требуется совершать в тематических ветках, некоторые из них уже могут быть в проекте, например, feature/handlers для работы с командами и callback'ами бота, feature/docker для настройки развертки проекта через Docker. Если вы собираетесь сделать несколько независимых задач, то это следует делать в разных тематических ветках. Если ваша основная задача связана с другими аспектами проекта, например, требует изменений в докере, то вам следует делать эти изменения в тематической ветке вашей основной задачи, не следует дробить на ветки зависимости вашей основной ветки. Ветка - это именно указание основной тематики ваших изменений. Их названия не означают, что в них можно изменять только соответствующие модули проекта.

После завершения работы над изменениями следует создать PR на их внедрение в ветку develop . Так как в ветке develop всегда находится завершенный и рабочий код, это еще раз подчеркивает важность правильной работы с тематическими ветками. Изменения в них должны быть самостоятельны и не зависить от изменений в других ветка. Затем проходит проверка PR и если всё хорошо, то изменения будут приняты в develop .

Не забывайте синхронизировать вашу тематическую ветку с текущей веткой develop .

Помимо сливания в ветку develop изменений из тематических веток, в ней также допускаются коммиты хот-фиксы/фиксы, направленные на устранение любых неисправностей, уязвимостей, критических ошибок.

Когда задачи, намеченные на новый релиз проекта выполнены, версия проекта в ветке develop ещё раз тестируется и затем происходит слияние ветки develop и main с git-тегом, указывающим на новую версию проекта.

Про Python пакеты проекта.

  • Каждый файл __init__.py должен содержать в своей первой строке список __all__ = [...] с перечислением всех элементов, которые могут быть импортированы из этого пакета. То есть если пакет в своем __init__.py содержит 2 различные переменные и импорт 1 класса, которые должны быть из него импортированы, то их названия следует указать в __all__. Пакет - директория, содерщая в себе другие директории, Python-модули и имеющая файл __init__.py.

  • После __all__, но перед началом импортов всегда должно находится 2 пустых строки. Если дальше идет обычная переменная, то 1 строка, если класс, функция или что-то ещё, то тоже 2 строки.

  • В пакете не следует импортировать абсолютно все переменные из его подпакетов, только то, что действительно может потребоваться за пределами этого основного пакета. Так, пакет middlewares в своем __init__.py будет содержать только импорт функции для присоединения мидлвари к диспетчеру бота, с последующим указанием названия этой функции в __all__, вся остальная логика, зависимости и реализации мидлвари могут быть скрыты в других файлах пакета, или находится внутри его подпакетов, если в них нет необходимости для использования за рамками этого пакета.

  • Если вашему пакету требуются вспомогательные функции, то их можно указать в модуле utils.py и импортировать оттуда.

  • Внутри директории src/ содержатся папки для всех основных компонентов проекта, его основных пакетов. Внутри них могут быть как вспомогательные пакеты, так и простые папки, так и простые модули.

  • Относительные пути следует использовать только в случае, если мы имеем хотим импортировать в пакет его содержимое. В остальном случае требуется использовать полный путь, который начинается с объявления основного пакета. Например from bot.handlers import connect_routers.

Про инструменты.

  • Для запуска проекта требуется использовать пакетный менеджер uv. Для начала загрузите все зависимости проекта командой uv sync --dev --locked.

  • Для запуска проекта используйте uv run src/main.py, вы также можете запускать скрипты проекта с помощью команды uv run --script scripts/<название-скрипта>.py.

  • Из-за указания флага --dev при использовании uv sync, были загружены зависимости необходимые для разработки. К ним относится ruff - Python линтер, который проверяет основные ошибки при написании кода с помощью команды ruff check. А также pyrefly - type-checker, который проверяет, учитывают ли ваши сценарии для работы с кодом то, что переменная может иметь разные типы данных, в зависимости от ситуации. Так CallbackQuery не всегда имеет атрибут message. Проверка осуществляется с помощью pyrefly check.

Про написание кода.

  • Все основные правила написания кода заложены в настройки ruff, pyrefly.

  • Длина строки не больше 70 символов.

  • Названия переменных, классов, функций должны быть понятными, короткими. Всё по PEP8.

  • Код должен быть понятным и лаконичным, заглушки для ruff указываются только в случае острой/временной необходимости, или если его замечания не соответствуют действительности. Перед ними всегда должен стоять объясняющий комментарий с тегом # DEBUG: ...

  • Костыли, hard-code, заглушки должны содержать комментарий с тегом # FIXME: ...

  • Всегда указывайте для всех функций, какой тип они возвращают и какие типы параметров принимают.

  • Логируйте важные события, делайте лог ошибок, старайтесь не допускать дыр в поведении программы. Логирование совершается с помощью библиотеки loguru. Импорт логера следует делать так: from loguru import logger as loguru_logger. Никаких print(), только логирование.

Про структуру проекта.

urfu-daddy/
├── .gitignore # Список файлов для игнорирования гитом.
├── flake.nix # Файл для настроек окружения NixOS.
├── flake.lock # Закрепление версий зависимостей.
├── docker/ # Контейнеризация и создание Docker образа.
├── .dockerignore # Игнорирование файлов проекта для Docker.
├── logs/ # Папка для хранения логов.
├── scripts/ # Полезные скрипты для проекта.
│   └── pybabel.py # Работа с локализацией.
├── src/ # Основные ресурсы проекта.
│   ├── main.py # Запуск всех компонентов.
│   ├── bot/ # Бот для Telegram.
│   │   ├── __init__.py # Функция для запуска бота.
│   │   ├── handlers/ # Обработка всех ивентов.
│   │   │   ├── callbacks/ # Обработка запросов.
│   │   │   └── commands/ # Обработка комманд.
│   │   ├── middlewares/ # Мидлвари для диспетчера/роутеров.
│   │   ├── services/ # Взаимодействие с другими сервисами бота.
│   │   └── utils/ # Вспомогательные компоненты для для бота.
│   ├── config/ # Получение env-настроек, настройка логирования.
│   ├── database/ # Инициализация и настройка БД.
│   └── locales/ # Папка с локализацией проекта.
├── LICENSE # Лицензия проекта.
├── README.md # Описание проекта.
├── CONTRIBUTE.md # Этот файл.
├── pyproject.toml # Настройки инструментов для разработки.
├── .python-version # Закрепление версии Python для проекта.
└── uv.lock # Закрепление версий зависимостей проекта.
  • В директориях commands и callbacks для создания новых хендлеров, требуется только создание нового файла (или изменение текущего) с привязкой декоратора RouterRegistry.register к функции хендлера. Подробный пример смотрите в docstring декоратора. Подключение к роутеру и последующая привязка к диспетчеру Aiogram происходит автоматически. Если вы хотите объединить несколько Python-модулей в одну папку, то просто создайте её и переместите модули туда. Файл __init__.py создавать не требуется, он будет проигнорирован при импортировании настроек RouterRegistry для привязки к роутеру!

Про настройки для проекта (env-настройки, config).

  • В корне проекта должен находится файл .env.

  • В нем должны быть объявлены обязательные переменные (bot_token), а также опциональные переменные, если такие требуются.

  • Список всех обязательный переменных и опциональных переменных с их значениями можно найти в src/config/utils, класс Settings.

Про коммиты, PR, документацию.

  • Если вы предлагаете PR, то пишите краткое, но полное описание изменений (если вы обсудили их с командой) или развернутое описание (в ином случае).

  • Коммиты пишутся на английском языке и соответствуют соглашению о коммитах.

  • Докстинги на английском языке и соответствуют общепринятому соглашению (расширения для VSCode - python docstrings).

Небольшие уточнения.

  • Игнорируйте замечания pyrefly на то, что для config: Settings не объявлена обязательная переменная, он не понимает, что они получаются из .env файла.

И самое главное.

  • Делайте хорошо.
  • Плохо не делайте.