{"id":29925488,"url":"https://github.com/expressapp/bot-template","last_synced_at":"2025-08-02T11:39:10.345Z","repository":{"id":38240452,"uuid":"377831551","full_name":"ExpressApp/bot-template","owner":"ExpressApp","description":"Шаблон проекта для создания новых ботов","archived":false,"fork":false,"pushed_at":"2025-08-01T14:45:09.000Z","size":703,"stargazers_count":8,"open_issues_count":3,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-08-01T16:36:39.839Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ExpressApp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-17T12:59:15.000Z","updated_at":"2025-05-07T12:12:21.000Z","dependencies_parsed_at":"2023-02-19T10:01:19.434Z","dependency_job_id":"635f8385-685d-4c4a-a35e-71fb0a4cfb91","html_url":"https://github.com/ExpressApp/bot-template","commit_stats":null,"previous_names":["expressapp/async-box"],"tags_count":86,"template":false,"template_full_name":null,"purl":"pkg:github/ExpressApp/bot-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fbot-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fbot-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fbot-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fbot-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ExpressApp","download_url":"https://codeload.github.com/ExpressApp/bot-template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fbot-template/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268380008,"owners_count":24241168,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-02T11:37:14.082Z","updated_at":"2025-08-02T11:39:10.324Z","avatar_url":"https://github.com/ExpressApp.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bot Template Tutorial\n \n## Введение\n\n\u003e :information_source: Инфо  \n\u003e Для взаимодействия с платформой **botx** используется библиотека **[pybotx](https://github.com/ExpressApp/pybotx)**. В **[документации](https://pypi.org/project/pybotx/)** можно посмотреть примеры её использования. Перед прочтением данного туториала следует с ней ознакомиться.\n\n----\n\nВне зависимости от решаемых ботами задач, во всех повторяется один и тот же код.\n\nЧтобы разработчикам не приходилось писать базовый однообразный код для каждого нового бота, существует шаблонный проект - Bot Template. Он задает структуру проекта и основной стек технологий. Это значительно упрощает разработку, позволяя сконцентрироваться на реализации бота.\n\n----\n\n\n## 1. Развертывание из шаблона и структура проекта\n\nДля развертывания проекта необходимо установить [copier](https://github.com/copier-org/copier) и выполнить команду:\n```bash\n$ copier bot-template bot-example\n```  \n\nСтруктура шаблонного бота состоит из нескольких следующих пакетов и модулей:\n\n```\n.\n├── app\n│   ├── api            - реализация http роутов для приложения, включая необходимые для бота\n│   ├── bot            - команды бота и вспомогательные функции для них\n│   ├── caching        - классы и функции для работы с in-memory БД\n│   ├── db             - модели, функции для работы с БД и миграции\n│   ├── resources      - текстовые или файловые ресурсы бота\n│   ├── schemas        - сериализаторы, енамы, доменные модели\n│   ├── services       - сервисы с логикой (бизнес-логика)\n│   ├── logger.py      - логгер\n│   ├── main.py        - запуск сервера с инициализацией необходимых сервисов\n│   └── settings.py    - настройки приложения\n├── scripts            - скрипты для запуска тестов, форматеров, линтеров\n├── tests              - тесты, структура которых соответствует структуре проекта, и хелперы для них\n├── poetry.lock        - конфигурация текущих зависимостей. используется для их установки\n├── pyproject.toml     - конфигурация зависимостей, мета информация проекта (название, версия, авторы и т.п.)\n└── setup.cfg          - конфигурация линтеров и тестов\n```\n\n## 2. Запуск проекта\n\n### Настройка окружения\n\n1. Устанавливаем зависимости проекта через [poetry](https://github.com/python-poetry/poetry#poetry-dependency-management-for-python):\n```bash\n$ poetry install\n```\n2. Определяем переменные окружения в файле **`.env`**. Примеры переменных окружения находятся в файле **`example.env`**.\n3. Запускаем `postges` и `redis` используя [docker-compose](https://docs.docker.com/compose/):\n```bash\n$ docker-compose -f docker-compose.dev.yml up -d\n```\n4. Применяем все миграции для инициализации таблиц с помощью [alembic](https://alembic.sqlalchemy.org/en/latest/tutorial.html):\n```bash\n$ alembic upgrade head\n```\n5. Запускаем бота как приложение [FastAPI](https://fastapi.tiangolo.com/tutorial/) через [gunicorn](https://fastapi.tiangolo.com/deployment/server-workers/?h=gunicorn#run-gunicorn-with-uvicorn-workers).\nФлаг `--reload` используется только при разработке для автоматического перезапуска сервера при изменениях в коде:\n```bash\n$ gunicorn \"app.main:get_application()\" --worker-class uvicorn.workers.UvicornWorker\n```\nПо необходимости добавить флаг `--workers` и их колличество, в данном случае 4 рабочих процесса:\n```bash\n$ gunicorn \"app.main:get_application()\" --worker-class uvicorn.workers.UvicornWorker --workers 4\n```\n\n----\n\n## 3. Добавление нового функционала\n\n### 3.1. Команды бота\n\n#### Структура пакета команд\nКоманды бота находятся в пакете **`app.bot.commands`** и группируются в отдельные модули в зависимости от логики. Команды добавляются с помощью [коллекторов pybotx](https://expressapp.github.io/pybotx/development/collector/). \n\nОсновные команды, такие как `/help` и системные команды, находятся в модуле **`common.py`**. Для команд, относящихся к определенной задаче, создается свой модуль. Например, для интеграции с Atlassian Jira будет создан модуль **`jira.py`**. В результате структура пакета **`app.bot.commands`** будет выглядеть так:\n\n```\nbot\n├── commands\n│   ├── common.py\n│   ├── jira.py \n```\n\nЕсли в модуле становится слишком много команд, следует разбить его на новые модули и сложить в один пакет с названием старого модуля. Например, так:\n\n```\nbot\n├── commands\n│   ├── common.py\n│   ├── jira\n│       ├── projects.py\n│       ├── issues.py\n```\n\n\n#### Регистрация команд\nДля добавления модуля с командами нужно импортировать `collector` в **`app/bot/bot.py`** и добавить его в инстанс бота: \n```python3\nfrom app.bot.commands import common \n\nbot.include_handlers(common.collector)\n```\n\n----\n\n### 3.2. Взаимодействие с БД\n\n#### Создание новых моделей\n\nВзаимодействовать с новыми таблицами можно через модели [sqlalchemy](https://www.sqlalchemy.org/). С примерами использования можно ознакомиться [тут](https://www.sqlalchemy.org/library.html#tutorials). Модели располагаются в пакете **`app.db.package_name`**. Там же хранятся `crud` функции и [репозитории](https://gist.github.com/maestrow/594fd9aee859c809b043). Структура пакета выглядит следующим образом: \n```\n├── app\n│   ├── db \n│       ├── migrations\n│       ├── exampleapp\n│           ├── repo.py - репозиторий/crud функции\n│           ├── models.py - модели таблиц\n```\n\nПример модели:\n``` python\nfrom sqlalchemy import Column, Integer, String\nfrom app.db.sqlalchemy import Base\n\nclass ExampleModel(Base):\n    __tablename__ = \"examples\"\n\n    id: int = Column(Integer, primary_key=True, autoincrement=True)\n    text: str = Column(String)\n```  \n\nПример репозитория:\n``` python\nfrom sqlalchemy import insert\nfrom app.db.sqlalchemy import session\nfrom app.db.example.models import ExampleModel\n\nclass ExampleRepo:\n    async def create(self, text: str) -\u003e None:\n        query = insert(ExampleModel).values(text=text)\n        async with session.begin():\n            await session.execute(query)\n```\n\n#### Создание новых миграций\n\nДля генерации миграций используется [alembic](https://alembic.sqlalchemy.org/en/latest/). Все файлы миграции хранятся в директории **`app.db.migrations`**. Для генерации новой миграции необходимо создать модель `sqlalchemy` и выполнить команду:\n\n```bash\n$ alembic revision --autogenerate -m \"migration message\"\n```\n\nНовый файл миграции будет создан в следующей директории:\n```\n├── app\n│   ├── db \n│       ├── migrations\n│           ├── versions\n│               ├── 0123456789ab_migration_message.py\n```\n\nЧтобы применить все миграции, следует выполнить команду:\n```bash\n$ alembic upgrade head\n```\nили:\n```bash\n$ alembic upgrade 1\n```\nдля применения только одной миграции.\n\nДля отмены одной миграции необходимо выолнить:\n```bash\n$ alembic downgrade -1\n```\n\n----\n\n### 3.3. Сервисы и бизнес-логика\n\nВся бизнес-логика проекта выносится в пакет  **`app.services`**. Бизнес-логика - логика, характерная только для данного проекта. Туда же выносятся запросы, клиенты для использования API сторонних сервисов, обработка данных по заданным (в ТЗ) правилам.\n\nСтруктура следующая:\n```\n├── app\n│   ├── services\n│   │     ├── errors.py - исключения, вызываемые в клиенте\n│   │     ├── client.py - клиент для обращения к стороннему сервису \n```\n\n----\n\n### 3.4. Конфиги и переменные среды\n\nНовые переменные среды можно добавить в класс `AppSettings` из файла `app/settings.py`. Если у переменной нет значения по умолчанию, то оно будет браться из файла `.env`.\nЧтобы использовать эту переменную в боте, необходимо:\n``` python\nfrom app.settings import settings\n...\nsettings.MY_VAR\n```\n\n\u003e :information_source: Инфо\n\u003e Через переменные среды можно указывать окружения, в которых будет запускаться бот. `test`, `dev` или `prod`. Просто добавьте в файл `.env` переменную `APP_ENV=prod`.\n\n----\n\n## 4. Линтеры и форматирование кода\n\n#### Запуск\nДля запуска всех форматеров необходимо выполнить скрипт:\n```bash\n$ ./scripts/format\n```\n\nДля запуска всех линтеров необходимо выполнить скрипт:\n```bash\n$ ./scripts/lint\n```\n\n#### Описание \n* [black](https://github.com/psf/black)\n\nИспользуется для форматирования кода к единому стилю: разбивает длинные строки, следит за отступами и импортами.\n\n\u003e :warning: Примечание  \n\u003e В некоторых моментах isort конфликтует с black. Конфликт решается настройкой файла конфигурации **`setup.cfg`**.\n\n* [isort](https://github.com/timothycrosley/isort)\n\nИспользуется для сортировки импортов. Сначала импорты из стандартных библиотек python, затем из внешних библиотек и в конце из модулей данного проекта.\nМежду собой импорты сортируются по алфавиту.\n\n* [autoflake](https://github.com/myint/autoflake)\n\nИспользуется для удаления неиспользуемых импортов и переменных.\n\n* [mypy](https://github.com/python/mypy)\n\nИспользуется для проверки типов. Помогает находить некоторые ошибки еще на стадии разработки. \n\n\u003e :warning: Примечание  \n\u003e К сожалению, не все библиотеки поддерживают типизацию. Чтобы подсказать это **mypy** необходимо добавить следующие строки в файл конфигурации **`setup.cfg`**:\n\n```\n[mypy]\n\n# ...\n\n[mypy-your_library_name.*]\nignore_missing_imports = True\n```\n\nНекоторые же наоборот имеют специальные плагины для **mypy**, например **pydantic**:\n\n```\n[mypy]\nplugins = pydantic.mypy\n\n...\n\n[pydantic-mypy]\ninit_forbid_extra = True\ninit_typed = True\nwarn_required_dynamic_aliases = True\nwarn_untyped_fields = True\n```\n\n* [wemake-python-styleguide](https://github.com/wemake-services/wemake-python-styleguide)\n\nИспользуется для комплексной проверки. Анализирует допустимые имена перменных и их длину, сложность вложенных конструкций, правильную обработку исключений и многое другое. Для каждого типа ошибок есть свой уникальный номер, объяснение, почему так делать не стоит, и объяснение, как делать правильно. Список ошибок можно посмотреть [тут](https://wemake-python-stylegui.de/en/latest/pages/usage/violations/index.html).\n\n\u003e :information_source: Инфо  \n\u003e В некоторых редких случаях можно игнорировать правила линтера. Для этого необходимо либо прописать комментарий с меткой `noqa` на проблемной строке:\n\u003e ```python3\n\u003e var = problem_function()  # noqa: WPS999 \n\u003e ```\n\u003e либо указать `ignore` ошибки в **`setup.cfg`**:\n\u003e ```\n\u003e [flake8]\n\u003e # ...\n\u003e ignore =\n\u003e     # f-strings are useful\n\u003e     WPS305,\n\u003e ```\n\u003e Также можно исключать модули и пакеты.\n\n\n----\n\n\n## 5. Тестирование\n\n\n\n### 5.1. Запуск и добавление тестов\n\nВсе тесты пишутся с помощью библиотеки [pytest](https://docs.pytest.org/en/latest/). Запустить тесты можно командой:\n\n```bash\n$ pytest\n```\n\nВо время тестирования поднимается docker-контейнер с БД. Порт выбирается свободный, поэтому запущенная локально БД не будет мешать. Если вы хотите запускать тесты используя вашу локальную БД, необходимо добавить в **`.env`** переменную `DB=1`, либо выполнить команду:\n```bash\n$ DB=1 pytest\n```\n\n\n\u003e :information_source: Инфо  \n\u003e Поскольку **pytest** не умеет в асинхронные тесты, для работы с ними ему необходим плагин **[pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio)**.\n\n### 5.2. Покрытие\n\nПокрытие показывает процент протестированного исходного кода, как всего, так и отдельных модулей. Покрытие помогает определить какие фрагменты кода не запускались в тестах. Для генерации отчетов покрытия используется плагин [pytest-cov](https://pytest-cov.readthedocs.io/en/latest/reporting.html).\n\nЧтобы не прописывать все флаги каждый раз, можно использовать эти скрипты:\n```bash\n$ ./scripts/test\n$ ./scripts/html-cov-test\n```\n\nПервый выводит отчет в терминале, второй генерирует отчет в виде `html`страниц с подсветкой непокрытых участков кода.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpressapp%2Fbot-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexpressapp%2Fbot-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpressapp%2Fbot-template/lists"}