Repository: aiogram/aiogram
Pull request #1353 (2023-11-01 10:12:26)

chore(docs): update middleware.rst
# Description

Just typo in docs

## Type of change

- [x] Documentation (typos, code examples or any documentation update)


github-actions[bot]: # :x: Changelog is required!

You need to add a brief description of the changes to the `CHANGES` directory.

Changes file should be named like `<issue or PR number>.<category>.rst`,
example `1234.bugfix.rst` where `1234` is the PR or issue number and `bugfix` is the category.

The content of the file should be a brief description of the changes in
the PR in the format of a description of what has been done.

Possible categories are: `feature`, `bugfix`, `doc`, `removal` and `misc`.

Patch:
diff --git a/CHANGES/1353.doc.rst b/CHANGES/1353.doc.rst
new file mode 100644
index 00000000..15f6d28e
--- /dev/null
+++ b/CHANGES/1353.doc.rst
@@ -0,0 +1,1 @@
+Minor typo correction in middleware docs.
diff --git a/CHANGES/1357.misc.rst b/CHANGES/1357.misc.rst
new file mode 100644
index 00000000..96822c1f
--- /dev/null
+++ b/CHANGES/1357.misc.rst
@@ -0,0 +1,1 @@
+Speeded up CallableMixin processing by caching references to nested objects and simplifying kwargs assembly.
diff --git a/CHANGES/1360.bugfix.rst b/CHANGES/1360.bugfix.rst
new file mode 100644
index 00000000..e02d0ea4
--- /dev/null
+++ b/CHANGES/1360.bugfix.rst
@@ -0,0 +1,1 @@
+Added current handler to filters, so that flags can be retrieved from it.
diff --git a/aiogram/dispatcher/event/handler.py b/aiogram/dispatcher/event/handler.py
index 2b71eed5..1045e667 100644
--- a/aiogram/dispatcher/event/handler.py
+++ b/aiogram/dispatcher/event/handler.py
@@ -4,7 +4,7 @@ import inspect
 import warnings
 from dataclasses import dataclass, field
 from functools import partial
-from typing import Any, Callable, Dict, List, Optional, Tuple
+from typing import Any, Callable, Dict, List, Optional, Tuple, Set
 
 from magic_filter.magic import MagicFilter as OriginalMagicFilter
 
@@ -21,20 +21,21 @@ CallbackType = Callable[..., Any]
 class CallableMixin:
     callback: CallbackType
     awaitable: bool = field(init=False)
-    spec: inspect.FullArgSpec = field(init=False)
+    params: Set[str] = field(init=False)
+    varkw: bool = field(init=False)
 
     def __post_init__(self) -> None:
         callback = inspect.unwrap(self.callback)
         self.awaitable = inspect.isawaitable(callback) or inspect.iscoroutinefunction(callback)
-        self.spec = inspect.getfullargspec(callback)
+        spec = inspect.getfullargspec(callback)
+        self.params = {*spec.args, *spec.kwonlyargs}
+        self.varkw = spec.varkw is not None
 
     def _prepare_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
-        if self.spec.varkw:
+        if self.varkw:
             return kwargs
 
-        return {
-            k: v for k, v in kwargs.items() if k in self.spec.args or k in self.spec.kwonlyargs
-        }
+        return {k: kwargs[k] for k in self.params if k in kwargs}
 
     async def call(self, *args: Any, **kwargs: Any) -> Any:
         wrapped = partial(self.callback, *args, **self._prepare_kwargs(kwargs))
diff --git a/aiogram/dispatcher/event/telegram.py b/aiogram/dispatcher/event/telegram.py
index 4a370074..afa8938e 100644
--- a/aiogram/dispatcher/event/telegram.py
+++ b/aiogram/dispatcher/event/telegram.py
@@ -109,9 +109,10 @@ class TelegramEventObserver:
         Handler will be called when all its filters are pass.
         """
         for handler in self.handlers:
+            kwargs["handler"] = handler
             result, data = await handler.check(event, **kwargs)
             if result:
-                kwargs.update(data, handler=handler)
+                kwargs.update(data)
                 try:
                     wrapped_inner = self.outer_middleware.wrap_middlewares(
                         self._resolve_middlewares(),
diff --git a/docs/api/session/middleware.rst b/docs/api/session/middleware.rst
index fb06daca..5a312c3e 100644
--- a/docs/api/session/middleware.rst
+++ b/docs/api/session/middleware.rst
@@ -53,7 +53,7 @@ Class based session middleware
 
 .. note::
 
-    this middlewware is already implemented inside aiogram, so, if you want to use it you can
+    this middleware is already implemented inside aiogram, so, if you want to use it you can
     just import it :code:`from aiogram.client.session.middlewares.request_logging import RequestLogging`
 
 


Test patch:
diff --git a/tests/test_api/test_types/test_message.py b/tests/test_api/test_types/test_message.py
index 4e893d20..7efe6c89 100644
--- a/tests/test_api/test_types/test_message.py
+++ b/tests/test_api/test_types/test_message.py
@@ -36,6 +36,7 @@ from aiogram.methods import (
     UnpinChatMessage,
 )
 from aiogram.types import (
+    UNSET_PARSE_MODE,
     Animation,
     Audio,
     Chat,
@@ -75,7 +76,6 @@ from aiogram.types import (
     VideoNote,
     Voice,
     WebAppData,
-    UNSET_PARSE_MODE,
 )
 from aiogram.types.message import ContentType, Message
 
diff --git a/tests/test_dispatcher/test_event/test_handler.py b/tests/test_dispatcher/test_event/test_handler.py
index f7000d8e..c2b11cff 100644
--- a/tests/test_dispatcher/test_event/test_handler.py
+++ b/tests/test_dispatcher/test_event/test_handler.py
@@ -1,5 +1,5 @@
 import functools
-from typing import Any, Dict, Union
+from typing import Any, Dict, Union, Callable, Set
 
 import pytest
 from magic_filter import F as A
@@ -61,9 +61,9 @@ class TestCallableMixin:
             pytest.param(SyncCallable(), {"self", "foo", "bar", "baz"}),
         ],
     )
-    def test_init_args_spec(self, callback, args):
+    def test_init_args_spec(self, callback: Callable, args: Set[str]):
         obj = CallableMixin(callback)
-        assert set(obj.spec.args) == args
+        assert set(obj.params) == args
 
     def test_init_decorated(self):
         def decorator(func):
@@ -85,9 +85,9 @@ class TestCallableMixin:
         obj1 = CallableMixin(callback1)
         obj2 = CallableMixin(callback2)
 
-        assert set(obj1.spec.args) == {"foo", "bar", "baz"}
+        assert set(obj1.params) == {"foo", "bar", "baz"}
         assert obj1.callback == callback1
-        assert set(obj2.spec.args) == {"foo", "bar", "baz"}
+        assert set(obj2.params) == {"foo", "bar", "baz"}
         assert obj2.callback == callback2
 
     @pytest.mark.parametrize(
@@ -124,7 +124,9 @@ class TestCallableMixin:
             ),
         ],
     )
-    def test_prepare_kwargs(self, callback, kwargs, result):
+    def test_prepare_kwargs(
+        self, callback: Callable, kwargs: Dict[str, Any], result: Dict[str, Any]
+    ):
         obj = CallableMixin(callback)
         assert obj._prepare_kwargs(kwargs) == result