new improved CallableMixin (#1357)

* optimized CallableMixin

* changes and Sets

* reformatted

* Update CHANGES/1357.misc.rst

Co-authored-by: Oleg A. <t0rr@mail.ru>

---------

Co-authored-by: Oleg A. <t0rr@mail.ru>
This commit is contained in:
RootShinobi 2023-11-13 21:04:58 +02:00 committed by GitHub
parent 9b5e462068
commit e76f4c38ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 17 additions and 13 deletions

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.

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

@ -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