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