As described in the function error handling chapter, to raise an exception from a #[pyfunction] or #[pymethods], return an Err(PyErr). PyO3 will automatically raise this exception for you when returning the result to Python.
You can also manually write and fetch errors in the Python interpreter's global state:
#![allow(unused)]fnmain() {
use pyo3::{Python, PyErr};
use pyo3::exceptions::PyTypeError;
Python::with_gil(|py| {
PyTypeError::new_err("Error").restore(py);
assert!(PyErr::occurred(py));
drop(PyErr::fetch(py));
});
}
#![allow(unused)]fnmain() {
use pyo3::Python;
use pyo3::types::{PyBool, PyList};
Python::with_gil(|py| {
assert!(PyBool::new(py, true).is_instance_of::<PyBool>().unwrap());
let list = PyList::new(py, &[1, 2, 3, 4]);
assert!(!list.is_instance_of::<PyBool>().unwrap());
assert!(list.is_instance_of::<PyList>().unwrap());
});
}
To check the type of an exception, you can similarly do:
#![allow(unused)]fnmain() {
use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
Python::with_gil(|py| {
let err = PyTypeError::new_err(());
err.is_instance_of::<PyTypeError>(py);
});
}
It is possible to use an exception defined in Python code as a native Rust type.
The import_exception! macro allows importing a specific exception class and defines a Rust type
for that exception.
#![allow(unused)]#![allow(dead_code)]fnmain() {
use pyo3::prelude::*;
mod io {
pyo3::import_exception!(io, UnsupportedOperation);
}
fntell(file: &PyAny) -> PyResult<u64> {
match file.call_method0("tell") {
Err(_) => Err(io::UnsupportedOperation::new_err("not supported: tell")),
Ok(x) => x.extract::<u64>(),
}
}
}
pyo3::exceptions
defines exceptions for several standard library modules.