diff --git a/frappe/__init__.py b/frappe/__init__.py index 17a945c875..a172c7412d 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -1501,18 +1501,26 @@ def call(fn, *args, **kwargs): def get_newargs(fn, kwargs): + + # 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 + if hasattr(fn, "fnargs"): fnargs = fn.fnargs else: signature = inspect.signature(fn) fnargs = list(signature.parameters) - varkw = "kwargs" in fnargs - if varkw: - fnargs.pop(-1) + + 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: + if (a in fnargs) or varkw_exist: newargs[a] = kwargs.get(a) newargs.pop("ignore_permissions", None) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index f4636fc026..4f4fca8bbf 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -621,6 +621,7 @@ class TestIntrospectionMagic(unittest.TestCase): """Test utils that inspect live objects""" def test_get_newargs(self): + # `kwargs` is just convention any **varname should work. def f(a, b=2, **args): pass @@ -630,3 +631,13 @@ class TestIntrospectionMagic(unittest.TestCase): unsafe_args = dict(safe_kwargs) unsafe_args.update({"ignore_permissions": True, "flags": {"ignore_mandatory": True}}) self.assertEqual(frappe.get_newargs(f, unsafe_args), safe_kwargs) + + def test_strip_off_kwargs_when_not_supported(self): + def f(a, b=2): + pass + + args = {"company": "Wind Power", "b": 1} + self.assertEqual(frappe.get_newargs(f, args), {"b": 1}) + + # No args + self.assertEqual(frappe.get_newargs(lambda: None, args), {})