Commit 0698cfe5 authored by Arnaud Fontaine's avatar Arnaud Fontaine

linecache: Display source code of TALES Expressions and add support for ipdb.

Signed-off-by: Julien Muchembled's avatarJulien Muchembled <jm@nexedi.com>
parent 6f92189a
......@@ -26,7 +26,7 @@
#
##############################################################################
import os, sys
import os, re, sys
if sys.version_info < (2, 7):
......@@ -100,46 +100,75 @@ if 1:
from docutils import utils
utils.relative_path = lambda source, target: os.path.abspath(target)
import linecache
linecache_getlines = linecache.getlines
def getlines(filename, module_globals=None):
"""
Patch of linecache module (used in traceback and pdb module) to display ZODB
Components and Python Script source code properly without requiring to
create a temporary file on the filesystem
The filename is always '<string>' for any code executed by exec() (ZODB
Components) and '(FILENAME)?Script \(Python\)' for Zope Python Scripts.
linecache.cache filled by linecache.updatecache() called by the original
linecache.getlines() is bypassed for ZODB Components and Python Script to
avoid getting inconsistent source code. Having no cache could be an issue if
performances would be required here but as linecache module is only called
by traceback and pdb modules not used often, this should not be an issue.
"""
if filename and module_globals:
data = None
# Get source code of ZODB Components (following PEP 302)
if filename == '<string>' 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:
def patch_linecache():
import linecache
from os.path import basename
expr_search = re.compile('^Python expression "(.+)"$').search
def get_globals(frame):
"""
ipdb does not pass module_globals to getlines()...
"""
m = frame.f_globals['__name__']
if m == 'linecache':
frame = frame.f_back
m = frame.f_globals['__name__']
if m == 'IPython.core.debugger':
co_name = frame.f_code.co_name
if co_name == 'format_stack_entry':
return frame.f_locals['frame'].f_globals
elif co_name == 'print_list_lines':
return frame.f_locals['self'].curframe.f_globals
linecache_getlines = linecache.getlines
def getlines(filename, module_globals=None):
"""
Patch of linecache module (used in traceback, ipdb, and pdb modules) to
display ZODB Components, Python Script source code and TALES Expressions
properly without requiring to create a temporary file on the filesystem
The filename is is always '<string>' for any code executed by exec() (ZODB
Components), '(FILENAME)?Script \(Python\)' for Zope Python Scripts and
'Python Expression "CODE"' for TALES expressions.
linecache.cache filled by linecache.updatecache() called by the original
linecache.getlines() is bypassed for Python Script to avoid getting
inconsistent source code. Having no cache could be an issue if performances
would be required here but as linecache module is only called by traceback
and pdb modules not used often, this should not be an issue.
"""
if filename:
if module_globals is None:
module_globals = get_globals(sys._getframe(1))
# Get source code of ZODB Components (following PEP 302)
if filename == '<string>' and '__loader__' in module_globals:
data = None
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
return data.splitlines(True) if data is not None else ()
if basename(filename) == 'Script (Python)':
try:
data = get_source(name)
except (ImportError, AttributeError):
script = module_globals['script']
if script._p_jar.opened:
return script.body().splitlines(True)
except Exception:
pass
return ()
x = expr_search(filename)
if x:
return x.groups()
return linecache_getlines(filename, module_globals)
# Get source code of Zope Python Script
elif 'Script (Python)' in filename and 'script' in module_globals:
data = module_globals['script'].body()
linecache.getlines = getlines
if data is not None:
data = [line + '\n' for line in data.splitlines()]
return data
return linecache_getlines(filename, module_globals)
linecache.getlines = getlines
patch_linecache()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment