@@ -27,26 +27,138 @@ _Py_IDENTIFIER(close);
2727_Py_IDENTIFIER (open );
2828_Py_IDENTIFIER (path );
2929
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+
3089static PyObject *
3190tb_dir (PyTracebackObject * self )
3291{
3392 return Py_BuildValue ("[ssss]" , "tb_frame" , "tb_next" ,
3493 "tb_lasti" , "tb_lineno" );
3594}
3695
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+
37145static PyMethodDef tb_methods [] = {
38146 {"__dir__" , (PyCFunction )tb_dir , METH_NOARGS },
39147 {NULL , NULL , 0 , NULL },
40148};
41149
42150static PyMemberDef tb_memberlist [] = {
43- {"tb_next" , T_OBJECT , OFF (tb_next ), READONLY },
44151 {"tb_frame" , T_OBJECT , OFF (tb_frame ), READONLY },
45152 {"tb_lasti" , T_INT , OFF (tb_lasti ), READONLY },
46153 {"tb_lineno" , T_INT , OFF (tb_lineno ), READONLY },
47154 {NULL } /* Sentinel */
48155};
49156
157+ static PyGetSetDef tb_getsetters [] = {
158+ {"tb_next" , (getter )tb_next_get , (setter )tb_next_set , NULL , NULL },
159+ {NULL } /* Sentinel */
160+ };
161+
50162static void
51163tb_dealloc (PyTracebackObject * tb )
52164{
@@ -94,7 +206,7 @@ PyTypeObject PyTraceBack_Type = {
94206 0 , /* tp_setattro */
95207 0 , /* tp_as_buffer */
96208 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC ,/* tp_flags */
97- 0 , /* tp_doc */
209+ tb_new__doc__ , /* tp_doc */
98210 (traverseproc )tb_traverse , /* tp_traverse */
99211 (inquiry )tb_clear , /* tp_clear */
100212 0 , /* tp_richcompare */
@@ -103,39 +215,24 @@ PyTypeObject PyTraceBack_Type = {
103215 0 , /* tp_iternext */
104216 tb_methods , /* tp_methods */
105217 tb_memberlist , /* tp_members */
106- 0 , /* tp_getset */
218+ tb_getsetters , /* tp_getset */
107219 0 , /* tp_base */
108220 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 */
109227};
110228
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-
133229int
134230PyTraceBack_Here (PyFrameObject * frame )
135231{
136232 PyObject * exc , * val , * tb , * newtb ;
137233 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 ));
139236 if (newtb == NULL ) {
140237 _PyErr_ChainExceptions (exc , val , tb );
141238 return -1 ;
0 commit comments