diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 50aae06990..81505e86a1 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -280,7 +280,10 @@ def execute(context, method, args=None, kwargs=None, profile=False): ret = frappe.get_attr(method)(*args, **kwargs) except Exception: # eval is safe here because input is from console - ret = eval(method + "(*args, **kwargs)", globals(), locals()) # nosemgrep + ret = eval(method, globals(), locals()) # nosemgrep + if callable(ret): + suffix = "(*args, **kwargs)" + ret = eval(method + suffix, globals(), locals()) # nosemgrep if profile: import pstats @@ -298,7 +301,7 @@ def execute(context, method, args=None, kwargs=None, profile=False): if ret: from frappe.utils.response import json_handler - print(json.dumps(ret, default=json_handler)) + print(json.dumps(ret, default=json_handler).strip('"')) if not context.sites: raise SiteNotSpecifiedError diff --git a/frappe/tests/test_commands.py b/frappe/tests/test_commands.py index 59f4c7c8fa..a875a7da15 100644 --- a/frappe/tests/test_commands.py +++ b/frappe/tests/test_commands.py @@ -224,18 +224,23 @@ class TestCommands(BaseTestCommands): self.assertEqual(self.returncode, 0) self.assertIsInstance(float(self.stdout), float) - # test 2: execute a command expecting an errored output as local won't exist + # test 2: execute a command accessing a normal attribute self.execute("bench --site {site} execute frappe.local.site") + self.assertEqual(self.returncode, 0) + self.assertIsNotNone(self.stderr) + + # test 3: execute a command expecting an errored output as lacol won't exist + self.execute("bench --site {site} execute frappe.lacol.site") self.assertEqual(self.returncode, 1) self.assertIsNotNone(self.stderr) - # test 3: execute a command with kwargs - # Note: - # terminal command has been escaped to avoid .format string replacement - # The returned value has quotes which have been trimmed for the test - self.execute("""bench --site {site} execute frappe.bold --kwargs '{{"text": "DocType"}}'""") + # test 4: execute a command with kwargs + self.execute( + "bench --site {site} execute frappe.bold --kwargs '{put_here}'", + {"put_here": '{"text": "DocType"}'}, # avoid escaping errors + ) self.assertEqual(self.returncode, 0) - self.assertEqual(self.stdout[1:-1], frappe.bold(text="DocType")) + self.assertEqual(self.stdout, frappe.bold(text="DocType")) @run_only_if(db_type_is.MARIADB) def test_restore(self):