xref: /aosp_15_r20/external/libchrome/third_party/jinja2/debug.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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