{"id":29925502,"url":"https://github.com/expressapp/pybotx-fsm","last_synced_at":"2025-08-02T11:39:12.243Z","repository":{"id":37853781,"uuid":"377121140","full_name":"ExpressApp/pybotx-fsm","owner":"ExpressApp","description":"Конечный автомат (Finite State Machine) для ботов на базе библиотеки pybotx","archived":false,"fork":false,"pushed_at":"2025-07-14T22:24:10.000Z","size":230,"stargazers_count":4,"open_issues_count":8,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-15T03:09:27.218Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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-15T10:19:02.000Z","updated_at":"2025-05-30T15:10:29.000Z","dependencies_parsed_at":"2024-01-01T17:28:53.408Z","dependency_job_id":"794dd657-6a63-4686-83bc-7f78c108b19c","html_url":"https://github.com/ExpressApp/pybotx-fsm","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/ExpressApp/pybotx-fsm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fpybotx-fsm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fpybotx-fsm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fpybotx-fsm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fpybotx-fsm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ExpressApp","download_url":"https://codeload.github.com/ExpressApp/pybotx-fsm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpressApp%2Fpybotx-fsm/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268380009,"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:16.184Z","updated_at":"2025-08-02T11:39:12.215Z","avatar_url":"https://github.com/ExpressApp.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pybotx-fsm\n\n[![codecov](https://codecov.io/gh/ExpressApp/pybotx-fsm/branch/master/graph/badge.svg?token=JWT9JWU2Z4)](https://codecov.io/gh/ExpressApp/pybotx-fsm)\n\nКонечный автомат (Finite state machine) для ботов на базе библиотеки\n[pybotx](https://github.com/ExpressApp/pybotx).\n\n\n## Возможности\n\n* Лёгкое создание графа состояний и их переключений.\n* Передача данных в следующее состояние при явном вызове перехода.\n\n\n## Подготовка к установке\n\nДля работы библиотеки необходим Redis, который уже встроен в последние версии\n[коробки](https://github.com/ExpressApp/async-box).\n\n\n## Установка\nИспользуя `poetry`:\n\n```bash\npoetry add pybotx-fsm\n```\n\n## Работа с графом состояний\n\n1. Создайте `enum` для возможных состояний автомата:\n\n```python #fsm_init\nfrom enum import Enum, auto\n\nfrom pybotx_fsm import FSMCollector\n\n\nclass LoginStates(Enum):\n    enter_email = auto()\n    enter_password = auto()\n\n\nfsm = FSMCollector(LoginStates)\n```\n\n\n2. Добавьте экземпляр автомата в мидлвари для того, чтобы бот мог использовать его:\n\n```python #fsm_usage\nBot(\n    collectors=[\n        myfile.collector,\n    ],\n    bot_accounts=[\n        BotAccountWithSecret(\n            # Не забудьте заменить эти учётные данные на настоящие,\n            # когда создадите бота в панели администратора.\n            id=UUID(\"123e4567-e89b-12d3-a456-426655440000\"),\n            cts_url=\"cts.example.com\",\n            secret_key=\"e29b417773f2feab9dac143ee3da20c5\",\n        ),\n    ],\n    middlewares=[\n        FSMMiddleware([myfile.fsm], state_repo_key=\"redis_repo\"),\n    ],\n)\n```\n\n3. Добавьте в `bot.state.{state_repo_key}` совместимый redis репозиторий:\n\n```python #noqa\nbot.state.redis_repo = await RedisRepo.init(...)\n```\n\n\n4. Создайте обработчики конкретных состояний:\n\n```python #fsm_state_handlers\n@fsm.on(LoginStates.enter_email)\nasync def enter_email(message: IncomingMessage, bot: Bot) -\u003e None:\n    email = message.body\n\n    if not check_user_exist(email):\n        await bot.answer_message(\"Wrong email, try again\")\n        return\n\n    await message.state.fsm.change_state(LoginStates.enter_password, email=email)\n    await bot.answer_message(\"Enter your password\")\n\n\n@fsm.on(LoginStates.enter_password)\nasync def enter_password(message: IncomingMessage, bot: Bot) -\u003e None:\n    email = message.state.fsm_storage.email\n    password = message.body\n\n    try:\n        login(email, password)\n    except IncorrectPasswordError:\n        await bot.answer_message(\"Wrong password, try again\")\n        return\n\n    await message.state.fsm.drop_state()\n    await bot.answer_message(\"Success!\")\n```\n\n5. Передайте управление обработчику состояний из любого обработчика сообщений:\n\n```python #fsm_change_state\n@collector.command(\"/login\")\nasync def start_login(message: IncomingMessage, bot: Bot) -\u003e None:\n    await bot.answer_message(\"Enter your email\")\n    await message.state.fsm.change_state(LoginStates.enter_email)\n```\n\n\n## Примеры\n\n### Минимальный пример бота с конечным автоматом\n\n```python #fsm_sample\n# Здесь и далее будут пропущены импорты и код, не затрагивающий\n# непосредственно pybotx_fsm\nclass FsmStates(Enum):\n    EXAMPLE_STATE = auto()\n\n\nfsm = FSMCollector(FsmStates)\n\n\n@collector.command(\"/echo\", description=\"Echo command\")\nasync def help_command(message: IncomingMessage, bot: Bot) -\u003e None:\n    await message.state.fsm.change_state(FsmStates.EXAMPLE_STATE)\n    await bot.answer_message(\"Input your text:\")\n\n\n@fsm.on(FsmStates.EXAMPLE_STATE)\nasync def example_state(message: IncomingMessage, bot: Bot) -\u003e None:\n    user_text = message.body\n    await message.state.fsm.drop_state()\n    await bot.answer_message(f\"Your text is {user_text}\")\n\n\nbot = Bot(\n    collectors=[\n        collector,\n    ],\n    bot_accounts=[\n        BotAccountWithSecret(\n            # Не забудьте заменить эти учётные данные на настоящие,\n            # когда создадите бота в панели администратора.\n            id=UUID(\"123e4567-e89b-12d3-a456-426655440000\"),\n            cts_url=\"cts.example.com\",\n            secret_key=\"e29b417773f2feab9dac143ee3da20c5\",\n        ),\n    ],\n    middlewares=[\n        FSMMiddleware([fsm], state_repo_key=\"redis_repo\"),\n    ],\n)\n```\n\n\n### Передача данных между состояниями\n```python #fsm_storage\n@fsm.on(FsmStates.INPUT_FIRST_NAME)\nasync def input_first_name(message: IncomingMessage, bot: Bot) -\u003e None:\n    first_name = message.body\n    await message.state.fsm.change_state(\n        FsmStates.INPUT_LAST_NAME,\n        first_name=first_name,\n    )\n    await bot.answer_message(\"Input your last name:\")\n\n\n@fsm.on(FsmStates.INPUT_LAST_NAME)\nasync def input_last_name(message: IncomingMessage, bot: Bot) -\u003e None:\n    first_name = message.state.fsm_storage.first_name\n    last_name = message.body\n    await message.state.fsm.drop_state()\n    await bot.answer_message(f\"Hello {first_name} {last_name}!\")\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpressapp%2Fpybotx-fsm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexpressapp%2Fpybotx-fsm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpressapp%2Fpybotx-fsm/lists"}