From b0bb1084379c5c693f9277b3d0ce044cea849dda Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Mon, 19 Jun 2023 15:31:07 +0200 Subject: [PATCH] Restore filename on code objects: `App.Extensions.getObject()`. (#1138) Since 4.0a6 the filename is missing there, resulting in problems while debugging (debugger is unable to show the code line) and coverage of Python modules loaded via Products.ExternalMethods. --- CHANGES.rst | 3 +++ src/App/Extensions.py | 3 ++- src/App/tests/fixtures/error.py | 2 ++ src/App/tests/fixtures/getObject.py | 5 ++++ src/App/tests/test_Extensions.py | 38 +++++++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/App/tests/fixtures/error.py create mode 100644 src/App/tests/fixtures/getObject.py create mode 100644 src/App/tests/test_Extensions.py diff --git a/CHANGES.rst b/CHANGES.rst index a57b4340e5..5afe97abcb 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -15,6 +15,9 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst For details, see `#1136 `_. +- Restore filename on code objects of objects returned from + ``App.Extensions.getObject()``. This got lost in 4.0a6. + - Update to newest compatible versions of dependencies. diff --git a/src/App/Extensions.py b/src/App/Extensions.py index a13c9d5c0f..dce6b121d6 100644 --- a/src/App/Extensions.py +++ b/src/App/Extensions.py @@ -180,8 +180,9 @@ def getObject(module, name, reload=0): except Exception: raise NotFound("The specified module, '%s', " "couldn't be opened." % module) + execcode = compile(execsrc, path, 'exec') module_dict = {} - exec(execsrc, module_dict) + exec(execcode, module_dict) if old is not None: # XXX Accretive?? diff --git a/src/App/tests/fixtures/error.py b/src/App/tests/fixtures/error.py new file mode 100644 index 0000000000..81fa728910 --- /dev/null +++ b/src/App/tests/fixtures/error.py @@ -0,0 +1,2 @@ +# This file intentionally contains a SyntaxError +a = # noqa diff --git a/src/App/tests/fixtures/getObject.py b/src/App/tests/fixtures/getObject.py new file mode 100644 index 0000000000..2ee5467cd2 --- /dev/null +++ b/src/App/tests/fixtures/getObject.py @@ -0,0 +1,5 @@ +import sys + + +def f1(): + return sys._getframe(0).f_code.co_filename diff --git a/src/App/tests/test_Extensions.py b/src/App/tests/test_Extensions.py new file mode 100644 index 0000000000..30d6271027 --- /dev/null +++ b/src/App/tests/test_Extensions.py @@ -0,0 +1,38 @@ +import types +import unittest +from pathlib import Path + +import App.config +from App.Extensions import getObject + + +class GetObjectTests(unittest.TestCase): + """Testing ..Extensions.getObject().""" + + def setUp(self): + cfg = App.config.getConfiguration() + assert not hasattr(cfg, 'extensions') + cfg.extensions = Path(__file__).parent / 'fixtures' + + def tearDown(self): + cfg = App.config.getConfiguration() + del cfg.extensions + + def test_Extensions__getObject__1(self): + """Check that "getObject" returns the requested function and ... + + that its code object has the path set. + """ + obj = getObject('getObject', 'f1') + self.assertIsInstance(obj, types.FunctionType) + self.assertEqual(obj.__name__, 'f1') + path = obj() + self.assertTrue( + path.endswith(str(Path('App/tests/fixtures/getObject.py')))) + + def test_Extensions__getObject__2(self): + """It raises a SyntaxError if necessary.""" + try: + getObject('error', 'f1') + except SyntaxError as e: + self.assertEqual(str(e), 'invalid syntax (error.py, line 2)')