diff --git a/frappe/__init__.py b/frappe/__init__.py index f323f58f39..12177d3037 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -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) diff --git a/frappe/utils/typing_validations.py b/frappe/utils/typing_validations.py index 5a7d40d8d6..48bc888cd2 100644 --- a/frappe/utils/typing_validations.py +++ b/frappe/utils/typing_validations.py @@ -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():