11use crate :: err:: { error_on_minusone, PyResult } ;
22use crate :: types:: { any:: PyAnyMethods , string:: PyStringMethods , PyString } ;
33use crate :: { ffi, Bound , PyAny } ;
4+ #[ cfg( all( not( Py_LIMITED_API ) , not( PyPy ) , not( GraalPy ) ) ) ]
5+ use crate :: { types:: PyFrame , PyTypeCheck , Python } ;
46
57/// Represents a Python traceback.
68///
@@ -20,6 +22,27 @@ pyobject_native_type_core!(
2022 #checkfunction=ffi:: PyTraceBack_Check
2123) ;
2224
25+ impl PyTraceback {
26+ /// Creates a new traceback object from the given frame.
27+ ///
28+ /// The `next` is the next traceback in the direction of where the exception was raised
29+ /// or `None` if this is the last frame in the traceback.
30+ #[ cfg( all( not( Py_LIMITED_API ) , not( PyPy ) , not( GraalPy ) ) ) ]
31+ pub fn new < ' py > (
32+ py : Python < ' py > ,
33+ next : Option < Bound < ' py , PyTraceback > > ,
34+ frame : Bound < ' py , PyFrame > ,
35+ instruction_index : i32 ,
36+ line_number : i32 ,
37+ ) -> PyResult < Bound < ' py , PyTraceback > > {
38+ unsafe {
39+ Ok ( PyTraceback :: classinfo_object ( py)
40+ . call1 ( ( next, frame, instruction_index, line_number) ) ?
41+ . cast_into_unchecked ( ) )
42+ }
43+ }
44+ }
45+
2346/// Implementation of functionality for [`PyTraceback`].
2447///
2548/// These methods are defined for the `Bound<'py, PyTraceback>` smart pointer, so to use method call
@@ -82,9 +105,10 @@ impl<'py> PyTracebackMethods<'py> for Bound<'py, PyTraceback> {
82105
83106#[ cfg( test) ]
84107mod tests {
108+ use super :: * ;
85109 use crate :: IntoPyObject ;
86110 use crate :: {
87- types:: { any :: PyAnyMethods , dict:: PyDictMethods , traceback :: PyTracebackMethods , PyDict } ,
111+ types:: { dict:: PyDictMethods , PyDict } ,
88112 PyErr , Python ,
89113 } ;
90114
@@ -146,4 +170,30 @@ def f():
146170 assert ! ( err_object. getattr( "__traceback__" ) . unwrap( ) . is( & traceback) ) ;
147171 } )
148172 }
173+
174+ #[ test]
175+ #[ cfg( all( not( Py_LIMITED_API ) , not( PyPy ) , not( GraalPy ) ) ) ]
176+ fn test_create_traceback ( ) {
177+ Python :: attach ( |py| {
178+ let traceback = PyTraceback :: new (
179+ py,
180+ None ,
181+ PyFrame :: new ( py, c"file2.py" , c"func2" , 20 ) . unwrap ( ) ,
182+ 0 ,
183+ 20 ,
184+ )
185+ . unwrap ( ) ;
186+ let traceback = PyTraceback :: new (
187+ py,
188+ Some ( traceback) ,
189+ PyFrame :: new ( py, c"file1.py" , c"func1" , 10 ) . unwrap ( ) ,
190+ 0 ,
191+ 10 ,
192+ )
193+ . unwrap ( ) ;
194+ assert_eq ! (
195+ traceback. format( ) . unwrap( ) , "Traceback (most recent call last):\n File \" file1.py\" , line 10, in func1\n File \" file2.py\" , line 20, in func2\n "
196+ ) ;
197+ } )
198+ }
149199}
0 commit comments