mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
* Preserve middleware context across scene goto transitions (#1687) * Add After.goto coverage for scene middleware context (#1687)
This commit is contained in:
parent
e37eddbe8c
commit
73710acb4c
4 changed files with 113 additions and 0 deletions
1
CHANGES/1687.bugfix.rst
Normal file
1
CHANGES/1687.bugfix.rst
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed scene transitions to preserve middleware-injected data when moving between scenes via ``SceneWizard.goto``.
|
||||||
|
|
@ -259,6 +259,7 @@ class SceneHandlerWrapper:
|
||||||
)
|
)
|
||||||
raise SceneException(msg) from None
|
raise SceneException(msg) from None
|
||||||
event_update: Update = kwargs["event_update"]
|
event_update: Update = kwargs["event_update"]
|
||||||
|
scenes.data = {**scenes.data, **kwargs}
|
||||||
scene = self.scene(
|
scene = self.scene(
|
||||||
wizard=SceneWizard(
|
wizard=SceneWizard(
|
||||||
scene_config=self.scene.__scene_config__,
|
scene_config=self.scene.__scene_config__,
|
||||||
|
|
@ -712,6 +713,9 @@ class ScenesManager:
|
||||||
:param kwargs: Additional keyword arguments to pass to the scene's wizard.enter() method.
|
:param kwargs: Additional keyword arguments to pass to the scene's wizard.enter() method.
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
if kwargs:
|
||||||
|
self.data = {**self.data, **kwargs}
|
||||||
|
|
||||||
if _check_active:
|
if _check_active:
|
||||||
active_scene = await self._get_active_scene()
|
active_scene = await self._get_active_scene()
|
||||||
if active_scene is not None:
|
if active_scene is not None:
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,7 @@ class TestSceneHandlerWrapper:
|
||||||
|
|
||||||
state_mock = AsyncMock(spec=FSMContext)
|
state_mock = AsyncMock(spec=FSMContext)
|
||||||
scenes_mock = AsyncMock(spec=ScenesManager)
|
scenes_mock = AsyncMock(spec=ScenesManager)
|
||||||
|
scenes_mock.data = {}
|
||||||
event_update_mock = Update(
|
event_update_mock = Update(
|
||||||
update_id=42,
|
update_id=42,
|
||||||
message=Message(
|
message=Message(
|
||||||
|
|
@ -282,6 +283,7 @@ class TestSceneHandlerWrapper:
|
||||||
|
|
||||||
state_mock = AsyncMock(spec=FSMContext)
|
state_mock = AsyncMock(spec=FSMContext)
|
||||||
scenes_mock = AsyncMock(spec=ScenesManager)
|
scenes_mock = AsyncMock(spec=ScenesManager)
|
||||||
|
scenes_mock.data = {}
|
||||||
event_update_mock = Update(
|
event_update_mock = Update(
|
||||||
update_id=42,
|
update_id=42,
|
||||||
message=Message(
|
message=Message(
|
||||||
|
|
|
||||||
106
tests/test_issues/test_1687_scene_goto_loses_middleware_data.py
Normal file
106
tests/test_issues/test_1687_scene_goto_loses_middleware_data.py
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from aiogram import BaseMiddleware, Dispatcher
|
||||||
|
from aiogram.enums import ChatType
|
||||||
|
from aiogram.filters import CommandStart
|
||||||
|
from aiogram.fsm.scene import After, Scene, SceneRegistry, on
|
||||||
|
from aiogram.types import Chat, Message, TelegramObject, Update, User
|
||||||
|
from tests.mocked_bot import MockedBot
|
||||||
|
|
||||||
|
|
||||||
|
class TestContextMiddleware(BaseMiddleware):
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
|
||||||
|
event: TelegramObject,
|
||||||
|
data: dict[str, Any],
|
||||||
|
) -> Any:
|
||||||
|
data["test_context"] = "context from middleware"
|
||||||
|
return await handler(event, data)
|
||||||
|
|
||||||
|
|
||||||
|
class TargetScene(Scene, state="target"):
|
||||||
|
entered_with_context: str | None = None
|
||||||
|
|
||||||
|
@on.message.enter()
|
||||||
|
async def on_enter(self, message: Message, test_context: str) -> None:
|
||||||
|
type(self).entered_with_context = test_context
|
||||||
|
|
||||||
|
|
||||||
|
class StartScene(Scene, state="start"):
|
||||||
|
@on.message.enter()
|
||||||
|
async def on_start(self, message: Message) -> None:
|
||||||
|
await self.wizard.goto(TargetScene)
|
||||||
|
|
||||||
|
|
||||||
|
class StartSceneWithAfter(Scene, state="start_with_after"):
|
||||||
|
@on.message(after=After.goto(TargetScene))
|
||||||
|
async def goto_target_with_after(self, message: Message) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def test_scene_goto_preserves_message_middleware_data(bot: MockedBot) -> None:
|
||||||
|
dp = Dispatcher()
|
||||||
|
registry = SceneRegistry(dp)
|
||||||
|
registry.add(StartScene, TargetScene)
|
||||||
|
dp.message.register(StartScene.as_handler(), CommandStart())
|
||||||
|
dp.message.middleware(TestContextMiddleware())
|
||||||
|
|
||||||
|
TargetScene.entered_with_context = None
|
||||||
|
|
||||||
|
update = Update(
|
||||||
|
update_id=1,
|
||||||
|
message=Message(
|
||||||
|
message_id=1,
|
||||||
|
date=datetime.now(),
|
||||||
|
chat=Chat(id=42, type=ChatType.PRIVATE),
|
||||||
|
from_user=User(id=42, is_bot=False, first_name="Test"),
|
||||||
|
text="/start",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await dp.feed_update(bot, update)
|
||||||
|
|
||||||
|
assert TargetScene.entered_with_context == "context from middleware"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_scene_after_goto_preserves_message_middleware_data(bot: MockedBot) -> None:
|
||||||
|
dp = Dispatcher()
|
||||||
|
registry = SceneRegistry(dp)
|
||||||
|
registry.add(StartSceneWithAfter, TargetScene)
|
||||||
|
dp.message.register(StartSceneWithAfter.as_handler(), CommandStart())
|
||||||
|
dp.message.middleware(TestContextMiddleware())
|
||||||
|
|
||||||
|
TargetScene.entered_with_context = None
|
||||||
|
|
||||||
|
await dp.feed_update(
|
||||||
|
bot,
|
||||||
|
Update(
|
||||||
|
update_id=1,
|
||||||
|
message=Message(
|
||||||
|
message_id=1,
|
||||||
|
date=datetime.now(),
|
||||||
|
chat=Chat(id=42, type=ChatType.PRIVATE),
|
||||||
|
from_user=User(id=42, is_bot=False, first_name="Test"),
|
||||||
|
text="/start",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
await dp.feed_update(
|
||||||
|
bot,
|
||||||
|
Update(
|
||||||
|
update_id=2,
|
||||||
|
message=Message(
|
||||||
|
message_id=2,
|
||||||
|
date=datetime.now(),
|
||||||
|
chat=Chat(id=42, type=ChatType.PRIVATE),
|
||||||
|
from_user=User(id=42, is_bot=False, first_name="Test"),
|
||||||
|
text="go",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert TargetScene.entered_with_context == "context from middleware"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue