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