From 2a0bfad4f760970fec1e8128a5d5f5adefa77a89 Mon Sep 17 00:00:00 2001 From: Lily Foote Date: Thu, 22 Feb 2024 10:25:38 +0000 Subject: [PATCH] Add a trait bound to From> for PyErr --- src/coroutine.rs | 2 +- src/err/mod.rs | 13 ++++++++++++- src/exceptions.rs | 2 ++ src/lib.rs | 2 +- src/tests/common.rs | 4 ++-- src/types/traceback.rs | 2 +- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/coroutine.rs b/src/coroutine.rs index 05240d70e64..b24197ad593 100644 --- a/src/coroutine.rs +++ b/src/coroutine.rs @@ -78,7 +78,7 @@ impl Coroutine { (Some(exc), Some(cb)) => cb.throw(exc), (Some(exc), None) => { self.close(); - return Err(exc.into_bound(py).into()); + return Err(PyErr::from_value_bound(exc.into_bound(py))); } (None, _) => {} } diff --git a/src/err/mod.rs b/src/err/mod.rs index e64cd420a3f..3e706b2c3e5 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -982,7 +982,18 @@ impl PyErrArguments for PyDowncastErrorArguments { } } -impl<'py, T> std::convert::From> for PyErr { +/// Python exceptions that can be converted to [`PyErr`]. +/// +/// This is used to implement [`From> for PyErr`]. +/// +/// Users should not need to implement this trait directly. It is implemented automatically in the +/// [`import_exception!`] and [`create_exception!`] macros. +pub trait ToPyErr {} + +impl<'py, T> std::convert::From> for PyErr +where + T: ToPyErr, +{ #[inline] fn from(err: Bound<'py, T>) -> PyErr { PyErr::from_value_bound(err.into_any()) diff --git a/src/exceptions.rs b/src/exceptions.rs index b38f1ea293a..ef55dcdd6e3 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -52,6 +52,8 @@ macro_rules! impl_exception_boilerplate { } } } + + impl $crate::ToPyErr for $name {} }; } diff --git a/src/lib.rs b/src/lib.rs index 0a0b4eae684..10f3088b7c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,7 +301,7 @@ pub use crate::conversion::{AsPyPointer, FromPyObject, FromPyPointer, IntoPy, To #[allow(deprecated)] pub use crate::conversion::{PyTryFrom, PyTryInto}; pub use crate::err::{ - DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyErrArguments, PyResult, + DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyErrArguments, PyResult, ToPyErr, }; pub use crate::gil::GILPool; #[cfg(not(PyPy))] diff --git a/src/tests/common.rs b/src/tests/common.rs index 942ccd51c78..854d73e4d7b 100644 --- a/src/tests/common.rs +++ b/src/tests/common.rs @@ -74,9 +74,9 @@ mod inner { #[pymethods(crate = "pyo3")] impl UnraisableCapture { pub fn hook(&mut self, unraisable: Bound<'_, PyAny>) { - let err = unraisable.getattr("exc_value").unwrap(); + let err = PyErr::from_value_bound(unraisable.getattr("exc_value").unwrap()); let instance = unraisable.getattr("object").unwrap(); - self.capture = Some((err.into(), instance.into())); + self.capture = Some((err, instance.into())); } } diff --git a/src/types/traceback.rs b/src/types/traceback.rs index fc4e39e62af..b8782463367 100644 --- a/src/types/traceback.rs +++ b/src/types/traceback.rs @@ -147,7 +147,7 @@ except Exception as e: Some(&locals), ) .unwrap(); - let err: PyErr = locals.get_item("err").unwrap().unwrap().into(); + let err = PyErr::from_value_bound(locals.get_item("err").unwrap().unwrap()); let traceback = err.value_bound(py).getattr("__traceback__").unwrap(); assert!(err.traceback_bound(py).unwrap().is(&traceback)); })