Helper tools (experimental)

State diagram

You can generate image with your states and transitions.

Firstly you need to install [graphviz](https://graphviz.org/download/) into your system. Check installation instructions on official site.

Install library with tools extras:

pip install aiogram_dialog[tools]

Import rendering method:

from aiogram_dialog.tools import render_transitions

Call it passing your registry or list of dialogs:

from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.types import Message

from aiogram_dialog import Dialog, Window, DialogManager
from aiogram_dialog.tools import render_transitions
from aiogram_dialog.widgets.input import MessageInput
from aiogram_dialog.widgets.kbd import Next, Back
from aiogram_dialog.widgets.text import Const


class RenderSG(StatesGroup):
    first = State()
    second = State()
    last = State()


async def on_input(m: Message, dialog: Dialog, manager: DialogManager):
    manager.current_context().dialog_data["name"] = m.text
    await dialog.next()


dialog = Dialog(
    Window(
        Const("1. First"),
        Next(),
        state=RenderSG.first,
    ),
    Window(
        Const("2. Second"),
        Back(),
        MessageInput(on_input),
        state=RenderSG.second,
    ),
    Window(
        Const("3. Last"),
        Back(),
        state=RenderSG.last,
    ),
)

# this is diagram rendering
render_transitions([dialog])

Run your code and you will get aiogram_dialog.png in working directory:

_images/render_simple.png

State transition hints

You may notice, that not all transitions are show on diagram. This is because library cannot analyze source code of you callbacks. Only transitions, done by special buttons are shown.

To fix this behavior you can set preview_add_transitions parameter of window:

from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.types import Message

from aiogram_dialog import Dialog, Window, DialogManager
from aiogram_dialog.tools import render_transitions
from aiogram_dialog.widgets.input import MessageInput
from aiogram_dialog.widgets.kbd import Next, Back
from aiogram_dialog.widgets.text import Const


class RenderSG(StatesGroup):
    first = State()
    second = State()
    last = State()


async def on_input(m: Message, dialog: Dialog, manager: DialogManager):
    manager.current_context().dialog_data["name"] = m.text
    await dialog.next()  # rendering tool cannot detect this call


dialog = Dialog(
    Window(
        Const("1. First"),
        Next(),
        state=RenderSG.first,
    ),
    Window(
        Const("2. Second"),
        Back(),
        MessageInput(on_input),
        state=RenderSG.second,
        preview_add_transitions=[Next()],  # this is a hint for rendering tool
    ),
    Window(
        Const("3. Last"),
        Back(),
        state=RenderSG.last,
    ),
)

render_transitions([dialog])

Run the code and check updated rendering result:

_images/render_hints.png

Dialogs preview

Import rendering method:

from aiogram_dialog.tools import render_preview

Add some data to be shown on preview using preview_data parameter of window:

class RenderSG(StatesGroup):
    first = State()


dialog = Dialog(
    Window(
        Format("Hello, {name}"),
        Cancel(),
        state=RenderSG.first,
        preview_data={"name": "Tishka17"},
    ),
)

Call it passing your registry and filename somewhere inside your asyncio code:


await render_transitions(registry, "preview.html")

Together it will be something like this:

import asyncio

from aiogram import Bot, Dispatcher
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher.filters.state import StatesGroup, State

from aiogram_dialog import Dialog, Window, DialogRegistry
from aiogram_dialog.tools import render_preview
from aiogram_dialog.widgets.kbd import Cancel
from aiogram_dialog.widgets.text import Format


class RenderSG(StatesGroup):
    first = State()


dialog = Dialog(
    Window(
        Format("Hello, {name}"),
        Cancel(),
        state=RenderSG.first,
        preview_data={"name": "Tishka17"},
    ),
)

storage = MemoryStorage()
bot = Bot(token='BOT TOKEN HERE')
dp = Dispatcher(bot, storage=storage)
registry = DialogRegistry(dp)
registry.register(dialog)


async def main():
    await render_preview(registry, "preview.html")


if __name__ == '__main__':
    asyncio.run(main())

As a result you will see a html file in working directory, that can be opened in browser to preview how all dialogs will look like.

_images/render_preview_result.png