From d4a5a46338cde97e86317c769a5916e0d26016b3 Mon Sep 17 00:00:00 2001 From: messense Date: Mon, 19 Jun 2017 13:30:15 +0800 Subject: [PATCH] Write Python Exception chapter for user guide --- guide/src/exception.md | 77 ++++++++++++++++++++++++++++++++++++++++-- guide/src/overview.md | 8 ----- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/guide/src/exception.md b/guide/src/exception.md index d6e653c4..07994175 100644 --- a/guide/src/exception.md +++ b/guide/src/exception.md @@ -34,8 +34,81 @@ let gil = Python::acquire_gil(); ## Raise an exception -TODO +To raise an exception, first you need to obtain an exception type and construct a new [`PyErr`](https://pyo3.github.io/PyO3/pyo3/struct.PyErr.html), then call [`PyErr::restore()`](https://pyo3.github.io/PyO3/pyo3/struct.PyErr.html#method.restore) method to write the exception back to the Python interpreter's global state. + +```rust +extern crate pyo3; + +use pyo3::{Python, PyErr, exc}; + +fn main() { + let gil = Python::acquire_gil(); + let py = gil.python(); + PyErr::new_lazy_init(py.get_type::(), None).restore(py); + assert!(PyErr::occurred(py)); + drop(PyErr::fetch(py)); +} +``` + +If you already have a Python exception instance, you can simply call [`PyErr::from_instance()`](https://pyo3.github.io/PyO3/pyo3/struct.PyErr.html#method.from_instance). + +```rust +PyErr::from_instance(py, err).restore(py); +``` ## Check exception type -TODO +Python has an [`isinstance`](https://docs.python.org/3/library/functions.html#isinstance) method to check object type, +in `PyO3` there is a [`Python::is_instance()`](https://pyo3.github.io/PyO3/pyo3/struct.Python.html#method.is_instance) method which does the same thing. + +```rust +extern crate pyo3; + +use pyo3::{Python, PyBool, PyList}; + +fn main() { + let gil = Python::acquire_gil(); + let py = gil.python(); + assert!(py.is_instance::(py.True().as_ref()).unwrap()); + let list = PyList::new(py, &[1, 2, 3, 4]); + assert!(!py.is_instance::(list.as_ref()).unwrap()); + assert!(py.is_instance::(list.as_ref()).unwrap()); +} +``` + +[`Python::is_instance()`](https://pyo3.github.io/PyO3/pyo3/struct.Python.html#method.is_instance) calls the underlaying [`PyType::is_instance`](https://pyo3.github.io/PyO3/pyo3/struct.PyType.html#method.is_instance) method to do the actual work. + +To check the type of an exception, you can simply do: + +```rust +let ret = py.is_instance::(&err.instance(py)).expect("Error calling is_instance"); +``` + +## Handle Rust Error + +The vast majority of operations in this library will return [`PyResult`](https://pyo3.github.io/PyO3/pyo3/type.PyResult.html). +This is an alias for the type `Result`. + +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. + +```rust +pub trait ToPyErr { + fn to_pyerr(&self, _: Python) -> PyErr; +} +``` + +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. + +```rust +use pyo3::{PyResult, ToPyErr}; + +fn parse_int(py: Python, s: String) -> PyResult { + Ok(s.parse::().map_err(|e| e.to_pyerr(py))?) +} +``` + +The code snippet above will raise `ValueError` in Python if `String::parse()` return an error. diff --git a/guide/src/overview.md b/guide/src/overview.md index 7196deea..95cc5f61 100644 --- a/guide/src/overview.md +++ b/guide/src/overview.md @@ -123,11 +123,3 @@ that a function can assume that the GIL is held. You obtain a [`Python`](https://pyo3.github.io/PyO3/pyo3/struct.Python.html) instance by acquiring the GIL, and have to pass it into all operations that call into the Python runtime. - -## Error Handling - -The vast majority of operations in this library will return [`PyResult`](https://pyo3.github.io/PyO3/pyo3/type.PyResult.html). -This is an alias for the type `Result`. - -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.