pyo3/src/err.rs

577 lines
19 KiB
Rust
Raw Normal View History

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;
use std::io;
2017-05-25 03:31:51 +00:00
use std::ffi::CString;
use std::os::raw::c_char;
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-07-26 16:16:26 +00:00
use object::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;
use conversion::{ToPyObject, IntoPyObject, ToBorrowedObject};
2015-01-05 16:05:53 +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]
/// extern crate pyo3;
///
/// use pyo3::{Python, PyDict};
///
/// py_exception!(mymodule, CustomError);
///
/// fn main() {
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// let ctx = PyDict::new(py);
///
/// ctx.set_item("CustomError", py.get_type::<CustomError>()).unwrap();
///
/// py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"",
/// None, Some(&ctx)).unwrap();
/// py.run("assert CustomError('oops').args == ('oops',)", None, Some(ctx)).unwrap();
/// }
/// ```
#[macro_export]
macro_rules! py_exception {
($module: ident, $name: ident, $base: ty) => {
2017-05-25 03:31:51 +00:00
pub struct $name;
impl ::std::convert::From<$name> for $crate::PyErr {
fn from(_err: $name) -> $crate::PyErr {
$crate::PyErr::new::<$name, _>(())
}
}
impl $name {
pub fn new<T: $crate::ToPyObject + 'static>(args: T) -> $crate::PyErr {
$crate::PyErr::new::<$name, T>(args)
}
2017-07-27 03:29:07 +00:00
#[inline]
2017-07-26 01:11:45 +00:00
fn type_object() -> *mut $crate::ffi::PyTypeObject {
2017-07-27 03:29:07 +00:00
static mut TYPE_OBJECT: *mut $crate::ffi::PyTypeObject =
2017-06-08 21:21:48 +00:00
0 as *mut $crate::ffi::PyTypeObject;
unsafe {
2017-07-27 03:29:07 +00:00
if TYPE_OBJECT.is_null() {
2017-07-26 01:11:45 +00:00
let gil = $crate::Python::acquire_gil();
let py = gil.python();
2017-07-27 03:29:07 +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);
}
2017-07-27 03:29:07 +00:00
TYPE_OBJECT
}
}
}
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
}
}
};
($module: ident, $name: ident) => {
py_exception!($module, $name, $crate::exc::Exception);
}
}
/// Represents a PyErr value
pub enum PyErrValue {
None,
Value(PyObject),
2017-07-26 21:28:04 +00:00
ToArgs(Box<PyErrArguments>),
ToObject(Box<ToPyObject>),
}
2015-06-27 20:45:35 +00:00
/// Represents a Python exception that was raised.
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>,
2017-07-26 17:47:17 +00:00
2015-04-18 22:39:04 +00:00
/// The value of the exception.
///
2017-07-26 17:47:17 +00:00
/// This can be either an instance of `PyObject`,
2015-04-18 22:39:04 +00:00
/// 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,
2017-07-26 17:47:17 +00:00
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.
pub type PyResult<T> = Result<T, PyErr>;
2015-01-05 16:05:53 +00:00
2017-06-20 06:57:34 +00:00
/// Marker type that indicates an error while downcasting
pub struct PyDowncastError;
2017-05-25 03:31:51 +00:00
2017-07-26 17:47:17 +00:00
/// Helper conversion trait that allows to use custom arguments for exception constructor.
pub trait PyErrArguments {
2017-07-26 16:16:26 +00:00
/// Arguments for exception
fn arguments(&self, Python) -> PyObject;
}
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, _>("Error message"));`
pub fn new<T, V>(value: V) -> PyErr
where T: PyTypeObject, V: ToPyObject + 'static
{
let ty = T::type_object();
assert_ne!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) }, 0);
PyErr {
ptype: ty,
pvalue: PyErrValue::ToObject(Box::new(value)),
ptraceback: None,
}
}
/// Construct a new error, with the usual lazy initialization of Python exceptions.
/// `exc` is the exception type; usually one of the standard exceptions
2017-07-26 21:28:04 +00:00
/// like `exc::RuntimeError`.
/// `args` is the a tuple of arguments to pass to the exception constructor.
pub fn from_type<A>(exc: Py<PyType>, args: A) -> PyErr
2017-07-26 21:28:04 +00:00
where A: ToPyObject + 'static
2017-01-27 20:51:56 +00:00
{
PyErr {
ptype: exc,
2017-07-26 21:28:04 +00:00
pvalue: PyErrValue::ToObject(Box::new(args)),
ptraceback: None,
}
}
/// Creates a new PyErr of type `T`.
pub fn from_value<T>(value: PyErrValue) -> PyErr
where T: PyTypeObject
{
let ty = T::type_object();
assert_ne!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) }, 0);
PyErr {
ptype: ty,
pvalue: value,
ptraceback: None,
}
2017-01-27 20:51:56 +00:00
}
2017-07-27 03:29:07 +00:00
/// Creates a new PyErr.
///
/// `obj` must be an Python exception instance, the PyErr will use that instance.
/// If `obj` is a Python exception type object, the PyErr will (lazily) create a new
/// instance of that type.
/// Otherwise, a `TypeError` is created instead.
pub fn from_instance(obj: &PyObjectRef) -> PyErr {
let ptr = obj.as_ptr();
if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 {
PyErr {
ptype: unsafe { Py::from_borrowed_ptr( ffi::PyExceptionInstance_Class(ptr)) },
pvalue: PyErrValue::Value(obj.into()),
ptraceback: None,
}
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
PyErr {
ptype: unsafe { Py::from_borrowed_ptr(ptr) },
pvalue: PyErrValue::None,
ptraceback: None,
}
} else {
PyErr {
ptype: exc::TypeError::type_object(),
pvalue: PyErrValue::ToObject(
Box::new("exceptions must derive from BaseException")),
ptraceback: None,
}
}
}
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() }
}
2017-07-27 03:29:07 +00:00
/// Retrieves the current error from the Python interpreter's global state.
/// The error is cleared from the Python interpreter.
/// If no error is set, returns a `SystemError`.
pub fn fetch(_: Python) -> PyErr {
unsafe {
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();
ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback);
PyErr::new_from_ffi_tuple(ptype, pvalue, ptraceback)
}
}
/// 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
{
let base: *mut ffi::PyObject = match base {
None => std::ptr::null_mut(),
2017-06-22 08:04:37 +00:00
Some(obj) => obj.as_ptr()
};
let dict: *mut ffi::PyObject = match dict {
None => std::ptr::null_mut(),
2017-06-22 08:04:37 +00:00
Some(obj) => obj.as_ptr(),
};
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
}
}
unsafe fn new_from_ffi_tuple(ptype: *mut ffi::PyObject,
2017-05-25 03:31:51 +00:00
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().
let pvalue = if let Some(obj) =
PyObject::from_owned_ptr_or_opt(Python::assume_gil_acquired(), pvalue)
{
PyErrValue::Value(obj)
} else {
PyErrValue::None
};
2015-01-05 15:34:12 +00:00
PyErr {
ptype: if ptype.is_null() {
<exc::SystemError as PyTypeObject>::type_object()
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
},
pvalue: pvalue,
ptraceback: PyObject::from_owned_ptr_or_opt(Python::assume_gil_acquired(), ptraceback),
}
}
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) {
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) {
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
where T: ToBorrowedObject
{
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
2017-07-26 21:28:04 +00:00
/// Return true if the current exception is instance of `T`
pub fn is_instance<T>(&self, _py: Python) -> bool
where T: PyTypeObject
{
unsafe {
ffi::PyErr_GivenExceptionMatches(
self.ptype.as_ptr(), T::type_object().as_ptr()) != 0
}
}
2017-07-27 03:29:07 +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 {
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-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;
let mut pvalue = match pvalue {
PyErrValue::None => std::ptr::null_mut(),
PyErrValue::Value(ob) => ob.into_ptr(),
2017-07-26 21:28:04 +00:00
PyErrValue::ToArgs(ob) => ob.arguments(py).into_ptr(),
PyErrValue::ToObject(ob) => ob.to_object(py).into_ptr(),
};
2017-05-25 03:31:51 +00:00
let mut ptype = ptype.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(ptype, pvalue, ptraceback)
2015-01-05 15:34:12 +00:00
}
}
2015-06-27 20:45:35 +00:00
2015-01-05 15:34:12 +00:00
/// Retrieves the exception instance for this error.
/// 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.
fn instance(mut self, py: Python) -> PyObject {
&self.normalize(py);
2015-01-05 15:34:12 +00:00
match self.pvalue {
PyErrValue::Value(ref instance) => instance.clone_ref(py),
_ => 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()`.
#[inline]
pub fn restore(self, py: Python) {
2015-01-05 16:05:53 +00:00
let PyErr { ptype, pvalue, ptraceback } = self;
let pvalue = match pvalue {
PyErrValue::None => std::ptr::null_mut(),
PyErrValue::Value(ob) => ob.into_ptr(),
2017-07-26 21:28:04 +00:00
PyErrValue::ToArgs(ob) => ob.arguments(py).into_ptr(),
PyErrValue::ToObject(ob) => ob.to_object(py).into_ptr(),
};
2015-01-05 16:05:53 +00:00
unsafe {
ffi::PyErr_Restore(ptype.into_ptr(), pvalue, 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<()> {
let message = CString::new(message)?;
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
pub fn clone_ref(&self, py: Python) -> PyErr {
let v = match self.pvalue {
PyErrValue::None => PyErrValue::None,
PyErrValue::Value(ref ob) => PyErrValue::Value(ob.clone_ref(py)),
PyErrValue::ToArgs(ref ob) => PyErrValue::Value(ob.arguments(py)),
PyErrValue::ToObject(ref ob) => PyErrValue::Value(ob.to_object(py)),
};
2017-07-18 17:13:50 +00:00
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
}
}
2015-01-05 15:34:12 +00:00
}
2015-01-05 16:05:53 +00:00
impl std::fmt::Debug for PyErr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str(format!("PyErr {{ type: {:?} }}", self.ptype).as_str())
}
}
impl IntoPyObject for PyErr {
fn into_object(self, py: Python) -> PyObject {
self.instance(py)
}
}
impl ToPyObject for PyErr {
fn to_object(&self, py: Python) -> PyObject {
let err = self.clone_ref(py);
err.instance(py)
}
}
impl<'a> IntoPyObject for &'a PyErr {
fn into_object(self, py: Python) -> PyObject {
let err = self.clone_ref(py);
err.instance(py)
}
}
2017-05-25 03:31:51 +00:00
/// Converts `PyDowncastError` to Python `TypeError`.
impl std::convert::From<PyDowncastError> for PyErr {
fn from(_err: PyDowncastError) -> PyErr {
2017-07-26 17:47:17 +00:00
exc::TypeError.into()
2017-05-25 03:31:51 +00:00
}
}
impl <'p> std::fmt::Debug for PyDowncastError {
2017-05-25 03:31:51 +00:00
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str("PyDowncastError")
}
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))
}
}
macro_rules! impl_to_pyerr {
($err: ty, $pyexc: ty) => {
2017-07-26 17:47:17 +00:00
impl PyErrArguments for $err {
fn arguments(&self, py: Python) -> PyObject {
self.description().to_object(py)
}
}
2017-07-26 17:47:17 +00:00
impl std::convert::From<$err> for PyErr {
fn from(err: $err) -> PyErr {
2017-07-26 21:28:04 +00:00
PyErr::from_value::<$pyexc>(PyErrValue::ToArgs(Box::new(err)))
}
}
}
}
2017-06-11 23:35:24 +00:00
#[cfg(Py_3)]
2017-06-11 15:46:23 +00:00
/// Create `OSError` from `io::Error`
impl std::convert::From<io::Error> for PyErr {
fn from(err: io::Error) -> PyErr {
match err.kind() {
io::ErrorKind::BrokenPipe =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::BrokenPipeError>(PyErrValue::ToArgs(Box::new(err))),
io::ErrorKind::ConnectionRefused =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::ConnectionRefusedError>(
PyErrValue::ToArgs(Box::new(err))),
io::ErrorKind::ConnectionAborted =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::ConnectionAbortedError>(
PyErrValue::ToArgs(Box::new(err))),
io::ErrorKind::ConnectionReset =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::ConnectionResetError>(
PyErrValue::ToArgs(Box::new(err))),
io::ErrorKind::Interrupted =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::InterruptedError>(PyErrValue::ToArgs(Box::new(err))),
io::ErrorKind::NotFound =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::FileNotFoundError>(PyErrValue::ToArgs(Box::new(err))),
io::ErrorKind::WouldBlock =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::BlockingIOError>(PyErrValue::ToArgs(Box::new(err))),
io::ErrorKind::TimedOut =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::TimeoutError>(PyErrValue::ToArgs(Box::new(err))),
_ =>
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::OSError>(PyErrValue::ToArgs(Box::new(err))),
}
}
}
2017-06-11 23:35:24 +00:00
#[cfg(not(Py_3))]
/// Create `OSError` from `io::Error`
impl std::convert::From<io::Error> for PyErr {
fn from(err: io::Error) -> PyErr {
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::OSError>(PyErrValue::ToArgs(Box::new(err)))
}
}
2017-06-11 23:35:24 +00:00
/// Extract `errno` and `errdesc` from from `io::Error`
2017-07-26 17:47:17 +00:00
impl PyErrArguments for io::Error {
2017-07-26 16:16:26 +00:00
fn arguments(&self, py: Python) -> PyObject {
(self.raw_os_error().unwrap_or(0), self.description()).to_object(py)
}
}
2017-06-11 23:35:24 +00:00
impl<W: 'static + Send + std::fmt::Debug> std::convert::From<std::io::IntoInnerError<W>> for PyErr
{
fn from(err: std::io::IntoInnerError<W>) -> PyErr {
2017-07-26 21:28:04 +00:00
PyErr::from_value::<exc::OSError>(PyErrValue::ToArgs(Box::new(err)))
2017-06-11 23:35:24 +00:00
}
}
2017-07-26 17:47:17 +00:00
impl<W: Send + std::fmt::Debug> PyErrArguments for std::io::IntoInnerError<W> {
2017-07-26 16:16:26 +00:00
fn arguments(&self, py: Python) -> PyObject {
self.description().to_object(py)
}
}
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);
impl_to_pyerr!(std::ffi::NulError, exc::ValueError);
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();
let err: PyErr = exc::TypeError.into();
err.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
}
}