From 2e2dde910ae2a0df880dc41fd6b25165a42c4b7e Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Tue, 11 Jul 2023 08:36:44 +0100 Subject: [PATCH] Preserve panic message after exception is normalized --- newsfragments/3326.fixed.md | 1 + src/err/mod.rs | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 newsfragments/3326.fixed.md diff --git a/newsfragments/3326.fixed.md b/newsfragments/3326.fixed.md new file mode 100644 index 00000000000..8353c598f72 --- /dev/null +++ b/newsfragments/3326.fixed.md @@ -0,0 +1 @@ +Fix loss of panic message in `PanicException` when unwinding after the exception was "normalized". diff --git a/src/err/mod.rs b/src/err/mod.rs index cdfb64b1249..8516cc9b1db 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -297,9 +297,10 @@ impl PyErr { }; if ptype.as_ptr() == PanicException::type_object_raw(py).cast() { - let msg: String = pvalue + let msg = pvalue .as_ref() - .and_then(|obj| obj.extract(py).ok()) + .and_then(|obj| obj.as_ref(py).str().ok()) + .map(|py_str| py_str.to_string_lossy().into()) .unwrap_or_else(|| String::from("Unwrapped panic from Python code")); eprintln!( @@ -845,6 +846,25 @@ mod tests { }); } + #[test] + #[should_panic(expected = "new panic")] + #[cfg(not(Py_3_12))] + fn fetching_normalized_panic_exception_resumes_unwind() { + use crate::panic::PanicException; + + Python::with_gil(|py| { + let err: PyErr = PanicException::new_err("new panic"); + // Restoring an error doesn't normalize it before Python 3.12, + // so we have to explicitly test this case. + let _ = err.normalized(py); + err.restore(py); + assert!(PyErr::occurred(py)); + + // should resume unwind + let _ = PyErr::fetch(py); + }); + } + #[test] fn err_debug() { // Debug representation should be like the following (without the newlines):