From e12e98a7c1c4a29f49c87497324890a768a6136e Mon Sep 17 00:00:00 2001 From: messense Date: Thu, 8 Jun 2017 09:40:30 +0800 Subject: [PATCH] Convert some std error types to PyErr (#22) * Convert some std error types to PyErr * Add ToPyErr trait --- src/err.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/err.rs b/src/err.rs index c0993001..b3e1dd64 100644 --- a/src/err.rs +++ b/src/err.rs @@ -1,6 +1,8 @@ use std; +use std::io; use std::ffi::CString; use std::os::raw::c_char; +use std::error::Error; use libc; use ffi; @@ -369,6 +371,61 @@ impl std::convert::From for std::io::Error { } } +/// Converts into PyErr +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()) + } + } + } +} + +/// Create OSError from io::Error +impl ToPyErr for io::Error { + + fn to_pyerr(&self, py: Python) -> PyErr { + let tp = match self.kind() { + io::ErrorKind::BrokenPipe => py.get_type::(), + io::ErrorKind::ConnectionRefused => py.get_type::(), + io::ErrorKind::ConnectionAborted => py.get_type::(), + io::ErrorKind::ConnectionReset => py.get_type::(), + io::ErrorKind::Interrupted => py.get_type::(), + io::ErrorKind::NotFound => py.get_type::(), + io::ErrorKind::WouldBlock => py.get_type::(), + io::ErrorKind::TimedOut => py.get_type::(), + _ => py.get_type::(), + }; + + let errno = self.raw_os_error().unwrap_or(0); + let errdesc = self.description(); + + PyErr::new_err(py, &tp, (errno, errdesc)) + } +} + +impl ToPyErr for std::io::IntoInnerError { + fn to_pyerr(&self, py: Python) -> PyErr { + PyErr::new::(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); +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); + pub fn panic_after_error() -> ! { unsafe { ffi::PyErr_Print(); } panic!("Python API called failed"); diff --git a/src/lib.rs b/src/lib.rs index edeee148..d743c8d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,7 @@ pub use pointers::PyPtr; mod token; pub use token::{PyToken, PyObjectWithToken, ToInstancePtr, InstancePtr}; -pub use err::{PyErr, PyResult, PyDowncastError}; +pub use err::{PyErr, PyResult, PyDowncastError, ToPyErr}; pub use objects::*; pub use objectprotocol::ObjectProtocol; pub use python::{Python, ToPyPointer, IntoPyPointer, PyClone,