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`.
|
/// Convert `PyDowncastError` to Python `TypeError`.
|
||||||
impl<'a> std::convert::From<PyDowncastError<'a>> for PyErr {
|
impl<'a> std::convert::From<PyDowncastError<'a>> for PyErr {
|
||||||
fn from(err: PyDowncastError<'_>) -> 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
|
// 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);
|
e.restore(py);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -308,7 +308,7 @@ pub use crate::conversion::{AsPyPointer, FromPyObject, FromPyPointer, IntoPy, To
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub use crate::conversion::{PyTryFrom, PyTryInto};
|
pub use crate::conversion::{PyTryFrom, PyTryInto};
|
||||||
pub use crate::err::{
|
pub use crate::err::{
|
||||||
DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyErrArguments, PyResult,
|
DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyErrArguments, PyResult, ToPyErr,
|
||||||
};
|
};
|
||||||
pub use crate::gil::GILPool;
|
pub use crate::gil::GILPool;
|
||||||
#[cfg(not(PyPy))]
|
#[cfg(not(PyPy))]
|
||||||
|
|
|
@ -73,9 +73,7 @@ impl<'a> PyStringData<'a> {
|
||||||
match self {
|
match self {
|
||||||
Self::Ucs1(data) => match str::from_utf8(data) {
|
Self::Ucs1(data) => match str::from_utf8(data) {
|
||||||
Ok(s) => Ok(Cow::Borrowed(s)),
|
Ok(s) => Ok(Cow::Borrowed(s)),
|
||||||
Err(e) => Err(crate::PyErr::from_value_bound(
|
Err(e) => Err(PyUnicodeDecodeError::new_utf8_bound(py, data, e)?.into()),
|
||||||
PyUnicodeDecodeError::new_utf8_bound(py, data, e)?.into_any(),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Self::Ucs2(data) => match String::from_utf16(data) {
|
Self::Ucs2(data) => match String::from_utf16(data) {
|
||||||
Ok(s) => Ok(Cow::Owned(s)),
|
Ok(s) => Ok(Cow::Owned(s)),
|
||||||
|
@ -83,30 +81,26 @@ impl<'a> PyStringData<'a> {
|
||||||
let mut message = e.to_string().as_bytes().to_vec();
|
let mut message = e.to_string().as_bytes().to_vec();
|
||||||
message.push(0);
|
message.push(0);
|
||||||
|
|
||||||
Err(crate::PyErr::from_value_bound(
|
Err(PyUnicodeDecodeError::new_bound(
|
||||||
PyUnicodeDecodeError::new_bound(
|
|
||||||
py,
|
py,
|
||||||
CStr::from_bytes_with_nul(b"utf-16\0").unwrap(),
|
CStr::from_bytes_with_nul(b"utf-16\0").unwrap(),
|
||||||
self.as_bytes(),
|
self.as_bytes(),
|
||||||
0..self.as_bytes().len(),
|
0..self.as_bytes().len(),
|
||||||
CStr::from_bytes_with_nul(&message).unwrap(),
|
CStr::from_bytes_with_nul(&message).unwrap(),
|
||||||
)?
|
)?
|
||||||
.into_any(),
|
.into())
|
||||||
))
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Self::Ucs4(data) => match data.iter().map(|&c| std::char::from_u32(c)).collect() {
|
Self::Ucs4(data) => match data.iter().map(|&c| std::char::from_u32(c)).collect() {
|
||||||
Some(s) => Ok(Cow::Owned(s)),
|
Some(s) => Ok(Cow::Owned(s)),
|
||||||
None => Err(crate::PyErr::from_value_bound(
|
None => Err(PyUnicodeDecodeError::new_bound(
|
||||||
PyUnicodeDecodeError::new_bound(
|
|
||||||
py,
|
py,
|
||||||
CStr::from_bytes_with_nul(b"utf-32\0").unwrap(),
|
CStr::from_bytes_with_nul(b"utf-32\0").unwrap(),
|
||||||
self.as_bytes(),
|
self.as_bytes(),
|
||||||
0..self.as_bytes().len(),
|
0..self.as_bytes().len(),
|
||||||
CStr::from_bytes_with_nul(b"error converting utf-32\0").unwrap(),
|
CStr::from_bytes_with_nul(b"error converting utf-32\0").unwrap(),
|
||||||
)?
|
)?
|
||||||
.into_any(),
|
.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`
|
| ^^^^^^^^^^^^^ the trait `From<MyError>` is not implemented for `PyErr`
|
||||||
|
|
|
|
||||||
= help: the following other types implement trait `From<T>`:
|
= 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<std::io::Error>>
|
||||||
<PyErr as From<PyBorrowError>>
|
<PyErr as From<PyBorrowError>>
|
||||||
<PyErr as From<PyBorrowMutError>>
|
<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<DowncastError<'_, '_>>>
|
||||||
<PyErr as From<DowncastIntoError<'_>>>
|
<PyErr as From<DowncastIntoError<'_>>>
|
||||||
<PyErr as From<NulError>>
|
<PyErr as From<NulError>>
|
||||||
<PyErr as From<IntoStringError>>
|
|
||||||
and $N others
|
and $N others
|
||||||
= note: required for `MyError` to implement `Into<PyErr>`
|
= 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)
|
= 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