diff --git a/aiogram/scenes/_scene.py b/aiogram/scenes/_scene.py index a7ff2858..3f0f455e 100644 --- a/aiogram/scenes/_scene.py +++ b/aiogram/scenes/_scene.py @@ -139,6 +139,9 @@ class SceneConfig: filters: Dict[str, List[CallbackType]] handlers: List[HandlerContainer] actions: Dict[SceneAction, Dict[str, CallableObject]] + reset_data_on_enter: Optional[bool] = None + reset_history_on_enter: Optional[bool] = None + callback_query_without_state: Optional[bool] = None async def _empty_handler(*args: Any, **kwargs: Any) -> None: @@ -158,6 +161,10 @@ class _SceneMeta(type): handlers: list[HandlerContainer] = [] actions: defaultdict[SceneAction, Dict[str, CallableObject]] = defaultdict(dict) + reset_data_on_enter = kwargs.pop("reset_data_on_enter", None) + reset_history_on_enter = kwargs.pop("reset_history_on_enter", None) + callback_query_without_state = kwargs.pop("callback_query_without_state", None) + for base in bases: if not issubclass(base, Scene): continue @@ -168,6 +175,13 @@ class _SceneMeta(type): for action, action_handlers in parent_scene_config.actions.items(): actions[action].update(action_handlers) + if reset_data_on_enter is None: + reset_data_on_enter = parent_scene_config.reset_data_on_enter + if reset_history_on_enter is None: + reset_history_on_enter = parent_scene_config.reset_history_on_enter + if callback_query_without_state is None: + callback_query_without_state = parent_scene_config.callback_query_without_state + for name, value in namespace.items(): if scene_handlers := getattr(value, "__aiogram_handler__", None): handlers.extend(scene_handlers) @@ -189,6 +203,9 @@ class _SceneMeta(type): filters=dict(filters), handlers=handlers, actions=dict(actions), + reset_data_on_enter=reset_data_on_enter, + reset_history_on_enter=reset_history_on_enter, + callback_query_without_state=callback_query_without_state, ) return super().__new__(mcs, name, bases, namespace, **kwargs) @@ -266,9 +283,9 @@ class Scene(metaclass=_SceneMeta): scene_config = cls.__scene_config__ used_observers = set() - for observer, filters in scene_config.filters.items(): - router.observers[observer].filter(*filters) - used_observers.add(observer) + for observer_name, filters in scene_config.filters.items(): + router.observers[observer_name].filter(*filters) + used_observers.add(observer_name) for handler in scene_config.handlers: router.observers[handler.name].register( @@ -281,8 +298,10 @@ class Scene(metaclass=_SceneMeta): ) used_observers.add(handler.name) - for observer in used_observers: - router.observers[observer].filter(StateFilter(scene_config.state)) + for observer_name in used_observers: + if scene_config.callback_query_without_state and observer_name == "callback_query": + continue + router.observers[observer_name].filter(StateFilter(scene_config.state)) @classmethod def as_router(cls) -> Router: @@ -320,8 +339,12 @@ class SceneWizard: self.scene: Optional[Scene] = None - async def enter(self, _with_history: bool = False, **kwargs: Any) -> None: + async def enter(self, **kwargs: Any) -> None: loggers.scene.debug("Entering scene %r", self.scene_config.state) + if self.scene_config.reset_data_on_enter: + await self.state.set_data({}) + if self.scene_config.reset_history_on_enter: + await self.manager.history.clear() await self.state.set_state(self.scene_config.state) await self._on_action(SceneAction.enter, **kwargs) diff --git a/examples/scene.py b/examples/scene.py index 1e4a7980..8814a825 100644 --- a/examples/scene.py +++ b/examples/scene.py @@ -137,7 +137,12 @@ class NameScene(CancellableScene, state="name"): await self.wizard.update_data(name=message.text) -class DefaultScene(Scene): +class DefaultScene( + Scene, + reset_data_on_enter=True, # Reset state data + reset_history_on_enter=True, # Reset history + callback_query_without_state=True, # Handle callback queries even if user in any scene +): """ Default scene for the bot.