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