From 98aa2e30402cb1fbe433ab3c5ef608a0c5fb3d93 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Tue, 26 Nov 2024 18:42:21 -0400 Subject: [PATCH] feat: cache results of _validate_wrapped_fn (#450) --- a_sync/a_sync/function.pyx | 42 +++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/a_sync/a_sync/function.pyx b/a_sync/a_sync/function.pyx index 05454dcb..3360db9b 100644 --- a/a_sync/a_sync/function.pyx +++ b/a_sync/a_sync/function.pyx @@ -100,24 +100,35 @@ cpdef void _validate_wrapped_fn(fn: Callable): See Also: - :func:`_check_not_genfunc` """ - if isinstance(fn, (AsyncPropertyDescriptor, AsyncCachedPropertyDescriptor)): + typ = type(fn) + if typ is _function_type: + _check_not_genfunc_cached(fn) + _validate_argspec_cached(fn) + return + if issubclass(typ, (AsyncPropertyDescriptor, AsyncCachedPropertyDescriptor)): return # These are always valid - elif isinstance(fn, _LRUCacheWrapper): + elif issubclass(typ, _LRUCacheWrapper): fn = fn.__wrapped__ + if type(fn) is _function_type: + _check_not_genfunc_cached(fn) + _validate_argspec_cached(fn) + return elif not callable(fn): raise TypeError(f"Input is not callable. Unable to decorate {fn}") - _check_not_genfunc(fn) - try: - _validate_argspec(fn) - except TypeError: - __validate_argspec(fn) + _validate_argspec(fn) + +cdef object _function_type = type(logging.getLogger) + +cdef set[Py_ssize_t] _argspec_validated = set() -@functools.lru_cache(maxsize=4096) -def _validate_argspec(fn: Callable): - __validate_argspec(fn) +cdef void _validate_argspec_cached(fn: Callable): + cdef Py_ssize_t fid = id(fn) + if fid not in _argspec_validated: + _validate_argspec(fn) + _argspec_validated.add(fid) -def __validate_argspec(fn: Callable): +cdef void _validate_argspec(fn: Callable): fn_args = inspect.getfullargspec(fn)[0] for flag in VIABLE_FLAGS: if flag in fn_args: @@ -125,7 +136,6 @@ def __validate_argspec(fn: Callable): f"{fn} must not have any arguments with the following names: {VIABLE_FLAGS}" ) - cdef inline bint _run_sync(object function, dict kwargs): """ Determines whether to run the function synchronously or asynchronously. @@ -961,6 +971,14 @@ class ASyncDecorator(_ModifiedMixin): return ASyncFunctionSyncDefault(func, **self.modifiers) +cdef set[Py_ssize_t] _is_genfunc_cache = set() + +cdef void _check_not_genfunc_cached(func: Callable): + cdef Py_ssize_t fid = id(func) + if fid not in _is_genfunc_cache: + _check_not_genfunc(func) + _is_genfunc_cache.add(fid) + cdef void _check_not_genfunc(func: Callable): """Raises an error if the function is a generator or async generator.