tb_set_next()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
c 1
b 0
f 0
dl 0
loc 14
rs 8
1
"""
2
Taken verbatim from Jinja2.
3
4
https://github.com/mitsuhiko/jinja2/blob/master/jinja2/debug.py#L267
5
"""
6
import platform
7
import sys
8
9
10
def _init_ugly_crap():
11
    """This function implements a few ugly things so that we can patch the
12
    traceback objects.  The function returned allows resetting `tb_next` on
13
    any python traceback object.  Do not attempt to use this on non cpython
14
    interpreters
15
    """
16
    import ctypes
17
    from types import TracebackType
18
19
    # figure out side of _Py_ssize_t
20
    if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
21
        _Py_ssize_t = ctypes.c_int64
22
    else:
23
        _Py_ssize_t = ctypes.c_int
24
25
    # regular python
26
    class _PyObject(ctypes.Structure):
27
        pass
28
29
    _PyObject._fields_ = [
30
        ('ob_refcnt', _Py_ssize_t),
31
        ('ob_type', ctypes.POINTER(_PyObject))
32
    ]
33
34
    # python with trace
35
    if hasattr(sys, 'getobjects'):
36
        class _PyObject(ctypes.Structure):
37
            pass
38
39
        _PyObject._fields_ = [
40
            ('_ob_next', ctypes.POINTER(_PyObject)),
41
            ('_ob_prev', ctypes.POINTER(_PyObject)),
42
            ('ob_refcnt', _Py_ssize_t),
43
            ('ob_type', ctypes.POINTER(_PyObject))
44
        ]
45
46
    class _Traceback(_PyObject):
47
        pass
48
49
    _Traceback._fields_ = [
50
        ('tb_next', ctypes.POINTER(_Traceback)),
51
        ('tb_frame', ctypes.POINTER(_PyObject)),
52
        ('tb_lasti', ctypes.c_int),
53
        ('tb_lineno', ctypes.c_int)
54
    ]
55
56
    def tb_set_next(tb, next):
57
        """Set the tb_next attribute of a traceback object."""
58
        if not (isinstance(tb, TracebackType) and (next is None or isinstance(next, TracebackType))):
59
            raise TypeError('tb_set_next arguments must be traceback objects')
60
        obj = _Traceback.from_address(id(tb))
61
        if tb.tb_next is not None:
62
            old = _Traceback.from_address(id(tb.tb_next))
63
            old.ob_refcnt -= 1
64
        if next is None:
65
            obj.tb_next = ctypes.POINTER(_Traceback)()
66
        else:
67
            next = _Traceback.from_address(id(next))
68
            next.ob_refcnt += 1
69
            obj.tb_next = ctypes.pointer(next)
70
71
    return tb_set_next
72
73
74
tb_set_next = None
75
try:
76
    if platform.python_implementation() == 'CPython':
77
        tb_set_next = _init_ugly_crap()
78
except Exception as exc:
79
    sys.stderr.write("Failed to initialize cpython support: {!r}".format(exc))
80
del _init_ugly_crap
81