rename ToPyErr to PyErrArguments
This commit is contained in:
parent
3b6d784bfb
commit
e45eb6e878
|
@ -92,18 +92,16 @@ This is an alias for the type `Result<T, PyErr>`.
|
|||
A [`PyErr`](https://pyo3.github.io/PyO3/pyo3/struct.PyErr.html) represents a Python exception.
|
||||
Errors within the `PyO3` library are also exposed as Python exceptions.
|
||||
|
||||
To handle rust errors, `std::convert::From<T>` and [`ToPyErr`](https://pyo3.github.io/PyO3/pyo3/trait.ToPyErr.html)
|
||||
traits need to be implemented for `PyErr`. The [`ToPyErr`](https://pyo3.github.io/PyO3/pyo3/trait.ToPyErr.html) trait provides
|
||||
a way to convert Rust errors arguments to Python exception arguments.
|
||||
PyO3 library handles python exception in two stages. During first stage `PyErr` instance get
|
||||
created. At this stage python gil is not required. During second stage, actual python
|
||||
exception instance get crated and set to python interpreter.
|
||||
|
||||
```rust
|
||||
pub trait ToPyErr {
|
||||
fn arguments(&self, _: Python) -> PyObject;
|
||||
}
|
||||
```
|
||||
|
||||
It's implemented for most of the standard library's error types so that you use [`Result::map_err()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err) to
|
||||
transform errors to Python exceptions as well as taking advantage of `try!` macro or `?` operator.
|
||||
In simple case, for custom errors support implementation of `std::convert::From<T>` trait
|
||||
for this custom error is enough. `PyErr::new` accepts arguments in form
|
||||
of `ToPyObject + 'static`. In case if `'static` constraint can not be satisfied or
|
||||
more complex arguments are required [`PyErrArgument`](https://pyo3.github.io/PyO3/pyo3/trait.PyErrArguments.html)
|
||||
trait can be implemented. In that case actual exception arguments creation get delayed
|
||||
until `Python` object is available.
|
||||
|
||||
```rust
|
||||
use std;
|
||||
|
@ -112,13 +110,7 @@ use pyo3::{PyErr, PyResult, ToPyErr, exc};
|
|||
|
||||
impl std::convert::From<std::io::Error> for PyErr {
|
||||
fn from(err: std::io::Error) -> PyErr {
|
||||
PyErr::from_value::<exc::OSError>(PyErrValue::ToErr(Box::new(err)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPyErr for std::io::Error {
|
||||
fn arguments(&self, py: Python) -> PyObject {
|
||||
(self.raw_os_error().unwrap_or(0), self.description()).to_object(py)
|
||||
exc::OSError.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,3 +122,16 @@ fn connect(py: Python, s: String) -> PyResult<bool> {
|
|||
```
|
||||
|
||||
The code snippet above will raise `OSError` in Python if `TcpListener::bind()` return an error.
|
||||
|
||||
`std::convert::From<T>` trait is implemented for most of the standard library's error
|
||||
types so `try!` macro or `?` operator can be used.
|
||||
|
||||
```rust
|
||||
use pyo3::{PyResult, ToPyErr};
|
||||
|
||||
fn parse_int(py: Python, s: String) -> PyResult<usize> {
|
||||
Ok(s.parse::<usize>()?)
|
||||
}
|
||||
```
|
||||
|
||||
The code snippet above will raise `ValueError` in Python if `String::parse()` return an error.
|
||||
|
|
32
src/err.rs
32
src/err.rs
|
@ -103,7 +103,7 @@ macro_rules! py_exception {
|
|||
pub enum PyErrValue {
|
||||
None,
|
||||
Value(PyObject),
|
||||
ToErr(Box<ToPyErr>),
|
||||
ToErr(Box<PyErrArguments>),
|
||||
ToObject(Box<ToPyObject>),
|
||||
ToTuple(Box<IntoPyTuple>),
|
||||
}
|
||||
|
@ -112,33 +112,31 @@ pub enum PyErrValue {
|
|||
pub struct PyErr {
|
||||
/// The type of the exception. This should be either a `PyClass` or a `PyType`.
|
||||
pub ptype: Py<PyType>,
|
||||
|
||||
/// The value of the exception.
|
||||
///
|
||||
/// This can be either an instance of `ptype`,
|
||||
/// This can be either an instance of `PyObject`,
|
||||
/// a tuple of arguments to be passed to `ptype`'s constructor,
|
||||
/// or a single argument to be passed to `ptype`'s constructor.
|
||||
/// Call `PyErr::instance()` to get the exception instance in all cases.
|
||||
pub pvalue: PyErrValue,
|
||||
|
||||
/// The `PyTraceBack` object associated with the error.
|
||||
pub ptraceback: Option<PyObject>,
|
||||
}
|
||||
|
||||
|
||||
/// Represents the result of a Python call.
|
||||
pub type PyResult<T> = Result<T, PyErr>;
|
||||
|
||||
|
||||
/// Marker type that indicates an error while downcasting
|
||||
pub struct PyDowncastError;
|
||||
|
||||
|
||||
/// Conversion trait that allows various errors to be converted into `PyErr`
|
||||
pub trait ToPyErr {
|
||||
/// Helper conversion trait that allows to use custom arguments for exception constructor.
|
||||
pub trait PyErrArguments {
|
||||
/// Arguments for exception
|
||||
fn arguments(&self, Python) -> PyObject;
|
||||
}
|
||||
|
||||
|
||||
impl PyErr {
|
||||
/// Creates a new PyErr of type `T`.
|
||||
///
|
||||
|
@ -425,7 +423,7 @@ impl std::fmt::Debug for PyErr {
|
|||
/// Converts `PyDowncastError` to Python `TypeError`.
|
||||
impl std::convert::From<PyDowncastError> for PyErr {
|
||||
fn from(_err: PyDowncastError) -> PyErr {
|
||||
PyErr::new::<exc::TypeError, _>(())
|
||||
exc::TypeError.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,17 +443,15 @@ impl std::convert::From<PyErr> for std::io::Error {
|
|||
|
||||
macro_rules! impl_to_pyerr {
|
||||
($err: ty, $pyexc: ty) => {
|
||||
impl $crate::ToPyErr for $err {
|
||||
fn arguments(&self, py: $crate::Python) -> PyObject {
|
||||
impl PyErrArguments for $err {
|
||||
fn arguments(&self, py: Python) -> PyObject {
|
||||
self.description().to_object(py)
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::std::convert::From<$err> for $crate::PyErr {
|
||||
fn from(err: $err) -> $crate::PyErr {
|
||||
$crate::PyErr::from_value::<$pyexc>(
|
||||
$crate::err::PyErrValue::ToErr(Box::new(err))
|
||||
)
|
||||
impl std::convert::From<$err> for PyErr {
|
||||
fn from(err: $err) -> PyErr {
|
||||
PyErr::from_value::<$pyexc>(PyErrValue::ToErr(Box::new(err)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -498,7 +494,7 @@ impl std::convert::From<io::Error> for PyErr {
|
|||
|
||||
|
||||
/// Extract `errno` and `errdesc` from from `io::Error`
|
||||
impl ToPyErr for io::Error {
|
||||
impl PyErrArguments for io::Error {
|
||||
fn arguments(&self, py: Python) -> PyObject {
|
||||
(self.raw_os_error().unwrap_or(0), self.description()).to_object(py)
|
||||
}
|
||||
|
@ -511,7 +507,7 @@ impl<W: 'static + Send + std::fmt::Debug> std::convert::From<std::io::IntoInnerE
|
|||
}
|
||||
}
|
||||
|
||||
impl<W: Send + std::fmt::Debug> ToPyErr for std::io::IntoInnerError<W> {
|
||||
impl<W: Send + std::fmt::Debug> PyErrArguments for std::io::IntoInnerError<W> {
|
||||
fn arguments(&self, py: Python) -> PyObject {
|
||||
self.description().to_object(py)
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ pub mod ffi {
|
|||
pub use ffi3::*;
|
||||
}
|
||||
|
||||
pub use err::{PyErr, PyErrValue, PyResult, PyDowncastError, ToPyErr};
|
||||
pub use err::{PyErr, PyErrValue, PyResult, PyDowncastError, PyErrArguments};
|
||||
pub use objects::*;
|
||||
pub use objectprotocol::ObjectProtocol;
|
||||
pub use object::PyObject;
|
||||
|
|
Loading…
Reference in New Issue