Исходный код raito.plugins.keyboards.dynamic

from collections.abc import Callable
from functools import wraps
from typing import Concatenate, Literal, TypeAlias, cast, overload

from aiogram.types import InlineKeyboardMarkup, ReplyKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
from typing_extensions import ParamSpec, TypeVar

__all__ = ("dynamic_keyboard",)


P = ParamSpec("P")
BuilderT = TypeVar("BuilderT", InlineKeyboardBuilder, ReplyKeyboardBuilder)

ButtonData: TypeAlias = str | tuple[str] | tuple[str, str] | list[str]
KeyboardMarkupT: TypeAlias = InlineKeyboardMarkup | ReplyKeyboardMarkup

InlineFn: TypeAlias = Callable[Concatenate[InlineKeyboardBuilder, P], object]
ReplyFn: TypeAlias = Callable[Concatenate[ReplyKeyboardBuilder, P], object]

InlineSyncFn: TypeAlias = Callable[P, InlineKeyboardMarkup]
ReplySyncFn: TypeAlias = Callable[P, ReplyKeyboardMarkup]


@overload
def dynamic_keyboard(
    *sizes: int,
    repeat: bool = True,
    adjust: bool = True,
    inline: Literal[True] = True,
    **builder_kwargs: object,
) -> Callable[[InlineFn[P]], InlineSyncFn[P]]: ...
@overload
def dynamic_keyboard(
    *sizes: int,
    repeat: bool = True,
    adjust: bool = True,
    inline: Literal[False],
    **builder_kwargs: object,
) -> Callable[[ReplyFn[P]], ReplySyncFn[P]]: ...
[документация] def dynamic_keyboard( # type: ignore[misc] *sizes: int, repeat: bool = True, adjust: bool = True, inline: bool = True, **builder_kwargs: object, ) -> Callable[[Callable[Concatenate[BuilderT, P], object]], Callable[P, KeyboardMarkupT]]: """Decorator to build inline or reply keyboards via builder style. Example: .. code-block:: python @keyboard(inline=True) def markup(builder: InlineKeyboardBuilder, name: str | None = None): if name is not None: builder.button(text=f"Hello, {name}", callback_data="hello") builder.button(text="Back", callback_data="back") :param sizes: Row sizes passed to `adjust(...)` :param repeat: Whether adjust sizes should repeat :param adjust: Auto-adjust layout if True :param inline: If True, builds InlineKeyboardMarkup :param builder_kwargs: Extra args passed to `as_markup()` :returns: A wrapped function returning KeyboardMarkup """ if not sizes: sizes = (1,) if not inline: builder_kwargs.setdefault("resize_keyboard", True) Builder = InlineKeyboardBuilder if inline else ReplyKeyboardBuilder def wrapper(fn: Callable[Concatenate[BuilderT, P], object]) -> Callable[P, KeyboardMarkupT]: @wraps(fn) def wrapped(*args: P.args, **kwargs: P.kwargs) -> KeyboardMarkupT: builder = Builder() fn(cast(BuilderT, builder), *args, **kwargs) if adjust: builder.adjust(*sizes, repeat=repeat) return builder.as_markup(**builder_kwargs) return wrapped return wrapper