Skip to main content

Лёгкий движок древовидных inline-опросников (wizard) для aiogram 3

Project description

tg-tree-wizard

Лёгкий движок древовидных inline-опросников для aiogram 3. Дерево описывается данными (Node/Option), а не отдельным хендлером на каждый уровень; "назад" и переходы обрабатываются двумя общими хендлерами независимо от глубины дерева.

Сколько кода экономит

Замер на дереве из 6 уровней (язык → формат → цель → индивидуально/группа → возраст → уровень владения), с 2-7 вариантами ответа на каждом — навигационная часть кода, без учёта бизнес-логики финального шага (сохранение заявки и т.п. — она одинакова в обоих случаях):

Строк кода
Вручную (клавиатура + парсинг callback_data + кнопка "назад" на каждый уровень) ~169
tg-tree-wizard (linear_wizard + подключение роутера) ~26

Разница держится линейно — не растёт и не убывает в зависимости от того, сколько таких деревьев в проекте: каждое новое дерево стоит фиксированные ~26 строк вместо ~169, потому что логика навигации, "назад" и защита от превышения лимита callback_data уже написаны и покрыты тестами один раз, внутри самой библиотеки.

Структура пакета

tg_tree_wizard/
├── pyproject.toml              # метаданные пакета, как его ставить
├── src/tg_tree_wizard/
│   ├── __init__.py             # публичный API (что видно снаружи через import)
│   ├── core.py                 # чистая логика дерева, БЕЗ aiogram
│   └── aiogram_adapter.py      # клавиатуры + хендлеры aiogram поверх core.py
├── tests/
│   └── test_core.py            # тесты ядра, без сети и без Telegram
└── examples/
    ├── simulate_flow.py        # прогон через настоящий aiogram Dispatcher, без сети
    └── language_school_bot.py  # реальный бот — запускается с настоящим токеном

Почему core.py отдельно от aiogram_adapter.py: это приём, который делает библиотеку тестируемой. Ядро ничего не знает про Telegram — значит, его логику (переходы, "назад", ошибки) можно проверить обычным pytest за доли секунды, без сети и без живого бота. Адаптер — тонкий слой, который только рендерит клавиатуры и дёргает ядро.

Установка

cd tg_tree_wizard
pip install -e .          # editable-режим: правите код — сразу видно в проекте

-e (editable) значит, что пакет ставится "по ссылке" на исходники, а не копируется — удобно, пока сами дорабатываете библиотеку.

Тесты ядра (без Telegram)

pip install pytest
pytest tests/ -v

Прогон через настоящий aiogram, но без сети

python examples/simulate_flow.py

Использует настоящий Dispatcher и MemoryStorage, подменяет только реальный HTTP-запрос к api.telegram.org — так что проверяется всё, кроме собственно доставки сообщений.

Запуск с реальным ботом

export BOT_TOKEN=ваш_настоящий_токен
python examples/language_school_bot.py

Дальше пишите /survey в бота и проходите дерево — это уже 100% реальная проверка через живой Telegram.

Как описать своё дерево

Короткий способ (рекомендуется для большинства случаев)linear_wizard. Подходит, когда вопросы идут по порядку и лишь изредка нужно свернуть в сторону:

from tg_tree_wizard import linear_wizard, TreeWizard

TREE, ROOT = linear_wizard([
    ("lang", "Выберите язык:", ["Английский", "Немецкий"]),       # label == value
    ("delivery", "Формат:", [("Очно", "offline"), ("Онлайн", "online")]),
    ("topping", "Начинка:", [
        ("Пепперони", "pepperoni", "spicy"),   # явный переход = ветвление
        ("Маргарита", "margherita"),           # без 3-го элемента = следующий шаг по порядку
    ]),
    ("spicy", "Поострее?", ["Да", "Нет"]),
])

wizard = TreeWizard(TREE, root=ROOT, on_finish=my_finish_callback)
dp.include_router(wizard.router)

Правила для варианта ответа:

  • "Текст" — метка и значение совпадают, переход на следующий шаг по списку;
  • ("Текст", "значение") — то же самое, но значение отдельно от текста кнопки;
  • ("Текст", "значение", "id_узла") — явный переход, для ветвления или для перехода не на следующий, а на произвольный узел (в т.ч. в обход промежуточных шагов).

Последний шаг в списке — финальный по умолчанию (после него опрос завершается), если явно не переопределить переход у его вариантов.

Полный способ — Node/Option напрямую. Нужен, когда переходов в дерево больше, чем шагов, и связь "шаг → следующий по умолчанию" не работает (сложные ветвящиеся графы, несколько независимых корней и т.п.):

from tg_tree_wizard import Node, Option, TreeWizard

TREE = {
    "start": Node(
        text="Первый вопрос:",
        options=(
            Option("Вариант A", "a", "next_node_id"),
            Option("Вариант B", "b", None),  # None = опрос завершается
        ),
    ),
    "next_node_id": Node(...),
}

wizard = TreeWizard(TREE, root="start", on_finish=my_finish_callback)

TreeWizard(...) сам вызывает validate_tree при создании — если где-то опечатались в id узла, бот упадёт при старте с понятной ошибкой.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tg_tree_wizard-1.0.1.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tg_tree_wizard-1.0.1-py3-none-any.whl (12.5 kB view details)

Uploaded Python 3

File details

Details for the file tg_tree_wizard-1.0.1.tar.gz.

File metadata

  • Download URL: tg_tree_wizard-1.0.1.tar.gz
  • Upload date:
  • Size: 16.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for tg_tree_wizard-1.0.1.tar.gz
Algorithm Hash digest
SHA256 501100f8584abbff5e7ce2eba66d5ba91ccf740071b5ef72866cf7f0f65ea5c2
MD5 d33ab242bff4a3b15999780e2ef8ee50
BLAKE2b-256 ec3d020eda36ef888102a5e8cd82e1c5946e84c9a87e8108f2c366e737a843b3

See more details on using hashes here.

File details

Details for the file tg_tree_wizard-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: tg_tree_wizard-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 12.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for tg_tree_wizard-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2e26028ec1f1f36ceddbe5aecacdd4196220b80f67d4c2e885cec668ea6d2fea
MD5 4ece0e4860d21d2b576a933e8da3c2e0
BLAKE2b-256 717b096521054943f3d2cf1523724e68f2a549eb42784792207ddf581127467b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page