Майcтер сцен¶
Добавлено в версии 3.2.
Предупреждение
Дана фича является експериментальною, поэтому в наступних оновленнях может зминюватись.
Базовый интерфейс litegram-в простой и мощный в використанни, что позволяет реализувати простые взаемодии, такие как обробка команд или сообщений и ответов. Однако некоторые задания требуют поэтапного диалогу между пользователем и ботом. Ось где сцени вступають в гру.
Что ж ике сцены?¶
Сцена в litegram схожа на абстрактний, изольований простир имен или кимнату, к которой пользователь может попасть с помощью коду. Когда пользователь перебувае в межах Сцени, бильшисть других глобальних команд или обработчиков сообщений пропускаются, если только они не предназначены для роботи поза Сценами.Сцени забезпечують структуру для бильш складних взаемодий, ефективно изолюючи и керуючи контекстами для ризних етапив розмови. Вони дозволяють бильш организовано контролювати и керувати розмовою.
Життевий цикл¶
У кожну сцену можно «войти», «покинуть» или «выйти», что обеспечивает читки переходи между ризними етапами розмови. Например, в багатоетапний взаемодии заповнення форми каждый шаг может быть сценою - бот направляе пользователя от одниеи сцени к наступнои, когда они надають необхидну информацию.
Слухачи событий¶
Сцени должны собственные хуки, которые является слушателями команд или сообщений, которые диють только тогда, когда пользователь знаходиться всередини сцени. Ци хуки реагують на действия пользователя, когда пользователь перебувае «всередини» Сцени, предоставляя видповиди или действия, видповидни этому контекста. Когда пользователь переходить от одниеи сцени к иншои, действия и видповиди видповидно зминюються, поскольку пользователь теперь взаемодие с групою слухачив в новий сцени. Ци «специфични для сцени» хуки или слухачи, видирвани от глобального контекста прослуховування, дозволяють бильш оптимизовану и организовану взаемодию бот-пользователь.
Взаемодия¶
Кожна сцена схожа на самодостатний свит из взаемодиями, визначеними в межах этой сцени. Таким чином, только обработчики, визначени в конкретний сцени, реагуватимуть на введення пользователя протягом життевого циклу этой сцени.
Переваги¶
Сцени могут допомогти керувати бильш складними робочими процесами взаемодии и забезпечити бильш интерактивни и динамические диалоги между пользователем и ботом. Это обеспечивает велику гнучкисть в обробци багатоетапних взаемодий или розмов с користувачами.
Как это использовать?¶
Например, в нас является тестовий бот, который задае користувачеви серию запитань, а потим видображае результаты - назвемо его гра-викторина.
Почнемо с моделей данных. У этому примеры простые модели данных використовуються для представлення запитань и ответов, в реальному житти вы, ймовирно, використовували б базу данных для хранения данных.
TOKEN = getenv("BOT_TOKEN")
@dataclass
class Answer:
"""
Represents an answer to a question.
"""
text: str
"""The answer text"""
is_correct: bool = False
"""Indicates if the answer is correct"""
@dataclass
class Question:
"""
Class representing a quiz with a question and a list of answers.
"""
text: str
"""The question text"""
answers: list[Answer]
"""List of answers"""
correct_answer: str = field(init=False)
def __post_init__(self):
self.correct_answer = next(answer.text for answer in self.answers if answer.is_correct)
# Fake data, in real application you should use a database or something else
QUESTIONS = [
Question(
text="What is the capital of France?",
answers=[
Answer("Paris", is_correct=True),
Answer("London"),
Answer("Berlin"),
Answer("Madrid"),
],
),
Question(
text="What is the capital of Spain?",
answers=[
Answer("Paris"),
Answer("London"),
Answer("Berlin"),
Answer("Madrid", is_correct=True),
],
),
Question(
text="What is the capital of Germany?",
answers=[
Answer("Paris"),
Answer("London"),
Answer("Berlin", is_correct=True),
Answer("Madrid"),
],
),
Question(
text="What is the capital of England?",
answers=[
Answer("Paris"),
Answer("London", is_correct=True),
Answer("Berlin"),
Answer("Madrid"),
],
),
Question(
text="What is the capital of Italy?",
answers=[
Answer("Paris"),
Answer("London"),
Answer("Berlin"),
Затем нам нужно создать класс Scene, который представлятиме сцену викторини:
Примечание
Іменований аргумент, переданный в определения класса, описуе имя сцени - те именно, что стан сцени.
class QuizScene(Scene, state="quiz"):
"""
This class represents a scene for a quiz game.
It inherits from Scene class and is associated with the state "quiz".
It handles the logic and flow of the quiz game.
"""
Також нам нужно определить обработчик, который поможетт запустити викторину:
"""
await message.answer("Please select an answer.")
Писля определения сцены нам нужно зарееструвати её в SceneRegistry:
def create_dispatcher() -> Dispatcher:
# Event isolation is needed to correctly handle fast user responses
dispatcher = Dispatcher(
events_isolation=SimpleEventIsolation(),
)
dispatcher.include_router(quiz_router)
# To use scenes, you should create a SceneRegistry and register your scenes there
scene_registry = SceneRegistry(dispatcher)
# ... and then register a scene in the registry
# by default, Scene will be mounted to the router that passed to the SceneRegistry,
# but you can specify the router explicitly using the `router` argument
scene_registry.add(QuizScene)
return dispatcher
Отже, теперь ми можемо реализувати логику гри-викторини, кожне вопроса надсилаеться користувачеви одне за одним, а ответ пользователя перевиряеться в кинци всех запитань.
Тепер нам нужно написать точку входу для обработчика запиинь:
@on.message.enter()
async def on_enter(self, message: Message, state: FSMContext, step: int = 0) -> Any:
"""
Method triggered when the user enters the quiz scene.
It displays the current question and answer options to the user.
:param message:
:param state:
:param step: Scene argument, can be passed to the scene using the wizard
:return:
"""
if step == 0:
# This is the first step, so we should greet the user
await message.answer("Welcome to the quiz!")
try:
quiz = QUESTIONS[step]
except IndexError:
# This error means that the question's list is over
return await self.wizard.exit()
markup = ReplyKeyboardBuilder()
markup.add(*[KeyboardButton(text=answer.text) for answer in quiz.answers])
if step > 0:
markup.button(text="🔙 Back")
markup.button(text="🚫 Exit")
await state.update_data(step=step)
return await message.answer(
text=QUESTIONS[step].text,
reply_markup=markup.adjust(2).as_markup(resize_keyboard=True),
)
Писля входу в сцену ми маемо ожидать видповиди пользователя, поэтому нам нужно написать для неи обработчик, этот обработчик имеет ожидать текстовое сообщения, сохранить ответ и повторно выполнить обработчик вопроса для наступного вопроса:
@on.message(F.text)
async def answer(self, message: Message, state: FSMContext) -> None:
"""
Method triggered when the user selects an answer.
It stores the answer and proceeds to the next question.
:param message:
:param state:
:return:
"""
data = await state.get_data()
step = data["step"]
answers = data.get("answers", {})
answers[step] = message.text
await state.update_data(answers=answers)
await self.wizard.retake(step=step + 1)
Когда пользователь видповидае невидомим повидомленням, ми должны знову ожидать текстовое сообщения:
@on.message()
async def unknown_message(self, message: Message) -> None:
"""
Method triggered when the user sends a message that is not a command or an answer.
It asks the user to select an answer.
:param message: The message received from the user.
:return: None
"""
await message.answer("Please select an answer.")
Писля видповиди на все вопроса ми маемо показати результаты користувачеви, как вы можете бачити в коди ниже, ми використовуемо await self.wizard.exit(), чтобы выйти зи сцени, когда список запитань в QuizScene» закинчено .on_enter обработчик.
Это означае, что нам нужно написать обработчик виходу, чтобы показати результаты користувачеви:
@on.message.exit()
async def on_exit(self, message: Message, state: FSMContext) -> None:
"""
Method triggered when the user exits the quiz scene.
It calculates the user's answers, displays the summary, and clears the stored answers.
:param message:
:param state:
:return:
"""
data = await state.get_data()
answers = data.get("answers", {})
correct = 0
incorrect = 0
user_answers = []
for step, quiz in enumerate(QUESTIONS):
answer = answers.get(step)
is_correct = answer == quiz.correct_answer
if is_correct:
correct += 1
icon = "✅"
else:
incorrect += 1
icon = "❌"
if answer is None:
answer = "no answer"
user_answers.append(f"{quiz.text} ({icon} {html.quote(answer)})")
content = as_list(
as_section(
Bold("Your answers:"),
as_numbered_list(*user_answers),
),
"",
as_section(
Bold("Summary:"),
as_list(
as_key_value("Correct", correct),
as_key_value("Incorrect", incorrect),
),
),
)
await message.answer(**content.as_kwargs(), reply_markup=ReplyKeyboardRemove())
await state.set_data({})
Також ми можемо выполнить действия для виходу с викторини или возврат к попереднього вопроса:
@on.message(F.text == "🚫 Exit")
async def exit(self, message: Message) -> None:
"""
Method triggered when the user selects the "Exit" button.
It exits the quiz.
:param message:
:return:
"""
await self.wizard.exit()
@on.message(F.text == "🔙 Back")
async def back(self, message: Message, state: FSMContext) -> None:
"""
Method triggered when the user selects the "Back" button.
It allows the user to go back to the previous question.
:param message:
:param state:
:return:
"""
data = await state.get_data()
step = data["step"]
previous_step = step - 1
if previous_step < 0:
# In case when the user tries to go back from the first question,
# we just exit the quiz
return await self.wizard.exit()
return await self.wizard.back(step=previous_step)
Тепер ми можетмо запустити бота и протестувати гру-викторину:
return dispatcher
async def main() -> None:
dp = create_dispatcher()
bot = Bot(token=TOKEN)
await dp.start_polling(bot)
if __name__ == "__main__":
# Alternatively, you can use litegram-cli:
# `litegram run polling quiz_scene:create_dispatcher --log-level info --token BOT_TOKEN`
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Зберемо все разом
from __future__ import annotations
import asyncio
import logging
from dataclasses import dataclass, field
from os import getenv
from typing import TYPE_CHECKING, Any
from litegram import Bot, Dispatcher, F, Router, html
from litegram.filters import Command
from litegram.fsm.scene import Scene, SceneRegistry, ScenesManager, on
from litegram.fsm.storage.memory import SimpleEventIsolation
from litegram.types import KeyboardButton, Message, ReplyKeyboardRemove
from litegram.utils.formatting import (
Bold,
as_key_value,
as_list,
as_numbered_list,
as_section,
)
from litegram.utils.keyboard import ReplyKeyboardBuilder
if TYPE_CHECKING:
from litegram.fsm.context import FSMContext
TOKEN = getenv("BOT_TOKEN")
@dataclass
class Answer:
"""
Represents an answer to a question.
"""
text: str
"""The answer text"""
is_correct: bool = False
"""Indicates if the answer is correct"""
@dataclass
class Question:
"""
Class representing a quiz with a question and a list of answers.
"""
text: str
"""The question text"""
answers: list[Answer]
"""List of answers"""
correct_answer: str = field(init=False)
def __post_init__(self):
self.correct_answer = next(answer.text for answer in self.answers if answer.is_correct)
# Fake data, in real application you should use a database or something else
QUESTIONS = [
Question(
text="What is the capital of France?",
answers=[
Answer("Paris", is_correct=True),
Answer("London"),
Answer("Berlin"),
Answer("Madrid"),
],
),
Question(
text="What is the capital of Spain?",
answers=[
Answer("Paris"),
Answer("London"),
Answer("Berlin"),
Answer("Madrid", is_correct=True),
],
),
Question(
text="What is the capital of Germany?",
answers=[
Answer("Paris"),
Answer("London"),
Answer("Berlin", is_correct=True),
Answer("Madrid"),
],
),
Question(
text="What is the capital of England?",
answers=[
Answer("Paris"),
Answer("London", is_correct=True),
Answer("Berlin"),
Answer("Madrid"),
],
),
Question(
text="What is the capital of Italy?",
answers=[
Answer("Paris"),
Answer("London"),
Answer("Berlin"),
Answer("Rome", is_correct=True),
],
),
]
class QuizScene(Scene, state="quiz"):
"""
This class represents a scene for a quiz game.
It inherits from Scene class and is associated with the state "quiz".
It handles the logic and flow of the quiz game.
"""
@on.message.enter()
async def on_enter(self, message: Message, state: FSMContext, step: int = 0) -> Any:
"""
Method triggered when the user enters the quiz scene.
It displays the current question and answer options to the user.
:param message:
:param state:
:param step: Scene argument, can be passed to the scene using the wizard
:return:
"""
if step == 0:
# This is the first step, so we should greet the user
await message.answer("Welcome to the quiz!")
try:
quiz = QUESTIONS[step]
except IndexError:
# This error means that the question's list is over
return await self.wizard.exit()
markup = ReplyKeyboardBuilder()
markup.add(*[KeyboardButton(text=answer.text) for answer in quiz.answers])
if step > 0:
markup.button(text="🔙 Back")
markup.button(text="🚫 Exit")
await state.update_data(step=step)
return await message.answer(
text=QUESTIONS[step].text,
reply_markup=markup.adjust(2).as_markup(resize_keyboard=True),
)
@on.message.exit()
async def on_exit(self, message: Message, state: FSMContext) -> None:
"""
Method triggered when the user exits the quiz scene.
It calculates the user's answers, displays the summary, and clears the stored answers.
:param message:
:param state:
:return:
"""
data = await state.get_data()
answers = data.get("answers", {})
correct = 0
incorrect = 0
user_answers = []
for step, quiz in enumerate(QUESTIONS):
answer = answers.get(step)
is_correct = answer == quiz.correct_answer
if is_correct:
correct += 1
icon = "✅"
else:
incorrect += 1
icon = "❌"
if answer is None:
answer = "no answer"
user_answers.append(f"{quiz.text} ({icon} {html.quote(answer)})")
content = as_list(
as_section(
Bold("Your answers:"),
as_numbered_list(*user_answers),
),
"",
as_section(
Bold("Summary:"),
as_list(
as_key_value("Correct", correct),
as_key_value("Incorrect", incorrect),
),
),
)
await message.answer(**content.as_kwargs(), reply_markup=ReplyKeyboardRemove())
await state.set_data({})
@on.message(F.text == "🔙 Back")
async def back(self, message: Message, state: FSMContext) -> None:
"""
Method triggered when the user selects the "Back" button.
It allows the user to go back to the previous question.
:param message:
:param state:
:return:
"""
data = await state.get_data()
step = data["step"]
previous_step = step - 1
if previous_step < 0:
# In case when the user tries to go back from the first question,
# we just exit the quiz
return await self.wizard.exit()
return await self.wizard.back(step=previous_step)
@on.message(F.text == "🚫 Exit")
async def exit(self, message: Message) -> None:
"""
Method triggered when the user selects the "Exit" button.
It exits the quiz.
:param message:
:return:
"""
await self.wizard.exit()
@on.message(F.text)
async def answer(self, message: Message, state: FSMContext) -> None:
"""
Method triggered when the user selects an answer.
It stores the answer and proceeds to the next question.
:param message:
:param state:
:return:
"""
data = await state.get_data()
step = data["step"]
answers = data.get("answers", {})
answers[step] = message.text
await state.update_data(answers=answers)
await self.wizard.retake(step=step + 1)
@on.message()
async def unknown_message(self, message: Message) -> None:
"""
Method triggered when the user sends a message that is not a command or an answer.
It asks the user to select an answer.
:param message: The message received from the user.
:return: None
"""
await message.answer("Please select an answer.")
quiz_router = Router(name=__name__)
# Add handler that initializes the scene
quiz_router.message.register(QuizScene.as_handler(), Command("quiz"))
@quiz_router.message(Command("start"))
async def command_start(message: Message, scenes: ScenesManager) -> None:
await scenes.close()
await message.answer(
"Hi! This is a quiz bot. To start the quiz, use the /quiz command.",
reply_markup=ReplyKeyboardRemove(),
)
def create_dispatcher() -> Dispatcher:
# Event isolation is needed to correctly handle fast user responses
dispatcher = Dispatcher(
events_isolation=SimpleEventIsolation(),
)
dispatcher.include_router(quiz_router)
# To use scenes, you should create a SceneRegistry and register your scenes there
scene_registry = SceneRegistry(dispatcher)
# ... and then register a scene in the registry
# by default, Scene will be mounted to the router that passed to the SceneRegistry,
# but you can specify the router explicitly using the `router` argument
scene_registry.add(QuizScene)
return dispatcher
async def main() -> None:
dp = create_dispatcher()
bot = Bot(token=TOKEN)
await dp.start_polling(bot)
if __name__ == "__main__":
# Alternatively, you can use litegram-cli:
# `litegram run polling quiz_scene:create_dispatcher --log-level info --token BOT_TOKEN`
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Компоненти¶
litegram.fsm.scene.Scene- представляет сцену, содержит обработчикиlitegram.fsm.scene.SceneRegistry- контейнер для всех сцен в боти, використовуеться для реестрации сцен и их виришення за названиемlitegram.fsm.scene.ScenesManager- керуе сценами для каждого пользователя, використовуеться для входу, виходу и виришення поточнои сцени для пользователяlitegram.fsm.scene.SceneConfig- конфигурация сцени, використовуеться для настройки сцениlitegram.fsm.scene.SceneWizard- майстер сцени, который використовуеться для взаемодии с пользователем в сцени с активного обработчика сцениMarkers - маркер для обработчиков сцен, використовуеться для позначення обработчиков сцен
- class litegram.fsm.scene.Scene(wizard: SceneWizard)[исходный код]¶
Предсивляе шаг в диалози.
Сэтона — это певний син розмови, где могут отбуватися певни действия.
Кожна сцена имеет набор фильтрив, которые определяют, когда вона имеет быть запущена, и набор обработчиков, которые определяют действия, которые должны выполняться, когда сцена активна.
Примечание
Этот класс не призначений для безпосереднього использования. Замисть этого следует создать пидкласи для определения собственных сцен.
- classmethod add_to_router(router: Router) None[исходный код]¶
Додае сцену к заданого маршрутизатора.
- Параметры:
router
- Результат:
- classmethod as_handler(**handler_kwargs: Any) Callable[[...], Any][исходный код]¶
Создайте обработчик точки входу для сцени, который можно использовать для упрощения обработчика, который запускае сцену.
>>> router.message.register(MyScene.as_handler(), Command("start"))
- classmethod as_router(name: str | None = None) Router[исходный код]¶
Returns the scene as a router.
- Результат:
новий роутер
- class litegram.fsm.scene.SceneRegistry(router: Router, register_on_add: bool = True)[исходный код]¶
Клас, который представляет реестр для сцен.
- add(*scenes: type[Scene], router: Router | None = None) None[исходный код]¶
Этот метод додае вказани сцени к реестру и додатково рееструе их на маршрутизаторе.
Если сцена с таким самим состоянием уже существует в реестре, возникает SceneException.
Предупреждение
If the router is not specified, the scenes will not be registered to the router. You will need to include the scenes manually to the router or use the register method.
- Параметры:
scenes – Параметр зминнои довжини, который принимает один или несколько типов сцен. Ци сцени является екземплярами класса Scene.
router – Додатковий параметр, который визначае маршрутизатор, к которого следует добавить сцени.
- Результат:
None
- get(scene: type[Scene] | State | str | None) type[Scene][исходный код]¶
Этот метод повертае зареестрований объект Scene для вказанои сцени. Параметром сцени может быть или объект Scene, или строку, что представляет название сцени. Если надаеться объект Scene, атрибут состояния объекта SceneConfig, пов’язаного с объектом Scene, використовуватиметься как им’я сцени. Если вказано None или недийсний тип, будет викликано SceneException.
Если вказану сцену не зареестровано в объекти SceneRegistry, будет породжено помилку SceneException.
- Параметры:
scene – Об’ект Scene или строку, что представляет название сцены.
- Результат:
Зареестрований объект Scene, что ответие даному параметру сцены.
- register(*scenes: type[Scene]) None[исходный код]¶
Рееструе одну или несколько сцен в SceneRegistry.
- Параметры:
scenes – Один или несколько класив сцен для реестрации.
- Результат:
None
- class litegram.fsm.scene.ScenesManager(registry: SceneRegistry, update_type: str, event: TelegramObject, state: FSMContext, data: dict[str, Any])[исходный код]¶
Клас ScenesManager видповидае за керування сценами в программы. Он предоставляет методы входу и виходу зи сцен, а также видновлення активнои сцени.
- async close(**kwargs: Any) None[исходный код]¶
Метод Close використовуеться для виходу с поточнои активнои сцени в ScenesManager.
- Параметры:
kwargs – Додаткови аргументы ключового слова, передани в метод виходу сцены.
- Результат:
None
- async enter(scene_type: type[Scene] | State | str | None, _check_active: bool = True, **kwargs: Any) None[исходный код]¶
Виходить на вказану сцену.
- Параметры:
scene_type – Додатково Type[Scene] или str, что представляет тип сцени, который нужно ввести.
_check_active – Необов’язковий параметр, что вказуе, или перевиряти наявнисть активнои сцени для виходу перед входом в нову сцену. За замовчуванням значение True.
kwargs – Додаткови именованные аргументы для передачи в метод wizard.enter() сцены.
- Результат:
None
- class litegram.fsm.scene.SceneConfig(state: 'str | None', handlers: 'list[HandlerContainer]', actions: 'dict[SceneAction, dict[str, CallableObject]]', reset_data_on_enter: 'bool | None' = None, reset_history_on_enter: 'bool | None' = None, callback_query_without_state: 'bool | None' = None, attrs_resolver: 'ClassAttrsResolver' = <function get_sorted_mro_attrs_resolver at 0x76aeb11ff880>)[исходный код]¶
-
- attrs_resolver() Generator[tuple[str, Any]]¶
Attributes resolver.
Опасно
This attribute should only be changed when you know what you are doing.
Добавлено в версии 3.19.0.
- class litegram.fsm.scene.SceneWizard(scene_config: SceneConfig, manager: ScenesManager, state: FSMContext, update_type: str, event: TelegramObject, data: dict[str, Any])[исходный код]¶
Клас, который представляет майстер сцен.
Экземпляр этого класса передаеться кожний сцени как параметр. Отже, вы можете использовать его для переходу между сценами, получения и встановлення данных и т.д..
Примечание
Этот класс не призначений для безпосереднього использования. Натомисть его следует использовать как параметр в конструктори сцени.
- async back(**kwargs: Any) None[исходный код]¶
Этот метод використовуеться для возврат к попередньои сцены.
- Параметры:
kwargs – Аргументи ключевых слов, которые можно передать в метод.
- Результат:
None
- async clear_data() None[исходный код]¶
Очищае дани.
- Результат:
None
- async enter(**kwargs: Any) None[исходный код]¶
Метод Enter використовуеться для переходу в сцену в классы SceneWizard. Он встановлюе стан, очищае дани и историю, если вказано, и запускае введення события сцени.
- Параметры:
kwargs – Додаткови именованные аргументы.
- Результат:
None
- async exit(**kwargs: Any) None[исходный код]¶
Вийти с поточнои сцены и перейти к синдартного сину или сцены.
- Параметры:
kwargs – Додаткови именованные аргументы.
- Результат:
None
- async get_data() dict[str, Any][исходный код]¶
Этот метод поверие дани, что зберигаються в текущему сини.
- Результат:
Словник, что содержит дани, что зберигаються в сини сцены.
- async goto(scene: type[Scene] | State | str, **kwargs: Any) None[исходный код]¶
Метод goto переходить к новои сцени. Спочатку вин викликае метод leave, чтобы выполнить будь-которое необходимое очистка в текущий сцени, а потим викликае подию enter, чтобы войти к вказанои сцени.
- Параметры:
scene – Сцена для переходу. Може быть экземпляром Scene или рядком, что представляет сцену.
kwargs – Додаткови именованные аргументы для точки входу к enter менеджера сцен.
- Результат:
None
- async leave(_with_history: bool = True, **kwargs: Any) None[исходный код]¶
Залишае поточну сцену. Этот метод використовуеться для виходу зи сцени и переходу к наступнои сцени.
- Параметры:
_with_history – Чи включати историю в знимок. За замовчуванням значение True.
kwargs – Додаткови именованные аргументы.
- Результат:
None
- async retake(**kwargs: Any) None[исходный код]¶
Этот метод кзволяе повторно войти к поточнои сцены.
- Параметры:
kwargs – Додаткови именованные аргументы для передачи к сцены.
- Результат:
None
- async set_data(data: Mapping[str, Any]) None[исходный код]¶
Всиновлюе настроювани дани в текущий син.
- Параметры:
data – Словник, что содержит настроювани дани, которые нужно встановити в текущему состояния.
- Результат:
None
- async update_data(data: Mapping[str, Any] | None = None, **kwargs: Any) dict[str, Any][исходный код]¶
Этот метод оновлюе дани, что зберигаються в текущему сини
- Параметры:
data – Додатковий словарь данных для обновления.
kwargs – Додаткови пари ключ-значение данных для обновления.
- Результат:
Словник оновлених данных
Маркеры¶
Маркеры подибни к механизму реестрации событий Router, но они використовуються для позначення обработчиков сцени в классы Scene.
Его можно импортувати с from litegram.fsm.scene import on и следует использовать как декоратор.
Дозволени типы событий:
message
edited_message
channel_post
edited_channel_post
inline_query
chosen_inline_result
callback_query
shipping_query
pre_checkout_query
poll
poll_answer
my_chat_member
chat_member
chat_join_request
Кожен тип события можно отфильтрувати ик само, как и в маршрутизаторе.
Також каждый тип события можно пометить как точку входу в сцену, точку виходу или точку переходу.
Если вы хотите пометить, что к сцени можно попасть с сообщения или ин-лайн кнопки, вам следует использовать маркер on.message или on.inline_query:
class MyScene(Scene, name="my_scene"):
@on.message.enter()
async def on_enter(self, message: types.Message):
pass
@on.callback_query.enter()
async def on_enter(self, callback_query: types.CallbackQuery):
pass
Сэтони должны три точки для переходив:
Точка входу - когда пользователь входить к сцены
Точка переходу - когда пользователь переходить к иншои сцены
Точка виходу - когда пользователь завершуе сцену
Как это использовать?¶
There are several ways to enter a scene in litegram. Each approach has specific use cases and advantages
Directly using the scene’s entry point as a handler:
You can convert a scene’s entry point to a handler and register it like any other handler:
router.message.register(SettingsScene.as_handler(), Command("settings"))
From a regular handler using ScenesManager:
Enter a scene from any regular handler by using the ScenesManager:
Примечание
When using ScenesManager, you need to explicitly pass all dependencies required by the scene’s entry point handler as arguments to the enter method.
@router.message(Command("settings")) async def settings_handler(message: Message, scenes: ScenesManager): await scenes.enter(SettingsScene, some_data="data") # pass additional arguments to the scene
From another scene using After.goto marker:
Transition to another scene after a handler is executed using the After marker:
class MyScene(Scene, state="my_scene"): ... @on.message(F.text.startswith("🚀"), after=After.goto(AnotherScene)) async def on_message(self, message: Message, some_repo: SomeRepository, db: AsyncSession): # Persist some data before going to another scene await some_repo.save(user_id=message.from_user.id, value=message.text) await db.commit() ...
Using explicit transition with wizard.goto:
For more control over the transition, use the wizard.goto method from within a scene handler:
Примечание
Dependencies will be injected into the handler normally and then extended with the arguments specified in the goto method.
class MyScene(Scene, state="my_scene"): ... @on.message(F.text.startswith("🚀")) async def on_message(self, message: Message): # Direct control over when and how to transition await self.wizard.goto(AnotherScene, value=message.text) ...
Each method offers different levels of control and integration with your application’s architecture. Choose the approach that best fits your specific use case and coding style.