Source code for pyzeta.framework.aop.advice

"""
TODO.

Authors:\n
- Philipp Schuette\n
"""

from typing import Callable, Generic, Optional, TypeVar

from typing_extensions import Concatenate, ParamSpec

T = TypeVar("T")
P = ParamSpec("P")


[docs] class Advice(Generic[T, P]): "Class representation of advice, i.e. an action to perform at runtime." __slots__ = ("preFunc", "postFunc")
[docs] def __init__( self, preFunc: Optional[Callable[P, None]] = None, postFunc: Optional[Callable[Concatenate[T, P], T]] = None, ) -> None: """ Initialize a new advice from callables to be applied around a point cut. At least one of the callbacks must be given. The pre callback must accept the same arguments as the wrapped method while the post callback must additionally accept the return value of the wrapped method as its first argument. :param preFunc: callback to be invoked before the point cut :param postFunc: callback to be invoked after the point cut """ if (not preFunc) and (not postFunc): raise ValueError("cannot create advice from two trivial callbacks") self.preFunc = preFunc self.postFunc = postFunc
[docs] def __call__(self, instanceMethod: Callable[P, T]) -> Callable[P, T]: """ Wrap a given method with the pre and post callbacks of the advice. :param instanceMethod: the method to wrap :return: the wrapped method """ def wrappedMethod(*args: P.args, **kwargs: P.kwargs) -> T: """ New method that coincides with the old one except for calling of pre and post functions of the advice. """ if self.preFunc: self.preFunc(*args, **kwargs) result = instanceMethod(*args, **kwargs) if self.postFunc: result = self.postFunc(result, *args, **kwargs) return result return wrappedMethod