From c6049d7e7caea22e9b515142a36a95df83dfd93c Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 28 Feb 2022 18:12:08 +0530 Subject: [PATCH] fix: always execute method if found in `__dict__` (#15958) 285823 --- frappe/model/document.py | 14 +++++++------- frappe/tests/test_document.py | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 37e70e8126..96f933179c 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -860,14 +860,14 @@ class Document(BaseDocument): def run_method(self, method, *args, **kwargs): """run standard triggers, plus those in hooks""" - if "flags" in kwargs: - del kwargs["flags"] - if hasattr(self, method) and hasattr(getattr(self, method), "__call__"): - fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs) - else: - # hack! to run hooks even if method does not exist - fn = lambda self, *args, **kwargs: None + def fn(self, *args, **kwargs): + method_object = getattr(self, method, None) + + # Cannot have a field with same name as method + # If method found in __dict__, expect it to be callable + if method in self.__dict__ or callable(method_object): + return method_object(*args, **kwargs) fn.__name__ = str(method) out = Document.hook(fn)(self, *args, **kwargs) diff --git a/frappe/tests/test_document.py b/frappe/tests/test_document.py index 18f104c28d..55dbf001f9 100644 --- a/frappe/tests/test_document.py +++ b/frappe/tests/test_document.py @@ -319,3 +319,21 @@ class TestDocument(unittest.TestCase): self.assertIsInstance(doc, Note) self.assertIsInstance(doc.as_dict().get("age"), timedelta) self.assertIsInstance(doc.get_valid_dict().get("age"), timedelta) + + def test_run_method(self): + doc = frappe.get_last_doc("User") + + # Case 1: Override with a string + doc.as_dict = "" + + # run_method should throw TypeError + self.assertRaisesRegex(TypeError, "not callable", doc.run_method, "as_dict") + + # Case 2: Override with a function + def my_as_dict(*args, **kwargs): + return "success" + + doc.as_dict = my_as_dict + + # run_method should get overridden + self.assertEqual(doc.run_method("as_dict"), "success")