11// Copyright (c) 2017-present PyO3 Project and Contributors
22
3+ use crate :: panic:: PanicException ;
34use crate :: type_object:: PyTypeObject ;
45use crate :: types:: PyType ;
56use crate :: { exceptions, ffi} ;
67use crate :: {
7- AsPyPointer , FromPy , IntoPy , IntoPyPointer , Py , PyAny , PyObject , Python , ToBorrowedObject ,
8- ToPyObject ,
8+ AsPyPointer , FromPy , FromPyPointer , IntoPy , IntoPyPointer , ObjectProtocol , Py , PyAny , PyObject ,
9+ Python , ToBorrowedObject , ToPyObject ,
910} ;
1011use libc:: c_int;
1112use std:: ffi:: CString ;
@@ -168,12 +169,20 @@ impl PyErr {
168169 ///
169170 /// The error is cleared from the Python interpreter.
170171 /// If no error is set, returns a `SystemError`.
171- pub fn fetch ( _ : Python ) -> PyErr {
172+ pub fn fetch ( py : Python ) -> PyErr {
172173 unsafe {
173174 let mut ptype: * mut ffi:: PyObject = std:: ptr:: null_mut ( ) ;
174175 let mut pvalue: * mut ffi:: PyObject = std:: ptr:: null_mut ( ) ;
175176 let mut ptraceback: * mut ffi:: PyObject = std:: ptr:: null_mut ( ) ;
176177 ffi:: PyErr_Fetch ( & mut ptype, & mut pvalue, & mut ptraceback) ;
178+
179+ if ptype == PanicException :: type_object ( ) . as_ptr ( ) {
180+ let msg: String = PyAny :: from_borrowed_ptr_or_opt ( py, pvalue)
181+ . and_then ( |obj| obj. extract ( ) . ok ( ) )
182+ . unwrap_or_else ( || String :: from ( "Unwrapped panic from Python code" ) ) ;
183+ panic ! ( msg)
184+ }
185+
177186 PyErr :: new_from_ffi_tuple ( ptype, pvalue, ptraceback)
178187 }
179188 }
@@ -564,6 +573,7 @@ pub fn error_on_minusone(py: Python, result: c_int) -> PyResult<()> {
564573#[ cfg( test) ]
565574mod tests {
566575 use crate :: exceptions;
576+ use crate :: panic:: PanicException ;
567577 use crate :: { PyErr , Python } ;
568578
569579 #[ test]
@@ -575,4 +585,15 @@ mod tests {
575585 assert ! ( PyErr :: occurred( py) ) ;
576586 drop ( PyErr :: fetch ( py) ) ;
577587 }
588+
589+ #[ test]
590+ fn fetching_panic_exception_panics ( ) {
591+ let gil = Python :: acquire_gil ( ) ;
592+ let py = gil. python ( ) ;
593+ let err: PyErr = PanicException :: py_err ( "new panic" ) ;
594+ err. restore ( py) ;
595+ assert ! ( PyErr :: occurred( py) ) ;
596+ let started_unwind = std:: panic:: catch_unwind ( || PyErr :: fetch ( py) ) . is_err ( ) ;
597+ assert ! ( started_unwind) ;
598+ }
578599}
0 commit comments