1
2 """
3 jinja2.debug
4 ~~~~~~~~~~~~
5
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.
9
10 :copyright: (c) 2010 by the Jinja Team.
11 :license: BSD, see LICENSE for more details.
12 """
13 import sys
14 import traceback
15
17 """This function implements a few ugly things so that we can patch the
18 traceback objects. The function returned allows resetting `tb_next` on
19 any python traceback object.
20 """
21 import ctypes
22 from types import TracebackType
23
24
25 if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
26 _Py_ssize_t = ctypes.c_int64
27 else:
28 _Py_ssize_t = ctypes.c_int
29
30
31 class _PyObject(ctypes.Structure):
32 pass
33 _PyObject._fields_ = [
34 ('ob_refcnt', _Py_ssize_t),
35 ('ob_type', ctypes.POINTER(_PyObject))
36 ]
37
38
39 if object.__basicsize__ != ctypes.sizeof(_PyObject):
40 class _PyObject(ctypes.Structure):
41 pass
42 _PyObject._fields_ = [
43 ('_ob_next', ctypes.POINTER(_PyObject)),
44 ('_ob_prev', ctypes.POINTER(_PyObject)),
45 ('ob_refcnt', _Py_ssize_t),
46 ('ob_type', ctypes.POINTER(_PyObject))
47 ]
48
49 class _Traceback(_PyObject):
50 pass
51 _Traceback._fields_ = [
52 ('tb_next', ctypes.POINTER(_Traceback)),
53 ('tb_frame', ctypes.POINTER(_PyObject)),
54 ('tb_lasti', ctypes.c_int),
55 ('tb_lineno', ctypes.c_int)
56 ]
57
58 def tb_set_next(tb, next):
59 """Set the tb_next attribute of a traceback object."""
60 if not (isinstance(tb, TracebackType) and
61 (next is None or isinstance(next, TracebackType))):
62 raise TypeError('tb_set_next arguments must be traceback objects')
63 obj = _Traceback.from_address(id(tb))
64 if tb.tb_next is not None:
65 old = _Traceback.from_address(id(tb.tb_next))
66 old.ob_refcnt -= 1
67 if next is None:
68 obj.tb_next = ctypes.POINTER(_Traceback)()
69 else:
70 next = _Traceback.from_address(id(next))
71 next.ob_refcnt += 1
72 obj.tb_next = ctypes.pointer(next)
73
74 return tb_set_next
75
76
77
78 try:
79 tb_set_next = _init_ugly_crap()
80 except:
81 tb_set_next = None
82 del _init_ugly_crap
83