Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cache results of _validate_wrapped_fn #450

Merged
merged 1 commit into from
Nov 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading