2017-06-24 08:36:51 +00:00
|
|
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
2015-01-05 16:05:53 +00:00
|
|
|
use std;
|
2017-06-08 01:40:30 +00:00
|
|
|
use std::io;
|
2017-05-25 03:31:51 +00:00
|
|
|
use std::ffi::CString;
|
2017-05-29 22:08:19 +00:00
|
|
|
use std::os::raw::c_char;
|
2017-06-08 01:40:30 +00:00
|
|
|
use std::error::Error;
|
2015-01-05 16:05:53 +00:00
|
|
|
use libc;
|
2017-05-25 03:31:51 +00:00
|
|
|
|
|
|
|
use ffi;
|
2017-07-18 17:13:50 +00:00
|
|
|
use python::{ToPyPointer, IntoPyPointer, Python};
|
2017-06-23 03:56:09 +00:00
|
|
|
use PyObject;
|
2017-06-24 15:28:31 +00:00
|
|
|
use objects::{PyObjectRef, PyType, exc};
|
2017-06-22 08:16:22 +00:00
|
|
|
use instance::Py;
|
2017-06-21 22:11:32 +00:00
|
|
|
use typeob::PyTypeObject;
|
2017-06-06 03:25:00 +00:00
|
|
|
use conversion::{ToPyObject, IntoPyTuple, IntoPyObject};
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2016-06-02 08:02:43 +00:00
|
|
|
/**
|
|
|
|
Defines a new exception type.
|
|
|
|
|
|
|
|
# Syntax
|
|
|
|
`py_exception!(module, MyError)`
|
|
|
|
|
|
|
|
* `module` is the name of the containing module.
|
|
|
|
* `MyError` is the name of the new exception type.
|
|
|
|
|
|
|
|
# Example
|
|
|
|
```
|
|
|
|
#[macro_use]
|
2017-05-13 05:43:17 +00:00
|
|
|
extern crate pyo3;
|
2016-06-02 08:02:43 +00:00
|
|
|
|
2017-05-13 05:43:17 +00:00
|
|
|
use pyo3::{Python, PyDict};
|
2016-06-02 08:02:43 +00:00
|
|
|
|
|
|
|
py_exception!(mymodule, CustomError);
|
|
|
|
|
|
|
|
fn main() {
|
2017-05-19 04:35:08 +00:00
|
|
|
let gil = Python::acquire_gil();
|
2016-06-02 08:02:43 +00:00
|
|
|
let py = gil.python();
|
|
|
|
let ctx = PyDict::new(py);
|
|
|
|
|
2017-06-21 21:08:16 +00:00
|
|
|
ctx.set_item("CustomError", py.get_type::<CustomError>()).unwrap();
|
2016-06-02 08:02:43 +00:00
|
|
|
|
|
|
|
py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"", None, Some(&ctx)).unwrap();
|
2017-06-21 21:08:16 +00:00
|
|
|
py.run("assert CustomError('oops').args == ('oops',)", None, Some(ctx)).unwrap();
|
2016-06-02 08:02:43 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
*/
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! py_exception {
|
|
|
|
($module: ident, $name: ident, $base: ty) => {
|
2017-05-25 03:31:51 +00:00
|
|
|
pub struct $name;
|
2016-06-02 08:02:43 +00:00
|
|
|
|
2017-05-30 01:36:44 +00:00
|
|
|
// pyobject_nativetype!($name);
|
2016-06-02 08:02:43 +00:00
|
|
|
|
|
|
|
impl $name {
|
2017-06-04 00:27:26 +00:00
|
|
|
pub fn new<T: $crate::IntoPyObject>(py: $crate::Python, args: T) -> $crate::PyErr {
|
2016-06-02 08:02:43 +00:00
|
|
|
$crate::PyErr::new::<$name, T>(py, args)
|
|
|
|
}
|
2017-06-08 21:21:48 +00:00
|
|
|
#[inline(always)]
|
2017-07-26 01:11:45 +00:00
|
|
|
fn type_object() -> *mut $crate::ffi::PyTypeObject {
|
2017-06-08 21:21:48 +00:00
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
static mut type_object: *mut $crate::ffi::PyTypeObject =
|
|
|
|
0 as *mut $crate::ffi::PyTypeObject;
|
2016-06-02 08:02:43 +00:00
|
|
|
|
|
|
|
unsafe {
|
|
|
|
if type_object.is_null() {
|
2017-07-26 01:11:45 +00:00
|
|
|
let gil = $crate::Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
|
2016-06-02 08:02:43 +00:00
|
|
|
type_object = $crate::PyErr::new_type(
|
2017-06-08 21:21:48 +00:00
|
|
|
py, concat!(stringify!($module), ".", stringify!($name)),
|
2017-07-26 01:11:45 +00:00
|
|
|
Some(py.get_type::<$base>()), None);
|
2016-06-02 08:02:43 +00:00
|
|
|
}
|
2017-06-08 21:21:48 +00:00
|
|
|
type_object
|
2016-06-02 08:02:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-08 21:21:48 +00:00
|
|
|
|
2017-06-15 18:13:58 +00:00
|
|
|
impl $crate::typeob::PyTypeObject for $name {
|
2017-06-08 21:21:48 +00:00
|
|
|
#[inline(always)]
|
2017-07-26 01:11:45 +00:00
|
|
|
fn init_type() {
|
|
|
|
let _ = $name::type_object();
|
2017-06-08 21:21:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2017-07-26 01:11:45 +00:00
|
|
|
fn type_object() -> $crate::Py<$crate::PyType> {
|
2017-07-26 01:39:11 +00:00
|
|
|
unsafe {
|
|
|
|
$crate::Py::from_borrowed_ptr(
|
|
|
|
$name::type_object() as *const _ as *mut $crate::ffi::PyObject)
|
|
|
|
}
|
2017-06-08 21:21:48 +00:00
|
|
|
}
|
|
|
|
}
|
2016-06-02 08:02:43 +00:00
|
|
|
};
|
|
|
|
($module: ident, $name: ident) => {
|
|
|
|
py_exception!($module, $name, $crate::exc::Exception);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Represents a Python exception that was raised.
|
2015-10-25 16:55:29 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PyErr {
|
2015-04-18 22:39:04 +00:00
|
|
|
/// The type of the exception. This should be either a `PyClass` or a `PyType`.
|
2017-06-21 22:11:32 +00:00
|
|
|
pub ptype: Py<PyType>,
|
2015-04-18 22:39:04 +00:00
|
|
|
/// The value of the exception.
|
2016-06-02 08:02:43 +00:00
|
|
|
///
|
2015-04-18 22:39:04 +00:00
|
|
|
/// This can be either an instance of `ptype`,
|
|
|
|
/// 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.
|
2017-06-23 03:56:09 +00:00
|
|
|
pub pvalue: Option<PyObject>,
|
2015-04-18 22:39:04 +00:00
|
|
|
/// The `PyTraceBack` object associated with the error.
|
2017-06-23 03:56:09 +00:00
|
|
|
pub ptraceback: Option<PyObject>,
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Represents the result of a Python call.
|
2015-10-25 16:55:29 +00:00
|
|
|
pub type PyResult<T> = Result<T, PyErr>;
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
|
2017-06-20 06:57:34 +00:00
|
|
|
/// Marker type that indicates an error while downcasting
|
2017-05-28 15:57:34 +00:00
|
|
|
pub struct PyDowncastError<'p>(pub Python<'p>, pub Option<&'p str>);
|
2017-05-25 03:31:51 +00:00
|
|
|
|
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
impl PyErr {
|
2017-01-27 20:51:56 +00:00
|
|
|
/// Creates a new PyErr of type `T`.
|
|
|
|
///
|
|
|
|
/// `value` can be:
|
|
|
|
/// * `NoArgs`: the exception instance will be created using python `T()`
|
|
|
|
/// * a tuple: the exception instance will be created using python `T(*tuple)`
|
|
|
|
/// * any other value: the exception instance will be created using python `T(value)`
|
|
|
|
///
|
|
|
|
/// Panics if `T` is not a python class derived from `BaseException`.
|
|
|
|
///
|
|
|
|
/// Example:
|
|
|
|
/// `return Err(PyErr::new::<exc::TypeError, _>(py, "Error message"));`
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn new<T, V>(py: Python, value: V) -> PyErr
|
2017-05-31 00:23:23 +00:00
|
|
|
where T: PyTypeObject, V: IntoPyObject
|
2017-01-27 20:51:56 +00:00
|
|
|
{
|
2017-06-03 01:58:16 +00:00
|
|
|
PyErr::new_helper(py, py.get_type::<T>(), value.into_object(py))
|
2017-01-27 20:51:56 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Gets whether an error is present in the Python interpreter's global state.
|
2015-01-05 15:34:12 +00:00
|
|
|
#[inline]
|
2017-07-26 01:39:11 +00:00
|
|
|
pub fn occurred(_: Python) -> bool {
|
2015-01-05 16:05:53 +00:00
|
|
|
unsafe { !ffi::PyErr_Occurred().is_null() }
|
|
|
|
}
|
|
|
|
|
2016-06-02 08:02:43 +00:00
|
|
|
/// Creates a new exception type with the given name, which must be of the form
|
|
|
|
/// `<module>.<ExceptionName>`, as required by `PyErr_NewException`.
|
|
|
|
///
|
|
|
|
/// `base` can be an existing exception type to subclass, or a tuple of classes
|
|
|
|
/// `dict` specifies an optional dictionary of class variables and methods
|
2017-07-26 01:39:11 +00:00
|
|
|
pub fn new_type<'p>(_: Python<'p>, name: &str, base: Option<&PyType>, dict: Option<PyObject>)
|
2017-07-26 01:11:45 +00:00
|
|
|
-> *mut ffi::PyTypeObject
|
2017-06-03 01:58:16 +00:00
|
|
|
{
|
2016-06-02 08:02:43 +00:00
|
|
|
let base: *mut ffi::PyObject = match base {
|
2017-05-29 22:08:19 +00:00
|
|
|
None => std::ptr::null_mut(),
|
2017-06-22 08:04:37 +00:00
|
|
|
Some(obj) => obj.as_ptr()
|
2016-06-02 08:02:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let dict: *mut ffi::PyObject = match dict {
|
2017-05-29 22:08:19 +00:00
|
|
|
None => std::ptr::null_mut(),
|
2017-06-22 08:04:37 +00:00
|
|
|
Some(obj) => obj.as_ptr(),
|
2016-06-02 08:02:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
unsafe {
|
2017-07-26 01:39:11 +00:00
|
|
|
let null_terminated_name = CString::new(name)
|
|
|
|
.expect("Failed to initialize nul terminated exception name");
|
|
|
|
ffi::PyErr_NewException(
|
|
|
|
null_terminated_name.as_ptr() as *mut c_char, base, dict) as *mut ffi::PyTypeObject
|
2016-06-02 08:02:43 +00:00
|
|
|
}
|
2017-05-29 22:08:19 +00:00
|
|
|
}
|
2016-06-02 08:02:43 +00:00
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Retrieves the current error from the Python interpreter's global state.
|
|
|
|
/// The error is cleared from the Python interpreter.
|
2015-04-18 22:39:04 +00:00
|
|
|
/// If no error is set, returns a `SystemError`.
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn fetch(py: Python) -> PyErr {
|
2015-01-05 16:05:53 +00:00
|
|
|
unsafe {
|
2017-05-29 09:47:27 +00:00
|
|
|
let mut ptype : *mut ffi::PyObject = std::ptr::null_mut();
|
|
|
|
let mut pvalue : *mut ffi::PyObject = std::ptr::null_mut();
|
|
|
|
let mut ptraceback : *mut ffi::PyObject = std::ptr::null_mut();
|
2015-01-05 16:05:53 +00:00
|
|
|
ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback);
|
2015-01-05 15:34:12 +00:00
|
|
|
PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-28 15:57:34 +00:00
|
|
|
unsafe fn new_from_ffi_tuple(py: Python,
|
2017-05-25 03:31:51 +00:00
|
|
|
ptype: *mut ffi::PyObject,
|
|
|
|
pvalue: *mut ffi::PyObject,
|
|
|
|
ptraceback: *mut ffi::PyObject) -> PyErr {
|
2015-01-05 15:34:12 +00:00
|
|
|
// Note: must not panic to ensure all owned pointers get acquired correctly,
|
|
|
|
// and because we mustn't panic in normalize().
|
|
|
|
PyErr {
|
|
|
|
ptype: if ptype.is_null() {
|
2017-06-21 22:11:32 +00:00
|
|
|
py.get_type::<exc::SystemError>().into()
|
2017-05-25 03:31:51 +00:00
|
|
|
} else {
|
2017-06-30 02:51:45 +00:00
|
|
|
Py::from_owned_ptr(ptype)
|
2017-05-25 03:31:51 +00:00
|
|
|
},
|
2017-06-23 03:56:09 +00:00
|
|
|
pvalue: PyObject::from_owned_ptr_or_opt(py, pvalue),
|
|
|
|
ptraceback: PyObject::from_owned_ptr_or_opt(py, ptraceback)
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-27 20:45:35 +00:00
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
fn new_helper(_py: Python, ty: &PyType, value: PyObject) -> PyErr {
|
2017-07-18 11:28:49 +00:00
|
|
|
assert_ne!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) }, 0);
|
2015-07-19 14:13:19 +00:00
|
|
|
PyErr {
|
2017-06-21 22:11:32 +00:00
|
|
|
ptype: ty.into(),
|
2017-05-31 00:23:23 +00:00
|
|
|
pvalue: Some(value),
|
2015-07-19 14:13:19 +00:00
|
|
|
ptraceback: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 00:40:48 +00:00
|
|
|
/// Creates a new PyErr.
|
2015-04-18 22:39:04 +00:00
|
|
|
///
|
2015-07-19 14:13:19 +00:00
|
|
|
/// `obj` must be an Python exception instance, the PyErr will use that instance.
|
2017-07-26 01:39:11 +00:00
|
|
|
/// If `obj` is a Python exception type object, the PyErr will (lazily) create a new
|
|
|
|
/// instance of that type.
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Otherwise, a `TypeError` is created instead.
|
2017-05-31 00:23:23 +00:00
|
|
|
pub fn from_instance<O>(py: Python, obj: O) -> PyErr where O: IntoPyObject {
|
|
|
|
PyErr::from_instance_helper(py, obj.into_object(py))
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
2015-06-27 20:45:35 +00:00
|
|
|
|
2017-07-18 11:28:49 +00:00
|
|
|
fn from_instance_helper(py: Python, obj: PyObject) -> PyErr {
|
2017-06-21 22:11:32 +00:00
|
|
|
let ptr = obj.as_ptr();
|
|
|
|
|
|
|
|
if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 {
|
2015-01-07 00:40:48 +00:00
|
|
|
PyErr {
|
2017-06-30 02:51:45 +00:00
|
|
|
ptype: unsafe { Py::from_borrowed_ptr( ffi::PyExceptionInstance_Class(ptr)) },
|
2017-05-31 00:23:23 +00:00
|
|
|
pvalue: Some(obj),
|
2015-01-07 00:40:48 +00:00
|
|
|
ptraceback: None
|
|
|
|
}
|
2015-01-11 03:21:05 +00:00
|
|
|
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
|
2015-01-07 00:40:48 +00:00
|
|
|
PyErr {
|
2017-06-22 08:04:37 +00:00
|
|
|
ptype: unsafe { Py::from_borrowed_ptr(ptr) },
|
2015-01-07 00:40:48 +00:00
|
|
|
pvalue: None,
|
|
|
|
ptraceback: None
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PyErr {
|
2017-06-21 22:11:32 +00:00
|
|
|
ptype: py.get_type::<exc::TypeError>().into(),
|
2017-05-30 23:29:13 +00:00
|
|
|
pvalue: Some("exceptions must derive from BaseException".into_object(py)),
|
2015-01-07 00:40:48 +00:00
|
|
|
ptraceback: None
|
|
|
|
}
|
2015-01-05 15:34:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Construct a new error, with the usual lazy initialization of Python exceptions.
|
2017-01-27 20:51:56 +00:00
|
|
|
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`.
|
2015-01-07 00:40:48 +00:00
|
|
|
/// `value` is the exception instance, or a tuple of arguments to pass to the exception constructor.
|
|
|
|
#[inline]
|
2017-06-23 03:56:09 +00:00
|
|
|
pub fn new_lazy_init(exc: &PyType, value: Option<PyObject>) -> PyErr {
|
2015-01-05 15:34:12 +00:00
|
|
|
PyErr {
|
2017-06-21 22:11:32 +00:00
|
|
|
ptype: exc.into(),
|
2015-01-05 15:34:12 +00:00
|
|
|
pvalue: value,
|
|
|
|
ptraceback: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-30 04:31:35 +00:00
|
|
|
/// Construct a new error, with the usual lazy initialization of Python exceptions.
|
|
|
|
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`.
|
|
|
|
/// `args` is the a tuple of arguments to pass to the exception constructor.
|
|
|
|
#[inline]
|
2017-06-06 03:25:00 +00:00
|
|
|
pub fn new_err<A>(py: Python, exc: &PyType, args: A) -> PyErr
|
|
|
|
where A: IntoPyTuple
|
2017-04-30 04:31:35 +00:00
|
|
|
{
|
|
|
|
PyErr {
|
2017-06-21 22:11:32 +00:00
|
|
|
ptype: exc.into(),
|
2017-06-06 03:25:00 +00:00
|
|
|
pvalue: Some(args.into_tuple(py).into()),
|
2017-04-30 04:31:35 +00:00
|
|
|
ptraceback: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-05 15:34:12 +00:00
|
|
|
/// Print a standard traceback to sys.stderr.
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn print(self, py: Python) {
|
2015-10-25 16:55:29 +00:00
|
|
|
self.restore(py);
|
2015-01-05 15:34:12 +00:00
|
|
|
unsafe { ffi::PyErr_PrintEx(0) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Print a standard traceback to sys.stderr.
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn print_and_set_sys_last_vars(self, py: Python) {
|
2015-10-25 16:55:29 +00:00
|
|
|
self.restore(py);
|
2015-01-05 15:34:12 +00:00
|
|
|
unsafe { ffi::PyErr_PrintEx(1) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return true if the current exception matches the exception in `exc`.
|
|
|
|
/// If `exc` is a class object, this also returns `true` when `self` is an instance of a subclass.
|
|
|
|
/// If `exc` is a tuple, all exceptions in the tuple (and recursively in subtuples) are searched for a match.
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn matches<T>(&self, py: Python, exc: T) -> bool
|
2016-04-17 21:26:33 +00:00
|
|
|
where T: ToPyObject
|
|
|
|
{
|
|
|
|
exc.with_borrowed_ptr(py, |exc| unsafe {
|
|
|
|
ffi::PyErr_GivenExceptionMatches(self.ptype.as_ptr(), exc) != 0
|
|
|
|
})
|
2015-01-05 15:34:12 +00:00
|
|
|
}
|
2015-06-27 20:45:35 +00:00
|
|
|
|
2015-01-05 15:34:12 +00:00
|
|
|
/// Normalizes the error. This ensures that the exception value is an instance of the exception type.
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn normalize(&mut self, py: Python) {
|
2015-01-05 15:34:12 +00:00
|
|
|
// The normalization helper function involves temporarily moving out of the &mut self,
|
|
|
|
// which requires some unsafe trickery:
|
|
|
|
unsafe {
|
2015-10-25 16:55:29 +00:00
|
|
|
std::ptr::write(self, std::ptr::read(self).into_normalized(py));
|
2015-01-05 15:34:12 +00:00
|
|
|
}
|
|
|
|
// This is safe as long as normalized() doesn't unwind due to a panic.
|
|
|
|
}
|
2015-10-26 22:52:18 +00:00
|
|
|
|
2015-01-05 15:34:12 +00:00
|
|
|
/// Helper function for normalizing the error by deconstructing and reconstructing the PyErr.
|
|
|
|
/// Must not panic for safety in normalize()
|
2017-05-28 15:57:34 +00:00
|
|
|
fn into_normalized(self, py: Python) -> PyErr {
|
2015-01-05 15:34:12 +00:00
|
|
|
let PyErr { ptype, pvalue, ptraceback } = self;
|
2017-05-25 03:31:51 +00:00
|
|
|
let mut ptype = ptype.into_ptr();
|
|
|
|
let mut pvalue = pvalue.into_ptr();
|
|
|
|
let mut ptraceback = ptraceback.into_ptr();
|
2015-01-05 15:34:12 +00:00
|
|
|
unsafe {
|
|
|
|
ffi::PyErr_NormalizeException(&mut ptype, &mut pvalue, &mut ptraceback);
|
|
|
|
PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback)
|
|
|
|
}
|
|
|
|
}
|
2015-06-27 20:45:35 +00:00
|
|
|
|
2015-01-06 00:04:25 +00:00
|
|
|
/// Retrieves the exception type.
|
2017-06-21 22:11:32 +00:00
|
|
|
pub fn get_type(&self, py: Python) -> Py<PyType> {
|
2017-06-04 00:42:12 +00:00
|
|
|
self.ptype.clone_ref(py)
|
2015-05-23 21:52:38 +00:00
|
|
|
}
|
2015-01-11 03:21:05 +00:00
|
|
|
|
2015-01-05 15:34:12 +00:00
|
|
|
/// Retrieves the exception instance for this error.
|
2015-04-18 22:39:04 +00:00
|
|
|
/// This method takes `&mut self` because the error might need
|
2015-01-06 00:04:25 +00:00
|
|
|
/// to be normalized in order to create the exception instance.
|
2017-06-23 03:56:09 +00:00
|
|
|
pub fn instance(&mut self, py: Python) -> PyObject {
|
2015-10-25 16:55:29 +00:00
|
|
|
self.normalize(py);
|
2015-01-05 15:34:12 +00:00
|
|
|
match self.pvalue {
|
2017-06-22 08:04:37 +00:00
|
|
|
Some(ref instance) => instance.clone_ref(py),
|
2017-06-01 20:34:46 +00:00
|
|
|
None => py.None(),
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Writes the error back to the Python interpreter's global state.
|
2015-04-18 22:39:04 +00:00
|
|
|
/// This is the opposite of `PyErr::fetch()`.
|
2015-01-07 00:40:48 +00:00
|
|
|
#[inline]
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn restore(self, _py: Python) {
|
2015-01-05 16:05:53 +00:00
|
|
|
let PyErr { ptype, pvalue, ptraceback } = self;
|
|
|
|
unsafe {
|
2017-05-25 03:31:51 +00:00
|
|
|
ffi::PyErr_Restore(ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr())
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-27 20:45:35 +00:00
|
|
|
|
2015-01-11 03:21:05 +00:00
|
|
|
/// Issue a warning message.
|
|
|
|
/// May return a PyErr if warnings-as-errors is enabled.
|
2017-06-24 15:28:31 +00:00
|
|
|
pub fn warn(py: Python, category: &PyObjectRef, message: &str, stacklevel: i32) -> PyResult<()> {
|
2017-06-17 09:40:11 +00:00
|
|
|
let message = CString::new(message).map_err(|e| e.to_pyerr(py))?;
|
2015-01-11 03:21:05 +00:00
|
|
|
unsafe {
|
2017-05-28 05:45:48 +00:00
|
|
|
error_on_minusone(py, ffi::PyErr_WarnEx(
|
|
|
|
category.as_ptr(), message.as_ptr(), stacklevel as ffi::Py_ssize_t))
|
2015-01-11 03:21:05 +00:00
|
|
|
}
|
|
|
|
}
|
2017-06-02 16:23:48 +00:00
|
|
|
|
2017-06-06 03:25:00 +00:00
|
|
|
pub fn clone_ref(&self, py: Python) -> PyErr {
|
2017-07-18 17:13:50 +00:00
|
|
|
let v = if let Some(ref val) = self.pvalue { Some(val.clone_ref(py))} else { None };
|
|
|
|
let t = if let Some(ref val) = self.ptraceback { Some(val.clone_ref(py))} else { None };
|
2017-06-06 03:25:00 +00:00
|
|
|
PyErr {
|
|
|
|
ptype: self.ptype.clone_ref(py),
|
2017-07-18 17:13:50 +00:00
|
|
|
pvalue: v,
|
|
|
|
ptraceback: t,
|
2017-06-06 03:25:00 +00:00
|
|
|
}
|
|
|
|
}
|
2017-06-07 02:26:59 +00:00
|
|
|
|
|
|
|
pub fn release(self, py: Python) {
|
|
|
|
let PyErr { ptype, pvalue, ptraceback } = self;
|
|
|
|
py.release(ptype);
|
|
|
|
py.release(pvalue);
|
|
|
|
py.release(ptraceback);
|
|
|
|
}
|
2015-01-05 15:34:12 +00:00
|
|
|
}
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
/// Converts `PyDowncastError` to Python `TypeError`.
|
|
|
|
impl <'p> std::convert::From<PyDowncastError<'p>> for PyErr {
|
|
|
|
fn from(err: PyDowncastError<'p>) -> PyErr {
|
2017-05-28 05:45:48 +00:00
|
|
|
PyErr::new_lazy_init(err.0.get_type::<exc::TypeError>(), None)
|
2017-05-25 03:31:51 +00:00
|
|
|
}
|
2016-04-17 21:26:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
impl <'p> std::fmt::Debug for PyDowncastError<'p> {
|
|
|
|
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
f.write_str("PyDowncastError")
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2017-06-11 15:46:23 +00:00
|
|
|
/// Convert `PyErr` to `io::Error`
|
2017-04-06 17:09:32 +00:00
|
|
|
impl std::convert::From<PyErr> for std::io::Error {
|
|
|
|
fn from(err: PyErr) -> Self {
|
|
|
|
std::io::Error::new(
|
|
|
|
std::io::ErrorKind::Other, format!("Python exception: {:?}", err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-11 15:46:23 +00:00
|
|
|
/// Converts into `PyErr`
|
2017-06-08 01:40:30 +00:00
|
|
|
pub trait ToPyErr {
|
|
|
|
fn to_pyerr(&self, Python) -> PyErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_to_pyerr {
|
|
|
|
($err: ty, $pyexc: ty) => {
|
|
|
|
impl $crate::ToPyErr for $err {
|
|
|
|
fn to_pyerr(&self, py: $crate::Python) -> PyErr {
|
|
|
|
PyErr::new::<$pyexc, _>(py, self.description())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-11 23:35:24 +00:00
|
|
|
#[cfg(Py_3)]
|
2017-06-11 15:46:23 +00:00
|
|
|
/// Create `OSError` from `io::Error`
|
2017-06-08 01:40:30 +00:00
|
|
|
impl ToPyErr for io::Error {
|
|
|
|
|
|
|
|
fn to_pyerr(&self, py: Python) -> PyErr {
|
|
|
|
let tp = match self.kind() {
|
|
|
|
io::ErrorKind::BrokenPipe => py.get_type::<exc::BrokenPipeError>(),
|
|
|
|
io::ErrorKind::ConnectionRefused => py.get_type::<exc::ConnectionRefusedError>(),
|
|
|
|
io::ErrorKind::ConnectionAborted => py.get_type::<exc::ConnectionAbortedError>(),
|
|
|
|
io::ErrorKind::ConnectionReset => py.get_type::<exc::ConnectionResetError>(),
|
|
|
|
io::ErrorKind::Interrupted => py.get_type::<exc::InterruptedError>(),
|
|
|
|
io::ErrorKind::NotFound => py.get_type::<exc::FileNotFoundError>(),
|
|
|
|
io::ErrorKind::WouldBlock => py.get_type::<exc::BlockingIOError>(),
|
|
|
|
io::ErrorKind::TimedOut => py.get_type::<exc::TimeoutError>(),
|
|
|
|
_ => py.get_type::<exc::OSError>(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let errno = self.raw_os_error().unwrap_or(0);
|
|
|
|
let errdesc = self.description();
|
|
|
|
|
2017-07-18 11:28:49 +00:00
|
|
|
PyErr::new_err(py, tp, (errno, errdesc))
|
2017-06-08 01:40:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-11 23:35:24 +00:00
|
|
|
#[cfg(not(Py_3))]
|
|
|
|
/// Create `OSError` from `io::Error`
|
|
|
|
impl ToPyErr for io::Error {
|
|
|
|
|
|
|
|
fn to_pyerr(&self, py: Python) -> PyErr {
|
|
|
|
let errno = self.raw_os_error().unwrap_or(0);
|
|
|
|
let errdesc = self.description();
|
|
|
|
|
|
|
|
PyErr::new_err(py, &py.get_type::<exc::OSError>(), (errno, errdesc))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-08 01:40:30 +00:00
|
|
|
impl<W: Send + std::fmt::Debug> ToPyErr for std::io::IntoInnerError<W> {
|
|
|
|
fn to_pyerr(&self, py: Python) -> PyErr {
|
|
|
|
PyErr::new::<exc::OSError, _>(py, self.description())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_to_pyerr!(std::num::ParseIntError, exc::ValueError);
|
|
|
|
impl_to_pyerr!(std::num::ParseFloatError, exc::ValueError);
|
|
|
|
impl_to_pyerr!(std::string::ParseError, exc::ValueError);
|
|
|
|
impl_to_pyerr!(std::str::ParseBoolError, exc::ValueError);
|
|
|
|
impl_to_pyerr!(std::ffi::IntoStringError, exc::UnicodeDecodeError);
|
2017-06-17 09:40:11 +00:00
|
|
|
impl_to_pyerr!(std::ffi::NulError, exc::ValueError);
|
2017-06-08 01:40:30 +00:00
|
|
|
impl_to_pyerr!(std::str::Utf8Error, exc::UnicodeDecodeError);
|
|
|
|
impl_to_pyerr!(std::string::FromUtf8Error, exc::UnicodeDecodeError);
|
|
|
|
impl_to_pyerr!(std::string::FromUtf16Error, exc::UnicodeDecodeError);
|
|
|
|
impl_to_pyerr!(std::char::DecodeUtf16Error, exc::UnicodeDecodeError);
|
|
|
|
impl_to_pyerr!(std::net::AddrParseError, exc::ValueError);
|
|
|
|
|
2017-05-28 05:45:48 +00:00
|
|
|
pub fn panic_after_error() -> ! {
|
2015-04-18 22:39:04 +00:00
|
|
|
unsafe { ffi::PyErr_Print(); }
|
|
|
|
panic!("Python API called failed");
|
|
|
|
}
|
|
|
|
|
2015-01-04 04:50:28 +00:00
|
|
|
/// Returns Ok if the error code is not -1.
|
|
|
|
#[inline]
|
2017-05-28 15:57:34 +00:00
|
|
|
pub fn error_on_minusone(py: Python, result: libc::c_int) -> PyResult<()> {
|
2015-01-04 04:50:28 +00:00
|
|
|
if result != -1 {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(PyErr::fetch(py))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 15:32:52 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2017-05-29 20:30:38 +00:00
|
|
|
use ::{Python, PyErr};
|
2015-06-27 21:49:53 +00:00
|
|
|
use objects::exc;
|
|
|
|
|
2015-01-04 15:32:52 +00:00
|
|
|
#[test]
|
|
|
|
fn set_typeerror() {
|
2017-05-29 20:30:38 +00:00
|
|
|
let gil = Python::acquire_gil();
|
2015-01-04 15:32:52 +00:00
|
|
|
let py = gil.python();
|
2015-10-25 16:55:29 +00:00
|
|
|
PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), None).restore(py);
|
2015-01-04 15:32:52 +00:00
|
|
|
assert!(PyErr::occurred(py));
|
2015-03-08 14:29:44 +00:00
|
|
|
drop(PyErr::fetch(py));
|
2015-01-04 15:32:52 +00:00
|
|
|
}
|
|
|
|
}
|