perf: cache signature params instead of signature

This commit is contained in:
Sagar Vora 2025-03-20 00:41:46 +05:30
parent 4a04b0a17f
commit 6435a77e41
2 changed files with 23 additions and 20 deletions

View file

@ -1512,7 +1512,22 @@ def call(fn: str | Callable, *args, **kwargs):
return fn(*args, **newargs)
_cached_inspect_signature = functools.lru_cache(inspect.signature)
@functools.lru_cache
def _get_cached_signature_params(fn: Callable) -> tuple[dict[str, Any], bool]:
"""
Get cached parameters for a function.
Returns a dictionary of parameters and a boolean indicating if the function has **kwargs.
"""
signature = inspect.signature(fn)
# if function has any **kwargs parameter that capture arbitrary keyword arguments
# Ref: https://docs.python.org/3/library/inspect.html#inspect.Parameter.kind
variable_kwargs_exist = any(
parameter.kind == inspect.Parameter.VAR_KEYWORD for parameter in signature.parameters.values()
)
return dict(signature.parameters), variable_kwargs_exist
def get_newargs(fn: Callable, kwargs: dict[str, Any]) -> dict[str, Any]:
@ -1526,23 +1541,12 @@ def get_newargs(fn: Callable, kwargs: dict[str, Any]) -> dict[str, Any]:
{"a": 2}
"""
# if function has any **kwargs parameter that capture arbitrary keyword arguments
# Ref: https://docs.python.org/3/library/inspect.html#inspect.Parameter.kind
varkw_exist = False
signature = _cached_inspect_signature(fn)
fnargs = list(signature.parameters)
for param_name, parameter in signature.parameters.items():
if parameter.kind == inspect.Parameter.VAR_KEYWORD:
varkw_exist = True
fnargs.remove(param_name)
break
newargs = {}
for a in kwargs:
if (a in fnargs) or varkw_exist:
newargs[a] = kwargs.get(a)
parameters, variable_kwargs_exist = _get_cached_signature_params(fn)
newargs = (
kwargs.copy()
if variable_kwargs_exist
else {key: value for key, value in kwargs.items() if key in parameters}
)
# WARNING: This behaviour is now part of business logic in places, never remove.
newargs.pop("ignore_permissions", None)

View file

@ -124,8 +124,7 @@ def transform_parameter_types(func: Callable, args: tuple, kwargs: dict):
prepared_args = dict(zip(arg_names, args, strict=False))
# check if type hints dont match the default values
func_signature = frappe._cached_inspect_signature(func)
func_params = dict(func_signature.parameters)
func_params = frappe._get_cached_signature_params(func)[0]
# check if the argument types are correct
for current_arg, current_arg_type in annotations.items():