Merge remote-tracking branch 'origin/dev-3.x' into dev-3.x

This commit is contained in:
JRoot Junior 2023-11-14 02:54:34 +02:00
commit 2f1ae0a686
No known key found for this signature in database
GPG key ID: 738964250D5FF6E2
8 changed files with 23 additions and 16 deletions

1
CHANGES/1353.doc.rst Normal file
View file

@ -0,0 +1 @@
Minor typo correction in middleware docs.

1
CHANGES/1357.misc.rst Normal file
View file

@ -0,0 +1 @@
Speeded up CallableMixin processing by caching references to nested objects and simplifying kwargs assembly.

1
CHANGES/1360.bugfix.rst Normal file
View file

@ -0,0 +1 @@
Added current handler to filters, so that flags can be retrieved from it.

View file

@ -4,7 +4,7 @@ import inspect
import warnings import warnings
from dataclasses import dataclass, field from dataclasses import dataclass, field
from functools import partial 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 from magic_filter.magic import MagicFilter as OriginalMagicFilter
@ -21,20 +21,21 @@ CallbackType = Callable[..., Any]
class CallableMixin: class CallableMixin:
callback: CallbackType callback: CallbackType
awaitable: bool = field(init=False) 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: def __post_init__(self) -> None:
callback = inspect.unwrap(self.callback) callback = inspect.unwrap(self.callback)
self.awaitable = inspect.isawaitable(callback) or inspect.iscoroutinefunction(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]: def _prepare_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
if self.spec.varkw: if self.varkw:
return kwargs return kwargs
return { return {k: kwargs[k] for k in self.params if k in kwargs}
k: v for k, v in kwargs.items() if k in self.spec.args or k in self.spec.kwonlyargs
}
async def call(self, *args: Any, **kwargs: Any) -> Any: async def call(self, *args: Any, **kwargs: Any) -> Any:
wrapped = partial(self.callback, *args, **self._prepare_kwargs(kwargs)) wrapped = partial(self.callback, *args, **self._prepare_kwargs(kwargs))

View file

@ -109,9 +109,10 @@ class TelegramEventObserver:
Handler will be called when all its filters are pass. Handler will be called when all its filters are pass.
""" """
for handler in self.handlers: for handler in self.handlers:
kwargs["handler"] = handler
result, data = await handler.check(event, **kwargs) result, data = await handler.check(event, **kwargs)
if result: if result:
kwargs.update(data, handler=handler) kwargs.update(data)
try: try:
wrapped_inner = self.outer_middleware.wrap_middlewares( wrapped_inner = self.outer_middleware.wrap_middlewares(
self._resolve_middlewares(), self._resolve_middlewares(),

View file

@ -53,7 +53,7 @@ Class based session middleware
.. note:: .. 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` just import it :code:`from aiogram.client.session.middlewares.request_logging import RequestLogging`

View file

@ -36,6 +36,7 @@ from aiogram.methods import (
UnpinChatMessage, UnpinChatMessage,
) )
from aiogram.types import ( from aiogram.types import (
UNSET_PARSE_MODE,
Animation, Animation,
Audio, Audio,
Chat, Chat,
@ -75,7 +76,6 @@ from aiogram.types import (
VideoNote, VideoNote,
Voice, Voice,
WebAppData, WebAppData,
UNSET_PARSE_MODE,
) )
from aiogram.types.message import ContentType, Message from aiogram.types.message import ContentType, Message

View file

@ -1,5 +1,5 @@
import functools import functools
from typing import Any, Dict, Union from typing import Any, Dict, Union, Callable, Set
import pytest import pytest
from magic_filter import F as A from magic_filter import F as A
@ -61,9 +61,9 @@ class TestCallableMixin:
pytest.param(SyncCallable(), {"self", "foo", "bar", "baz"}), 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) obj = CallableMixin(callback)
assert set(obj.spec.args) == args assert set(obj.params) == args
def test_init_decorated(self): def test_init_decorated(self):
def decorator(func): def decorator(func):
@ -85,9 +85,9 @@ class TestCallableMixin:
obj1 = CallableMixin(callback1) obj1 = CallableMixin(callback1)
obj2 = CallableMixin(callback2) obj2 = CallableMixin(callback2)
assert set(obj1.spec.args) == {"foo", "bar", "baz"} assert set(obj1.params) == {"foo", "bar", "baz"}
assert obj1.callback == callback1 assert obj1.callback == callback1
assert set(obj2.spec.args) == {"foo", "bar", "baz"} assert set(obj2.params) == {"foo", "bar", "baz"}
assert obj2.callback == callback2 assert obj2.callback == callback2
@pytest.mark.parametrize( @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) obj = CallableMixin(callback)
assert obj._prepare_kwargs(kwargs) == result assert obj._prepare_kwargs(kwargs) == result