Implement `From<Bound<'py, T>>` for PyErr (#3881)
* Implement `From<Bound<'py, T>>` for PyErr * Replace PyErr::from_value_bound calls with .into * Fix From<MyError> expected error message * Add a trait bound to From<Bound<'py, T>> for PyErr
This commit is contained in:
parent
cd1c0dbf39
commit
5c41ea0ade
|
@ -982,6 +982,24 @@ impl PyErrArguments for PyDowncastErrorArguments {
|
|||
}
|
||||
}
|
||||
|
||||
/// Python exceptions that can be converted to [`PyErr`].
|
||||
///
|
||||
/// This is used to implement [`From<Bound<'_, T>> for PyErr`].
|
||||
///
|
||||
/// Users should not need to implement this trait directly. It is implemented automatically in the
|
||||
/// [`crate::import_exception!`] and [`crate::create_exception!`] macros.
|
||||
pub trait ToPyErr {}
|
||||
|
||||
impl<'py, T> std::convert::From<Bound<'py, T>> for PyErr
|
||||
where
|
||||
T: ToPyErr,
|
||||
{
|
||||
#[inline]
|
||||
fn from(err: Bound<'py, T>) -> PyErr {
|
||||
PyErr::from_value_bound(err.into_any())
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `PyDowncastError` to Python `TypeError`.
|
||||
impl<'a> std::convert::From<PyDowncastError<'a>> for PyErr {
|
||||
fn from(err: PyDowncastError<'_>) -> PyErr {
|
||||
|
|
|
@ -54,6 +54,8 @@ macro_rules! impl_exception_boilerplate {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::ToPyErr for $name {}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1076,7 @@ mod tests {
|
|||
);
|
||||
|
||||
// Restoring should preserve the same error
|
||||
let e = PyErr::from_value_bound(decode_err.into_any());
|
||||
let e: PyErr = decode_err.into();
|
||||
e.restore(py);
|
||||
|
||||
assert_eq!(
|
||||
|
|
|
@ -308,7 +308,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))]
|
||||
|
|
|
@ -73,9 +73,7 @@ impl<'a> PyStringData<'a> {
|
|||
match self {
|
||||
Self::Ucs1(data) => match str::from_utf8(data) {
|
||||
Ok(s) => Ok(Cow::Borrowed(s)),
|
||||
Err(e) => Err(crate::PyErr::from_value_bound(
|
||||
PyUnicodeDecodeError::new_utf8_bound(py, data, e)?.into_any(),
|
||||
)),
|
||||
Err(e) => Err(PyUnicodeDecodeError::new_utf8_bound(py, data, e)?.into()),
|
||||
},
|
||||
Self::Ucs2(data) => match String::from_utf16(data) {
|
||||
Ok(s) => Ok(Cow::Owned(s)),
|
||||
|
@ -83,30 +81,26 @@ impl<'a> PyStringData<'a> {
|
|||
let mut message = e.to_string().as_bytes().to_vec();
|
||||
message.push(0);
|
||||
|
||||
Err(crate::PyErr::from_value_bound(
|
||||
PyUnicodeDecodeError::new_bound(
|
||||
py,
|
||||
CStr::from_bytes_with_nul(b"utf-16\0").unwrap(),
|
||||
self.as_bytes(),
|
||||
0..self.as_bytes().len(),
|
||||
CStr::from_bytes_with_nul(&message).unwrap(),
|
||||
)?
|
||||
.into_any(),
|
||||
))
|
||||
Err(PyUnicodeDecodeError::new_bound(
|
||||
py,
|
||||
CStr::from_bytes_with_nul(b"utf-16\0").unwrap(),
|
||||
self.as_bytes(),
|
||||
0..self.as_bytes().len(),
|
||||
CStr::from_bytes_with_nul(&message).unwrap(),
|
||||
)?
|
||||
.into())
|
||||
}
|
||||
},
|
||||
Self::Ucs4(data) => match data.iter().map(|&c| std::char::from_u32(c)).collect() {
|
||||
Some(s) => Ok(Cow::Owned(s)),
|
||||
None => Err(crate::PyErr::from_value_bound(
|
||||
PyUnicodeDecodeError::new_bound(
|
||||
py,
|
||||
CStr::from_bytes_with_nul(b"utf-32\0").unwrap(),
|
||||
self.as_bytes(),
|
||||
0..self.as_bytes().len(),
|
||||
CStr::from_bytes_with_nul(b"error converting utf-32\0").unwrap(),
|
||||
)?
|
||||
.into_any(),
|
||||
)),
|
||||
None => Err(PyUnicodeDecodeError::new_bound(
|
||||
py,
|
||||
CStr::from_bytes_with_nul(b"utf-32\0").unwrap(),
|
||||
self.as_bytes(),
|
||||
0..self.as_bytes().len(),
|
||||
CStr::from_bytes_with_nul(b"error converting utf-32\0").unwrap(),
|
||||
)?
|
||||
.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ error[E0277]: the trait bound `PyErr: From<MyError>` is not satisfied
|
|||
| ^^^^^^^^^^^^^ the trait `From<MyError>` is not implemented for `PyErr`
|
||||
|
|
||||
= help: the following other types implement trait `From<T>`:
|
||||
<PyErr as From<pyo3::Bound<'py, T>>>
|
||||
<PyErr as From<std::io::Error>>
|
||||
<PyErr as From<PyBorrowError>>
|
||||
<PyErr as From<PyBorrowMutError>>
|
||||
|
@ -12,7 +13,6 @@ error[E0277]: the trait bound `PyErr: From<MyError>` is not satisfied
|
|||
<PyErr as From<DowncastError<'_, '_>>>
|
||||
<PyErr as From<DowncastIntoError<'_>>>
|
||||
<PyErr as From<NulError>>
|
||||
<PyErr as From<IntoStringError>>
|
||||
and $N others
|
||||
= note: required for `MyError` to implement `Into<PyErr>`
|
||||
= note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
Loading…
Reference in New Issue