1b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# -*- coding: utf-8 -*- 2b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)""" 3b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) jinja2.debug 4b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ~~~~~~~~~~~~ 5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) Implements the debug interface for Jinja. This module does some pretty 7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ugly stuff with the Python traceback system in order to achieve tracebacks 8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) with correct line numbers, locals and contents. 9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :copyright: (c) 2010 by the Jinja Team. 11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) :license: BSD, see LICENSE for more details. 12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)""" 13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)import sys 14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)import traceback 15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from types import TracebackType 16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from jinja2.utils import CodeType, missing, internal_code 17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from jinja2.exceptions import TemplateSyntaxError 18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# on pypy we can take advantage of transparent proxies 20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)try: 21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) from __pypy__ import tproxy 22b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)except ImportError: 23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tproxy = None 24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 25b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# how does the raise helper look like? 27b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)try: 28b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exec "raise TypeError, 'foo'" 29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)except SyntaxError: 30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) raise_helper = 'raise __jinja_exception__[1]' 31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)except TypeError: 32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) raise_helper = 'raise __jinja_exception__[0], __jinja_exception__[1]' 33b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class TracebackFrameProxy(object): 36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Proxies a traceback frame.""" 37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __init__(self, tb): 39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.tb = tb 40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self._tb_next = None 41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @property 43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def tb_next(self): 44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return self._tb_next 45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 46b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def set_next(self, next): 47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if tb_set_next is not None: 48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb_set_next(self.tb, next and next.tb or None) 50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) except Exception: 51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # this function can fail due to all the hackery it does 52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # on various python implementations. We just catch errors 53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # down and ignore them if necessary. 54b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pass 55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self._tb_next = next 56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @property 58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def is_jinja_frame(self): 59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return '__jinja_template__' in self.tb.tb_frame.f_globals 60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __getattr__(self, name): 62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return getattr(self.tb, name) 63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def make_frame_proxy(frame): 66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) proxy = TracebackFrameProxy(frame) 67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if tproxy is None: 68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return proxy 69b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def operation_handler(operation, *args, **kwargs): 70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if operation in ('__getattribute__', '__getattr__'): 71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return getattr(proxy, args[0]) 72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) elif operation == '__setattr__': 73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) proxy.__setattr__(*args, **kwargs) 74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return getattr(proxy, operation)(*args, **kwargs) 76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return tproxy(TracebackType, operation_handler) 77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class ProcessedTraceback(object): 80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Holds a Jinja preprocessed traceback for priting or reraising.""" 81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __init__(self, exc_type, exc_value, frames): 83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) assert frames, 'no frames for this traceback?' 84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.exc_type = exc_type 85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.exc_value = exc_value 86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.frames = frames 87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # newly concatenate the frames (which are proxies) 89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) prev_tb = None 90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for tb in self.frames: 91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if prev_tb is not None: 92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) prev_tb.set_next(tb) 93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) prev_tb = tb 94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) prev_tb.set_next(None) 95b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def render_as_text(self, limit=None): 97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Return a string with the traceback.""" 98b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) lines = traceback.format_exception(self.exc_type, self.exc_value, 99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.frames[0], limit=limit) 100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return ''.join(lines).rstrip() 101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 102b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def render_as_html(self, full=False): 103b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Return a unicode string with the traceback as rendered HTML.""" 104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) from jinja2.debugrenderer import render_traceback 105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return u'%s\n\n<!--\n%s\n-->' % ( 106b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) render_traceback(self, full=full), 107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.render_as_text().decode('utf-8', 'replace') 108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ) 109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 110b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @property 111b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def is_template_syntax_error(self): 112b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """`True` if this is a template syntax error.""" 113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return isinstance(self.exc_value, TemplateSyntaxError) 114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 115b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @property 116b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def exc_info(self): 117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Exception info tuple with a proxy around the frame objects.""" 118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return self.exc_type, self.exc_value, self.frames[0] 119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @property 121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def standard_exc_info(self): 122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Standard python exc_info for re-raising""" 123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb = self.frames[0] 124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # the frame will be an actual traceback (or transparent proxy) if 125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # we are on pypy or a python implementation with support for tproxy 126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if type(tb) is not TracebackType: 127b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb = tb.tb 128b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return self.exc_type, self.exc_value, tb 129b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 131b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def make_traceback(exc_info, source_hint=None): 132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Creates a processed traceback object from the exc_info.""" 133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exc_type, exc_value, tb = exc_info 134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if isinstance(exc_value, TemplateSyntaxError): 135b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exc_info = translate_syntax_error(exc_value, source_hint) 136b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) initial_skip = 0 137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 138b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) initial_skip = 1 139b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return translate_exception(exc_info, initial_skip) 140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def translate_syntax_error(error, source=None): 143b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Rewrites a syntax error to please traceback systems.""" 144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) error.source = source 145b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) error.translated = True 146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exc_info = (error.__class__, error, None) 147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) filename = error.filename 148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if filename is None: 149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) filename = '<unknown>' 150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return fake_exc_info(exc_info, filename, error.lineno) 151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def translate_exception(exc_info, initial_skip=0): 154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """If passed an exc_info it will automatically rewrite the exceptions 155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) all the way down to the correct line numbers and frames. 156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb = exc_info[2] 158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) frames = [] 159b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # skip some internal frames if wanted 161b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for x in xrange(initial_skip): 162b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if tb is not None: 163b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb = tb.tb_next 164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) initial_tb = tb 165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) while tb is not None: 167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # skip frames decorated with @internalcode. These are internal 168b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # calls we can't avoid and that are useless in template debugging 169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # output. 170b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if tb.tb_frame.f_code in internal_code: 171b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb = tb.tb_next 172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) continue 173b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 174b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # save a reference to the next frame if we override the current 175b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # one with a faked one. 176b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next = tb.tb_next 177b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 178b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # fake template exceptions 179b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) template = tb.tb_frame.f_globals.get('__jinja_template__') 180b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if template is not None: 181b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) lineno = template.get_corresponding_lineno(tb.tb_lineno) 182b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb = fake_exc_info(exc_info[:2] + (tb,), template.filename, 183b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) lineno)[2] 184b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 185b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) frames.append(make_frame_proxy(tb)) 186b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb = next 187b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 188b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # if we don't have any exceptions in the frames left, we have to 189b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # reraise it unchanged. 190b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # XXX: can we backup here? when could this happen? 191b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not frames: 192b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) raise exc_info[0], exc_info[1], exc_info[2] 193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return ProcessedTraceback(exc_info[0], exc_info[1], frames) 195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def fake_exc_info(exc_info, filename, lineno): 198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Helper for `translate_exception`.""" 199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exc_type, exc_value, tb = exc_info 200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # figure the real context out 202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if tb is not None: 203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) real_locals = tb.tb_frame.f_locals.copy() 204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ctx = real_locals.get('context') 205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if ctx: 206b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) locals = ctx.get_all() 207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) locals = {} 209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for name, value in real_locals.iteritems(): 210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if name.startswith('l_') and value is not missing: 211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) locals[name[2:]] = value 212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # if there is a local called __jinja_exception__, we get 214b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # rid of it to not break the debug functionality. 215b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) locals.pop('__jinja_exception__', None) 216b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) locals = {} 218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # assamble fake globals we need 220b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) globals = { 221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) '__name__': filename, 222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) '__file__': filename, 223b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) '__jinja_exception__': exc_info[:2], 224b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 225b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # we don't want to keep the reference to the template around 226b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # to not cause circular dependencies, but we mark it as Jinja 227b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # frame for the ProcessedTraceback 228b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) '__jinja_template__': None 229b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 230b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 231b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # and fake the exception 232b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) code = compile('\n' * (lineno - 1) + raise_helper, filename, 'exec') 233b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 234b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # if it's possible, change the name of the code. This won't work 235b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # on some python environments such as google appengine 236b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 237b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if tb is None: 238b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) location = 'template' 239b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) function = tb.tb_frame.f_code.co_name 241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if function == 'root': 242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) location = 'top-level template code' 243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) elif function.startswith('block_'): 244b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) location = 'block "%s"' % function[6:] 245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 246b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) location = 'template' 247b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) code = CodeType(0, code.co_nlocals, code.co_stacksize, 248b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) code.co_flags, code.co_code, code.co_consts, 249b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) code.co_names, code.co_varnames, filename, 250b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) location, code.co_firstlineno, 251b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) code.co_lnotab, (), ()) 252b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) except: 253b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pass 254b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 255b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # execute the code and catch the new traceback 256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 257b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exec code in globals, locals 258b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) except: 259b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) exc_info = sys.exc_info() 260b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) new_tb = exc_info[2].tb_next 261b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # return without this frame 263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return exc_info[:2] + (new_tb,) 264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)def _init_ugly_crap(): 267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """This function implements a few ugly things so that we can patch the 268b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) traceback objects. The function returned allows resetting `tb_next` on 269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) any python traceback object. Do not attempt to use this on non cpython 270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) interpreters 271b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """ 272b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) import ctypes 273b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) from types import TracebackType 274b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 275b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # figure out side of _Py_ssize_t 276b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'): 277b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) _Py_ssize_t = ctypes.c_int64 278b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 279b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) _Py_ssize_t = ctypes.c_int 280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 281b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # regular python 282b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) class _PyObject(ctypes.Structure): 283b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pass 284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) _PyObject._fields_ = [ 285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('ob_refcnt', _Py_ssize_t), 286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('ob_type', ctypes.POINTER(_PyObject)) 287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ] 288b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 289b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) # python with trace 290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if hasattr(sys, 'getobjects'): 291b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) class _PyObject(ctypes.Structure): 292b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pass 293b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) _PyObject._fields_ = [ 294b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('_ob_next', ctypes.POINTER(_PyObject)), 295b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('_ob_prev', ctypes.POINTER(_PyObject)), 296b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('ob_refcnt', _Py_ssize_t), 297b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('ob_type', ctypes.POINTER(_PyObject)) 298b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ] 299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 300b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) class _Traceback(_PyObject): 301b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pass 302b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) _Traceback._fields_ = [ 303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('tb_next', ctypes.POINTER(_Traceback)), 304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('tb_frame', ctypes.POINTER(_PyObject)), 305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('tb_lasti', ctypes.c_int), 306b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ('tb_lineno', ctypes.c_int) 307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ] 308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def tb_set_next(tb, next): 310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) """Set the tb_next attribute of a traceback object.""" 311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if not (isinstance(tb, TracebackType) and 312b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) (next is None or isinstance(next, TracebackType))): 313b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) raise TypeError('tb_set_next arguments must be traceback objects') 314b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) obj = _Traceback.from_address(id(tb)) 315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if tb.tb_next is not None: 316b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) old = _Traceback.from_address(id(tb.tb_next)) 317b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) old.ob_refcnt -= 1 318b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if next is None: 319b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) obj.tb_next = ctypes.POINTER(_Traceback)() 320b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else: 321b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next = _Traceback.from_address(id(next)) 322b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) next.ob_refcnt += 1 323b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) obj.tb_next = ctypes.pointer(next) 324b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 325b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return tb_set_next 326b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 328b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# try to get a tb_set_next implementation if we don't have transparent 329b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# proxies. 330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)tb_set_next = None 331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)if tproxy is None: 332b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) from jinja2._debugsupport import tb_set_next 334b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) except ImportError: 335b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) try: 336b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) tb_set_next = _init_ugly_crap() 337b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) except: 338b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) pass 339b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) del _init_ugly_crap 340