Skip to content

Commit

Permalink
feat: cache results of _validate_wrapped_fn (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
BobTheBuidler authored Nov 26, 2024
1 parent b811efc commit 98aa2e3
Showing 1 changed file with 30 additions and 12 deletions.
42 changes: 30 additions & 12 deletions a_sync/a_sync/function.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -100,32 +100,42 @@ 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:
raise RuntimeError(
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.
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 98aa2e3

Please sign in to comment.