update guide related to exception
This commit is contained in:
parent
c9572d6e1d
commit
b250ad22ca
|
@ -44,7 +44,7 @@ use pyo3::{Python, PyErr, exc};
|
|||
fn main() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), None).restore(py);
|
||||
PyErr::new::<exc::TypeError, _>("Error").restore(py);
|
||||
assert!(PyErr::occurred(py));
|
||||
drop(PyErr::fetch(py));
|
||||
}
|
||||
|
@ -92,11 +92,13 @@ 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.
|
||||
|
||||
The [`ToPyErr`](https://pyo3.github.io/PyO3/pyo3/trait.ToPyErr.html) trait provides a way to convert Rust errors to 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.
|
||||
|
||||
```rust
|
||||
pub trait ToPyErr {
|
||||
fn to_pyerr(&self, _: Python) -> PyErr;
|
||||
fn arguments(&self, _: Python) -> PyObject;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -104,11 +106,27 @@ It's implemented for most of the standard library's error types so that you use
|
|||
transform errors to Python exceptions as well as taking advantage of `try!` macro or `?` operator.
|
||||
|
||||
```rust
|
||||
use pyo3::{PyResult, ToPyErr};
|
||||
use std;
|
||||
use std::net::TcpListener;
|
||||
use pyo3::{PyErr, PyResult, ToPyErr, exc};
|
||||
|
||||
fn parse_int(py: Python, s: String) -> PyResult<usize> {
|
||||
Ok(s.parse::<usize>().map_err(|e| e.to_pyerr(py))?)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
fn connect(py: Python, s: String) -> PyResult<bool> {
|
||||
TcpListener::bind("127.0.0.1:80")?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
```
|
||||
|
||||
The code snippet above will raise `ValueError` in Python if `String::parse()` return an error.
|
||||
The code snippet above will raise `OSError` in Python if `TcpListener::bind()` return an error.
|
||||
|
|
32
src/err.rs
32
src/err.rs
|
@ -8,7 +8,7 @@ use libc;
|
|||
|
||||
use ffi;
|
||||
use python::{ToPyPointer, IntoPyPointer, Python};
|
||||
use PyObject;
|
||||
use object::PyObject;
|
||||
use objects::{PyObjectRef, PyType, exc};
|
||||
use instance::Py;
|
||||
use typeob::PyTypeObject;
|
||||
|
@ -132,6 +132,13 @@ pub type PyResult<T> = Result<T, PyErr>;
|
|||
pub struct PyDowncastError;
|
||||
|
||||
|
||||
/// Conversion trait that allows various errors to be converted into `PyErr`
|
||||
pub trait ToPyErr {
|
||||
/// Arguments for exception
|
||||
fn arguments(&self, Python) -> PyObject;
|
||||
}
|
||||
|
||||
|
||||
impl PyErr {
|
||||
/// Creates a new PyErr of type `T`.
|
||||
///
|
||||
|
@ -161,6 +168,8 @@ impl PyErr {
|
|||
/// `exc` is the exception type; usually one of the standard exceptions
|
||||
/// like `exc::RuntimeError::type_info()`.
|
||||
/// `args` is the a tuple of arguments to pass to the exception constructor.
|
||||
///
|
||||
/// Panics if `T` is not a python class derived from `BaseException`.
|
||||
pub fn from_type<A>(exc: Py<PyType>, args: A) -> PyErr
|
||||
where A: IntoPyTuple + 'static
|
||||
{
|
||||
|
@ -327,7 +336,7 @@ impl PyErr {
|
|||
let mut pvalue = match pvalue {
|
||||
PyErrValue::None => std::ptr::null_mut(),
|
||||
PyErrValue::Value(ob) => ob.into_ptr(),
|
||||
PyErrValue::ToErr(ob) => ob.exc_arguments(py).into_ptr(),
|
||||
PyErrValue::ToErr(ob) => ob.arguments(py).into_ptr(),
|
||||
PyErrValue::ToObject(ob) => ob.to_object(py).into_ptr(),
|
||||
PyErrValue::ToTuple(ob) => ob.to_tuple(py).into_ptr(),
|
||||
};
|
||||
|
@ -365,7 +374,7 @@ impl PyErr {
|
|||
let pvalue = match pvalue {
|
||||
PyErrValue::None => std::ptr::null_mut(),
|
||||
PyErrValue::Value(ob) => ob.into_ptr(),
|
||||
PyErrValue::ToErr(ob) => ob.exc_arguments(py).into_ptr(),
|
||||
PyErrValue::ToErr(ob) => ob.arguments(py).into_ptr(),
|
||||
PyErrValue::ToObject(ob) => ob.to_object(py).into_ptr(),
|
||||
PyErrValue::ToTuple(ob) => ob.to_tuple(py).into_ptr(),
|
||||
};
|
||||
|
@ -434,22 +443,17 @@ impl std::convert::From<PyErr> for std::io::Error {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts into `PyErr`
|
||||
pub trait ToPyErr {
|
||||
fn exc_arguments(&self, Python) -> PyObject;
|
||||
}
|
||||
|
||||
macro_rules! impl_to_pyerr {
|
||||
($err: ty, $pyexc: ty) => {
|
||||
impl $crate::ToPyErr for $err {
|
||||
fn exc_arguments(&self, py: $crate::Python) -> PyObject {
|
||||
fn arguments(&self, py: $crate::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::<exc::ValueError>(
|
||||
$crate::PyErr::from_value::<$pyexc>(
|
||||
$crate::err::PyErrValue::ToErr(Box::new(err))
|
||||
)
|
||||
}
|
||||
|
@ -495,10 +499,8 @@ impl std::convert::From<io::Error> for PyErr {
|
|||
|
||||
/// Extract `errno` and `errdesc` from from `io::Error`
|
||||
impl ToPyErr for io::Error {
|
||||
fn exc_arguments(&self, py: Python) -> PyObject {
|
||||
let errno = self.raw_os_error().unwrap_or(0);
|
||||
let errdesc = self.description().to_owned();
|
||||
(errno, errdesc).to_object(py)
|
||||
fn arguments(&self, py: Python) -> PyObject {
|
||||
(self.raw_os_error().unwrap_or(0), self.description()).to_object(py)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,7 +512,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> {
|
||||
fn exc_arguments(&self, py: Python) -> PyObject {
|
||||
fn arguments(&self, py: Python) -> PyObject {
|
||||
self.description().to_object(py)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,33 +9,35 @@ use std::{self, mem, ops};
|
|||
use std::ffi::CStr;
|
||||
|
||||
use ffi;
|
||||
use objects::PyObjectRef;
|
||||
use instance::Py;
|
||||
use err::{PyErr, PyResult};
|
||||
use python::{Python, ToPyPointer};
|
||||
use err::PyResult;
|
||||
use super::PyTuple;
|
||||
use objects::{PyTuple, PyType, PyObjectRef};
|
||||
use typeob::PyTypeObject;
|
||||
use conversion::ToPyObject;
|
||||
|
||||
macro_rules! exc_type(
|
||||
($name:ident, $exc_name:ident) => (
|
||||
pub struct $name;
|
||||
|
||||
impl std::convert::From<$name> for $crate::PyErr {
|
||||
fn from(_err: $name) -> $crate::PyErr {
|
||||
$crate::PyErr::new::<$name, _>(())
|
||||
impl std::convert::From<$name> for PyErr {
|
||||
fn from(_err: $name) -> PyErr {
|
||||
PyErr::new::<$name, _>(())
|
||||
}
|
||||
}
|
||||
impl $name {
|
||||
pub fn new<V: $crate::ToPyObject + 'static>(value: V) -> $crate::PyErr {
|
||||
$crate::PyErr::new::<$name, V>(value)
|
||||
pub fn new<V: ToPyObject + 'static>(args: V) -> PyErr {
|
||||
PyErr::new::<$name, V>(args)
|
||||
}
|
||||
}
|
||||
impl $crate::typeob::PyTypeObject for $name {
|
||||
impl PyTypeObject for $name {
|
||||
#[inline(always)]
|
||||
fn init_type() {}
|
||||
|
||||
#[inline]
|
||||
fn type_object() -> $crate::Py<$crate::PyType> {
|
||||
fn type_object() -> Py<PyType> {
|
||||
unsafe {
|
||||
$crate::Py::from_borrowed_ptr(ffi::$exc_name)
|
||||
Py::from_borrowed_ptr(ffi::$exc_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue