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