Skip to content

Commit e12e98a

Browse files
authored
Convert some std error types to PyErr (#22)
* Convert some std error types to PyErr * Add ToPyErr trait
1 parent a584ce1 commit e12e98a

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

src/err.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std;
2+
use std::io;
23
use std::ffi::CString;
34
use std::os::raw::c_char;
5+
use std::error::Error;
46
use libc;
57

68
use ffi;
@@ -369,6 +371,61 @@ impl std::convert::From<PyErr> for std::io::Error {
369371
}
370372
}
371373

374+
/// Converts into PyErr
375+
pub trait ToPyErr {
376+
fn to_pyerr(&self, Python) -> PyErr;
377+
}
378+
379+
macro_rules! impl_to_pyerr {
380+
($err: ty, $pyexc: ty) => {
381+
impl $crate::ToPyErr for $err {
382+
fn to_pyerr(&self, py: $crate::Python) -> PyErr {
383+
PyErr::new::<$pyexc, _>(py, self.description())
384+
}
385+
}
386+
}
387+
}
388+
389+
/// Create OSError from io::Error
390+
impl ToPyErr for io::Error {
391+
392+
fn to_pyerr(&self, py: Python) -> PyErr {
393+
let tp = match self.kind() {
394+
io::ErrorKind::BrokenPipe => py.get_type::<exc::BrokenPipeError>(),
395+
io::ErrorKind::ConnectionRefused => py.get_type::<exc::ConnectionRefusedError>(),
396+
io::ErrorKind::ConnectionAborted => py.get_type::<exc::ConnectionAbortedError>(),
397+
io::ErrorKind::ConnectionReset => py.get_type::<exc::ConnectionResetError>(),
398+
io::ErrorKind::Interrupted => py.get_type::<exc::InterruptedError>(),
399+
io::ErrorKind::NotFound => py.get_type::<exc::FileNotFoundError>(),
400+
io::ErrorKind::WouldBlock => py.get_type::<exc::BlockingIOError>(),
401+
io::ErrorKind::TimedOut => py.get_type::<exc::TimeoutError>(),
402+
_ => py.get_type::<exc::OSError>(),
403+
};
404+
405+
let errno = self.raw_os_error().unwrap_or(0);
406+
let errdesc = self.description();
407+
408+
PyErr::new_err(py, &tp, (errno, errdesc))
409+
}
410+
}
411+
412+
impl<W: Send + std::fmt::Debug> ToPyErr for std::io::IntoInnerError<W> {
413+
fn to_pyerr(&self, py: Python) -> PyErr {
414+
PyErr::new::<exc::OSError, _>(py, self.description())
415+
}
416+
}
417+
418+
impl_to_pyerr!(std::num::ParseIntError, exc::ValueError);
419+
impl_to_pyerr!(std::num::ParseFloatError, exc::ValueError);
420+
impl_to_pyerr!(std::string::ParseError, exc::ValueError);
421+
impl_to_pyerr!(std::str::ParseBoolError, exc::ValueError);
422+
impl_to_pyerr!(std::ffi::IntoStringError, exc::UnicodeDecodeError);
423+
impl_to_pyerr!(std::str::Utf8Error, exc::UnicodeDecodeError);
424+
impl_to_pyerr!(std::string::FromUtf8Error, exc::UnicodeDecodeError);
425+
impl_to_pyerr!(std::string::FromUtf16Error, exc::UnicodeDecodeError);
426+
impl_to_pyerr!(std::char::DecodeUtf16Error, exc::UnicodeDecodeError);
427+
impl_to_pyerr!(std::net::AddrParseError, exc::ValueError);
428+
372429
pub fn panic_after_error() -> ! {
373430
unsafe { ffi::PyErr_Print(); }
374431
panic!("Python API called failed");

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub use pointers::PyPtr;
7070
mod token;
7171
pub use token::{PyToken, PyObjectWithToken, ToInstancePtr, InstancePtr};
7272

73-
pub use err::{PyErr, PyResult, PyDowncastError};
73+
pub use err::{PyErr, PyResult, PyDowncastError, ToPyErr};
7474
pub use objects::*;
7575
pub use objectprotocol::ObjectProtocol;
7676
pub use python::{Python, ToPyPointer, IntoPyPointer, PyClone,

0 commit comments

Comments
 (0)