File: pytraceback.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (115 lines) | stat: -rw-r--r-- 3,928 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import sys

from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter import baseobjspace
from pypy.interpreter.error import oefmt, OperationError
from pypy.interpreter.location import offset2lineno

# for some strange reason CPython allows the setting of the lineno to be
# negative. I am not sure why that is useful, but let's use the most negative
# value as a sentinel to denote the default behaviour "please take the lineno
# from the frame and lasti"
LINENO_NOT_COMPUTED = -sys.maxint-1

"""
"""

class PyTraceback(baseobjspace.W_Root):
    """Traceback object

    Public app-level fields:
     * 'tb_frame'
     * 'tb_lasti'
     * 'tb_lineno'
     * 'tb_next'
    """

    def __init__(self, space, frame, lasti, next, lineno=LINENO_NOT_COMPUTED):
        self.space = space
        self.frame = frame
        self.lasti = lasti
        self.next = next
        self.lineno = lineno

    def get_lineno(self):
        if self.lineno == LINENO_NOT_COMPUTED:
            self.lineno = offset2lineno(self.frame.pycode, self.lasti)
        return self.lineno

    def descr_get_tb_lineno(self, space):
        return space.newint(self.get_lineno())

    def descr_set_tb_lineno(self, space, w_lineno):
        self.lineno = space.int_w(w_lineno)

    def descr_get_tb_lasti(self, space):
        return space.newint(self.lasti)

    def descr_set_tb_lasti(self, space, w_lasti):
        self.lasti = space.int_w(w_lasti)

    def descr_get_next(self, space):
        return self.next

    def descr_set_next(self, space, w_next):
        newnext = space.interp_w(PyTraceback, w_next, can_be_None=True)
        # check for loops
        curr = newnext
        while curr is not None and isinstance(curr, PyTraceback):
            if curr is self:
                raise oefmt(space.w_ValueError, 'traceback loop detected')
            curr = curr.next
        self.next = newnext

    @staticmethod
    @unwrap_spec(lasti=int, lineno=int)
    def descr_new(space, w_subtype, w_next, w_frame, lasti, lineno):
        from pypy.interpreter.pyframe import PyFrame
        w_next = space.interp_w(PyTraceback, w_next, can_be_None=True)
        w_frame = space.interp_w(PyFrame, w_frame)
        traceback = space.allocate_instance(PyTraceback, w_subtype)
        PyTraceback.__init__(traceback, space, w_frame, lasti, w_next, lineno)
        return traceback

    def descr__reduce__(self, space):
        from pypy.interpreter.mixedmodule import MixedModule
        w_mod = space.getbuiltinmodule('_pickle_support')
        mod = space.interp_w(MixedModule, w_mod)
        new_inst = mod.get('traceback_new')

        tup_base = []
        tup_state = [
            self.frame,
            space.newint(self.lasti),
            self.next,
            space.newint(self.lineno)
        ]
        nt = space.newtuple
        return nt([new_inst, nt(tup_base), nt(tup_state)])

    def descr__setstate__(self, space, w_args):
        from pypy.interpreter.pyframe import PyFrame
        args_w = space.unpackiterable(w_args, 4)
        w_frame, w_lasti, w_next, w_lineno = args_w
        self.frame = space.interp_w(PyFrame, w_frame)
        self.lasti = space.int_w(w_lasti)
        self.next = space.interp_w(PyTraceback, w_next, can_be_None=True)
        self.lineno = space.int_w(w_lineno)

    def descr__dir__(self, space):
        return space.newlist([space.newtext(n) for n in
            ['tb_frame', 'tb_next', 'tb_lasti', 'tb_lineno']])


def record_application_traceback(space, operror, frame, last_instruction):
    if frame.pycode.hidden_applevel:
        return
    tb = operror.get_traceback()
    tb = PyTraceback(space, frame, last_instruction, tb)
    operror.set_traceback(tb)


def check_traceback(space, w_tb, msg):
    if w_tb is None or not space.isinstance_w(w_tb, space.gettypeobject(PyTraceback.typedef)):
        raise OperationError(space.w_TypeError, space.newtext(msg))
    return w_tb