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

View file

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