@@ -27,26 +27,138 @@ _Py_IDENTIFIER(close);
27
27
_Py_IDENTIFIER (open );
28
28
_Py_IDENTIFIER (path );
29
29
30
+ /*[clinic input]
31
+ class TracebackType "PyTracebackObject *" "&PyTraceback_Type"
32
+ [clinic start generated code]*/
33
+ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=928fa06c10151120]*/
34
+
35
+ #include "clinic/traceback.c.h"
36
+
37
+ static PyObject *
38
+ tb_create_raw (PyTracebackObject * next , PyFrameObject * frame , int lasti ,
39
+ int lineno )
40
+ {
41
+ PyTracebackObject * tb ;
42
+ if ((next != NULL && !PyTraceBack_Check (next )) ||
43
+ frame == NULL || !PyFrame_Check (frame )) {
44
+ PyErr_BadInternalCall ();
45
+ return NULL ;
46
+ }
47
+ tb = PyObject_GC_New (PyTracebackObject , & PyTraceBack_Type );
48
+ if (tb != NULL ) {
49
+ Py_XINCREF (next );
50
+ tb -> tb_next = next ;
51
+ Py_XINCREF (frame );
52
+ tb -> tb_frame = frame ;
53
+ tb -> tb_lasti = lasti ;
54
+ tb -> tb_lineno = lineno ;
55
+ PyObject_GC_Track (tb );
56
+ }
57
+ return (PyObject * )tb ;
58
+ }
59
+
60
+ /*[clinic input]
61
+ @classmethod
62
+ TracebackType.__new__ as tb_new
63
+
64
+ tb_next: object
65
+ tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type')
66
+ tb_lasti: int
67
+ tb_lineno: int
68
+
69
+ Create a new traceback object.
70
+ [clinic start generated code]*/
71
+
72
+ static PyObject *
73
+ tb_new_impl (PyTypeObject * type , PyObject * tb_next , PyFrameObject * tb_frame ,
74
+ int tb_lasti , int tb_lineno )
75
+ /*[clinic end generated code: output=fa077debd72d861a input=01cbe8ec8783fca7]*/
76
+ {
77
+ if (tb_next == Py_None ) {
78
+ tb_next = NULL ;
79
+ } else if (!PyTraceBack_Check (tb_next )) {
80
+ return PyErr_Format (PyExc_TypeError ,
81
+ "expected traceback object or None, got '%s'" ,
82
+ Py_TYPE (tb_next )-> tp_name );
83
+ }
84
+
85
+ return tb_create_raw ((PyTracebackObject * )tb_next , tb_frame , tb_lasti ,
86
+ tb_lineno );
87
+ }
88
+
30
89
static PyObject *
31
90
tb_dir (PyTracebackObject * self )
32
91
{
33
92
return Py_BuildValue ("[ssss]" , "tb_frame" , "tb_next" ,
34
93
"tb_lasti" , "tb_lineno" );
35
94
}
36
95
96
+ static PyObject *
97
+ tb_next_get (PyTracebackObject * self , void * Py_UNUSED (_ ))
98
+ {
99
+ PyObject * ret = (PyObject * )self -> tb_next ;
100
+ if (!ret ) {
101
+ ret = Py_None ;
102
+ }
103
+ Py_INCREF (ret );
104
+ return ret ;
105
+ }
106
+
107
+ static int
108
+ tb_next_set (PyTracebackObject * self , PyObject * new_next , void * Py_UNUSED (_ ))
109
+ {
110
+ if (!new_next ) {
111
+ PyErr_Format (PyExc_TypeError , "can't delete tb_next attribute" );
112
+ return -1 ;
113
+ }
114
+
115
+ /* We accept None or a traceback object, and map None -> NULL (inverse of
116
+ tb_next_get) */
117
+ if (new_next == Py_None ) {
118
+ new_next = NULL ;
119
+ } else if (!PyTraceBack_Check (new_next )) {
120
+ PyErr_Format (PyExc_TypeError ,
121
+ "expected traceback object, got '%s'" ,
122
+ Py_TYPE (new_next )-> tp_name );
123
+ return -1 ;
124
+ }
125
+
126
+ /* Check for loops */
127
+ PyTracebackObject * cursor = (PyTracebackObject * )new_next ;
128
+ while (cursor ) {
129
+ if (cursor == self ) {
130
+ PyErr_Format (PyExc_ValueError , "traceback loop detected" );
131
+ return -1 ;
132
+ }
133
+ cursor = cursor -> tb_next ;
134
+ }
135
+
136
+ PyObject * old_next = (PyObject * )self -> tb_next ;
137
+ Py_XINCREF (new_next );
138
+ self -> tb_next = (PyTracebackObject * )new_next ;
139
+ Py_XDECREF (old_next );
140
+
141
+ return 0 ;
142
+ }
143
+
144
+
37
145
static PyMethodDef tb_methods [] = {
38
146
{"__dir__" , (PyCFunction )tb_dir , METH_NOARGS },
39
147
{NULL , NULL , 0 , NULL },
40
148
};
41
149
42
150
static PyMemberDef tb_memberlist [] = {
43
- {"tb_next" , T_OBJECT , OFF (tb_next ), READONLY },
44
151
{"tb_frame" , T_OBJECT , OFF (tb_frame ), READONLY },
45
152
{"tb_lasti" , T_INT , OFF (tb_lasti ), READONLY },
46
153
{"tb_lineno" , T_INT , OFF (tb_lineno ), READONLY },
47
154
{NULL } /* Sentinel */
48
155
};
49
156
157
+ static PyGetSetDef tb_getsetters [] = {
158
+ {"tb_next" , (getter )tb_next_get , (setter )tb_next_set , NULL , NULL },
159
+ {NULL } /* Sentinel */
160
+ };
161
+
50
162
static void
51
163
tb_dealloc (PyTracebackObject * tb )
52
164
{
@@ -94,7 +206,7 @@ PyTypeObject PyTraceBack_Type = {
94
206
0 , /* tp_setattro */
95
207
0 , /* tp_as_buffer */
96
208
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC ,/* tp_flags */
97
- 0 , /* tp_doc */
209
+ tb_new__doc__ , /* tp_doc */
98
210
(traverseproc )tb_traverse , /* tp_traverse */
99
211
(inquiry )tb_clear , /* tp_clear */
100
212
0 , /* tp_richcompare */
@@ -103,39 +215,24 @@ PyTypeObject PyTraceBack_Type = {
103
215
0 , /* tp_iternext */
104
216
tb_methods , /* tp_methods */
105
217
tb_memberlist , /* tp_members */
106
- 0 , /* tp_getset */
218
+ tb_getsetters , /* tp_getset */
107
219
0 , /* tp_base */
108
220
0 , /* tp_dict */
221
+ 0 , /* tp_descr_get */
222
+ 0 , /* tp_descr_set */
223
+ 0 , /* tp_dictoffset */
224
+ 0 , /* tp_init */
225
+ 0 , /* tp_alloc */
226
+ tb_new , /* tp_new */
109
227
};
110
228
111
- static PyTracebackObject *
112
- newtracebackobject (PyTracebackObject * next , PyFrameObject * frame )
113
- {
114
- PyTracebackObject * tb ;
115
- if ((next != NULL && !PyTraceBack_Check (next )) ||
116
- frame == NULL || !PyFrame_Check (frame )) {
117
- PyErr_BadInternalCall ();
118
- return NULL ;
119
- }
120
- tb = PyObject_GC_New (PyTracebackObject , & PyTraceBack_Type );
121
- if (tb != NULL ) {
122
- Py_XINCREF (next );
123
- tb -> tb_next = next ;
124
- Py_XINCREF (frame );
125
- tb -> tb_frame = frame ;
126
- tb -> tb_lasti = frame -> f_lasti ;
127
- tb -> tb_lineno = PyFrame_GetLineNumber (frame );
128
- PyObject_GC_Track (tb );
129
- }
130
- return tb ;
131
- }
132
-
133
229
int
134
230
PyTraceBack_Here (PyFrameObject * frame )
135
231
{
136
232
PyObject * exc , * val , * tb , * newtb ;
137
233
PyErr_Fetch (& exc , & val , & tb );
138
- newtb = (PyObject * )newtracebackobject ((PyTracebackObject * )tb , frame );
234
+ newtb = tb_create_raw ((PyTracebackObject * )tb , frame , frame -> f_lasti ,
235
+ PyFrame_GetLineNumber (frame ));
139
236
if (newtb == NULL ) {
140
237
_PyErr_ChainExceptions (exc , val , tb );
141
238
return -1 ;
0 commit comments