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 Dispatcher, Router or Dialog instance:

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

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


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


async def on_input(
        message: Message, dialog: DialogProtocol, manager: DialogManager,
):
    manager.dialog_data["name"] = message.text
    await manager.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.filters.state import StatesGroup, State
from aiogram.types import Message

from aiogram_dialog import Dialog, DialogManager, DialogProtocol, Window
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(message: Message, dialog: DialogProtocol,
                   manager: DialogManager):
    manager.dialog_data["name"] = message.text
    await manager.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 Dispatcher, Router or Dialog instance and filename somewhere inside your asyncio code:

await render_transitions(dp, "preview.html")

Together it will be something like this:

import asyncio

from aiogram import Dispatcher
from aiogram.filters.state import StatesGroup, State

from aiogram_dialog import Dialog, Window
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"},
    ),
)

dp = Dispatcher()
dp.include_router(dialog)


async def main():
    await render_preview(dp, "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

Web Preview#

Instead of creating files with previews you can serve them using web browser.

Just run aiogram-dialog-preview command passing path to Dispatcher/Router/Dialog in form path/to/dir/package.module:object_or_callable

aiogram-dialog-preview example/subdialog:dialog_router

See console output to get URL and error logs