1
1
// Copyright (c) 2017-present PyO3 Project and Contributors
2
2
3
+ use crate :: panic:: PanicException ;
3
4
use crate :: type_object:: PyTypeObject ;
4
5
use crate :: types:: PyType ;
5
6
use crate :: { exceptions, ffi} ;
6
7
use 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 ,
9
10
} ;
10
11
use libc:: c_int;
11
12
use std:: ffi:: CString ;
@@ -168,12 +169,20 @@ impl PyErr {
168
169
///
169
170
/// The error is cleared from the Python interpreter.
170
171
/// If no error is set, returns a `SystemError`.
171
- pub fn fetch ( _ : Python ) -> PyErr {
172
+ pub fn fetch ( py : Python ) -> PyErr {
172
173
unsafe {
173
174
let mut ptype: * mut ffi:: PyObject = std:: ptr:: null_mut ( ) ;
174
175
let mut pvalue: * mut ffi:: PyObject = std:: ptr:: null_mut ( ) ;
175
176
let mut ptraceback: * mut ffi:: PyObject = std:: ptr:: null_mut ( ) ;
176
177
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
+
177
186
PyErr :: new_from_ffi_tuple ( ptype, pvalue, ptraceback)
178
187
}
179
188
}
@@ -564,6 +573,7 @@ pub fn error_on_minusone(py: Python, result: c_int) -> PyResult<()> {
564
573
#[ cfg( test) ]
565
574
mod tests {
566
575
use crate :: exceptions;
576
+ use crate :: panic:: PanicException ;
567
577
use crate :: { PyErr , Python } ;
568
578
569
579
#[ test]
@@ -575,4 +585,15 @@ mod tests {
575
585
assert ! ( PyErr :: occurred( py) ) ;
576
586
drop ( PyErr :: fetch ( py) ) ;
577
587
}
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
+ }
578
599
}
0 commit comments