diff --git a/product/ERP5Type/patches/PythonScript.py b/product/ERP5Type/patches/PythonScript.py index 38d9c223bcdff2984625d60bbfac6068f76b8945..d84a904b249642af366d6eb94c8e6d60698ae92d 100644 --- a/product/ERP5Type/patches/PythonScript.py +++ b/product/ERP5Type/patches/PythonScript.py @@ -14,6 +14,21 @@ from Products.PythonScripts.PythonScript import PythonScript from OFS.misc_ import p_ from App.ImageFile import ImageFile +PythonScript_write = PythonScript.write +def write(self, text): + """ + Change the Python Script and purge linecache cache entry (meaningful for any + module relying on linecache, such as traceback and pdb) + """ + PythonScript_write(self, text) + + import linecache + try: + del linecache.cache[self.get_filepath()] + except KeyError: + pass + +PythonScript.write = write def haveProxyRole(self): """if a script has proxy role, return True""" diff --git a/product/ERP5Type/patches/python.py b/product/ERP5Type/patches/python.py index ede77b23387c4141e174ee2c0c3c885fb277c0dc..b9746d7cfd9ffd075ff2065aeabe7dd9360992ad 100644 --- a/product/ERP5Type/patches/python.py +++ b/product/ERP5Type/patches/python.py @@ -109,12 +109,14 @@ linecache_getlines = linecache.getlines def getlines(filename, module_globals=None): """ The filename is always '<string>' for any code executed by exec(). ZODB - Component modules always set __file__ attribute to <erp5.component...>. + Component modules always set __file__ attribute to <erp5.component...> and + 'Script (Python)' for Zope Python Scripts. The original getlines() will be called which look into the cache and if not available, call updatecache. """ - if filename == '<string>' and module_globals and '__file__' in module_globals: + if ((filename == '<string>' or filename == 'Script (Python)') + and module_globals and '__file__' in module_globals): filename = module_globals['__file__'] return linecache_getlines(filename, module_globals) @@ -129,25 +131,38 @@ def updatecache(filename, module_globals=None): through PEP 302 Loader, but it is perhaps to be more generic. Anyhow, <> is really needed to differenciate files on the filesystem to the ones only in memory... + + Also, get source code of Zope Python Script and store it in the linecache + cache as well (using __file__ module attribute equals to: 'Script + (Python):ABSOLUTE_URL'). See PythonScript.py patch as well to remove cache + entry when a PythonScript is modified. """ - if (filename[0] == '<' and filename[-1] == '>' and module_globals and - '__loader__' in module_globals): - name = module_globals.get('__name__') - loader = module_globals['__loader__'] - get_source = getattr(loader, 'get_source', None) - if name and get_source: - try: - data = get_source(name) - except (ImportError, AttributeError): - pass - else: - if data is None: - return [] - - data_len = len(data) - data = [line + '\n' for line in data.splitlines()] - linecache.cache[filename] = (data_len, None, data, filename) - return data + if filename and module_globals: + data = None + + # Get source code of ZODB Components (following PEP 302) + if filename[0] == '<' and filename[-1] == '>' and '__loader__' in module_globals: + name = module_globals.get('__name__') + loader = module_globals['__loader__'] + get_source = getattr(loader, 'get_source', None) + if name and get_source: + try: + data = get_source(name) + except (ImportError, AttributeError): + pass + else: + if data is None: + return [] + + # Get source code of Zope Python Script + elif filename.startswith('Script (Python)') and 'script' in module_globals: + data = module_globals['script'].body() + + if data is not None: + data_len = len(data) + data = [line + '\n' for line in data.splitlines()] + linecache.cache[filename] = (data_len, None, data, filename) + return data return linecache_updatecache(filename, module_globals)