1- use crate :: PyObject ;
2- use crate :: pystate:: with_vm;
1+ use crate :: object :: define_py_check ;
2+ use crate :: { PyObject , pystate:: with_vm} ;
33use core:: convert:: Infallible ;
44use core:: ffi:: { CStr , c_char, c_int} ;
55use core:: ptr:: NonNull ;
@@ -96,6 +96,8 @@ define_exception_statics! {
9696 PyExc_EncodingWarning => encoding_warning,
9797}
9898
99+ define_py_check ! ( fn PyExceptionInstance_Check , exceptions. base_exception_type) ;
100+
99101#[ unsafe( no_mangle) ]
100102pub extern "C" fn PyErr_Occurred ( ) -> * mut PyObject {
101103 with_vm ( |vm| {
@@ -191,6 +193,15 @@ pub unsafe extern "C" fn PyErr_WriteUnraisable(obj: *mut PyObject) {
191193 } )
192194}
193195
196+ #[ unsafe( no_mangle) ]
197+ pub unsafe extern "C" fn PyExceptionClass_Check ( obj : * mut PyObject ) -> c_int {
198+ with_vm ( |vm| unsafe {
199+ obj. as_ref ( )
200+ . and_then ( |obj| obj. downcast_ref :: < PyType > ( ) )
201+ . is_some_and ( |ty| ty. is_subtype ( vm. ctx . exceptions . base_exception_type ) )
202+ } )
203+ }
204+
194205#[ unsafe( no_mangle) ]
195206pub unsafe extern "C" fn PyErr_NewException (
196207 name : * const c_char ,
@@ -252,6 +263,39 @@ pub unsafe extern "C" fn PyErr_GivenExceptionMatches(
252263 } )
253264}
254265
266+ #[ unsafe( no_mangle) ]
267+ pub unsafe extern "C" fn PyException_GetTraceback ( exc : * mut PyObject ) -> * mut PyObject {
268+ with_vm ( |vm| {
269+ let exc = unsafe { & * exc } . try_downcast_ref :: < PyBaseException > ( vm) ?;
270+ let tb = exc
271+ . __traceback__ ( )
272+ . map ( |tb| tb. into_object ( ) . into_raw ( ) . as_ptr ( ) )
273+ . unwrap_or_default ( ) ;
274+ Ok ( tb)
275+ } )
276+ }
277+
278+ #[ unsafe( no_mangle) ]
279+ pub unsafe extern "C" fn PyException_GetCause ( exc : * mut PyObject ) -> * mut PyObject {
280+ with_vm ( |vm| {
281+ let exc = unsafe { & * exc } . try_downcast_ref :: < PyBaseException > ( vm) ?;
282+ let cause = exc
283+ . __cause__ ( )
284+ . map ( |cause| cause. into_object ( ) . into_raw ( ) . as_ptr ( ) )
285+ . unwrap_or_default ( ) ;
286+ Ok ( cause)
287+ } )
288+ }
289+
290+ #[ unsafe( no_mangle) ]
291+ pub unsafe extern "C" fn PyException_GetContext ( exc : * mut PyObject ) -> * mut PyObject {
292+ with_vm ( |vm| {
293+ let exc = unsafe { & * exc } . try_downcast_ref :: < PyBaseException > ( vm) ?;
294+ let context = exc. __context__ ( ) . map ( |context| context. into_object ( ) ) ;
295+ Ok ( vm. unwrap_or_none ( context) )
296+ } )
297+ }
298+
255299#[ cfg( test) ]
256300mod tests {
257301 use pyo3:: exceptions:: PyTypeError ;
@@ -274,4 +318,33 @@ mod tests {
274318 assert ! ( err. is_instance_of:: <PyTypeError >( py) ) ;
275319 } )
276320 }
321+
322+ #[ test]
323+ fn test_exception_get_cause_and_context ( ) {
324+ Python :: attach ( |py| {
325+ let cause = PyTypeError :: new_err ( "cause" ) . into_value ( py) ;
326+ let context = PyTypeError :: new_err ( "context" ) . into_value ( py) ;
327+ let exc = PyTypeError :: new_err ( "exc" ) . into_value ( py) ;
328+
329+ unsafe {
330+ pyo3:: ffi:: PyException_SetCause ( exc. as_ptr ( ) , cause. into_ptr ( ) ) ;
331+ pyo3:: ffi:: PyException_SetContext ( exc. as_ptr ( ) , context. into_ptr ( ) ) ;
332+
333+ assert ! ( !pyo3:: ffi:: PyException_GetCause ( exc. as_ptr( ) ) . is_null( ) ) ;
334+ assert ! ( !pyo3:: ffi:: PyException_GetContext ( exc. as_ptr( ) ) . is_null( ) ) ;
335+ }
336+ } )
337+ }
338+
339+ #[ test]
340+ fn test_exception_get_cause_and_context_null ( ) {
341+ Python :: attach ( |py| {
342+ let exc = PyTypeError :: new_err ( "exc" ) . into_value ( py) ;
343+
344+ unsafe {
345+ assert ! ( pyo3:: ffi:: PyException_GetCause ( exc. as_ptr( ) ) . is_null( ) ) ;
346+ assert ! ( pyo3:: ffi:: PyException_GetContext ( exc. as_ptr( ) ) . is_null( ) ) ;
347+ }
348+ } )
349+ }
277350}
0 commit comments