pyo3/err/
impls.rs
1use crate::IntoPyObject;
2use crate::{err::PyErrArguments, exceptions, PyErr, PyObject, Python};
3use std::io;
4
5impl From<PyErr> for io::Error {
7 fn from(err: PyErr) -> Self {
8 let kind = Python::with_gil(|py| {
9 if err.is_instance_of::<exceptions::PyBrokenPipeError>(py) {
10 io::ErrorKind::BrokenPipe
11 } else if err.is_instance_of::<exceptions::PyConnectionRefusedError>(py) {
12 io::ErrorKind::ConnectionRefused
13 } else if err.is_instance_of::<exceptions::PyConnectionAbortedError>(py) {
14 io::ErrorKind::ConnectionAborted
15 } else if err.is_instance_of::<exceptions::PyConnectionResetError>(py) {
16 io::ErrorKind::ConnectionReset
17 } else if err.is_instance_of::<exceptions::PyInterruptedError>(py) {
18 io::ErrorKind::Interrupted
19 } else if err.is_instance_of::<exceptions::PyFileNotFoundError>(py) {
20 io::ErrorKind::NotFound
21 } else if err.is_instance_of::<exceptions::PyPermissionError>(py) {
22 io::ErrorKind::PermissionDenied
23 } else if err.is_instance_of::<exceptions::PyFileExistsError>(py) {
24 io::ErrorKind::AlreadyExists
25 } else if err.is_instance_of::<exceptions::PyBlockingIOError>(py) {
26 io::ErrorKind::WouldBlock
27 } else if err.is_instance_of::<exceptions::PyTimeoutError>(py) {
28 io::ErrorKind::TimedOut
29 } else {
30 io::ErrorKind::Other
31 }
32 });
33 io::Error::new(kind, err)
34 }
35}
36
37impl From<io::Error> for PyErr {
41 fn from(err: io::Error) -> PyErr {
42 if err.get_ref().map_or(false, |e| e.is::<PyErr>()) {
44 return *err.into_inner().unwrap().downcast().unwrap();
45 }
46 match err.kind() {
47 io::ErrorKind::BrokenPipe => exceptions::PyBrokenPipeError::new_err(err),
48 io::ErrorKind::ConnectionRefused => exceptions::PyConnectionRefusedError::new_err(err),
49 io::ErrorKind::ConnectionAborted => exceptions::PyConnectionAbortedError::new_err(err),
50 io::ErrorKind::ConnectionReset => exceptions::PyConnectionResetError::new_err(err),
51 io::ErrorKind::Interrupted => exceptions::PyInterruptedError::new_err(err),
52 io::ErrorKind::NotFound => exceptions::PyFileNotFoundError::new_err(err),
53 io::ErrorKind::PermissionDenied => exceptions::PyPermissionError::new_err(err),
54 io::ErrorKind::AlreadyExists => exceptions::PyFileExistsError::new_err(err),
55 io::ErrorKind::WouldBlock => exceptions::PyBlockingIOError::new_err(err),
56 io::ErrorKind::TimedOut => exceptions::PyTimeoutError::new_err(err),
57 _ => exceptions::PyOSError::new_err(err),
58 }
59 }
60}
61
62impl PyErrArguments for io::Error {
63 fn arguments(self, py: Python<'_>) -> PyObject {
64 self.to_string()
66 .into_pyobject(py)
67 .unwrap()
68 .into_any()
69 .unbind()
70 }
71}
72
73impl<W> From<io::IntoInnerError<W>> for PyErr {
74 fn from(err: io::IntoInnerError<W>) -> PyErr {
75 err.into_error().into()
76 }
77}
78
79impl<W: Send + Sync> PyErrArguments for io::IntoInnerError<W> {
80 fn arguments(self, py: Python<'_>) -> PyObject {
81 self.into_error().arguments(py)
82 }
83}
84
85impl From<std::convert::Infallible> for PyErr {
86 fn from(_: std::convert::Infallible) -> PyErr {
87 unreachable!()
88 }
89}
90
91macro_rules! impl_to_pyerr {
92 ($err: ty, $pyexc: ty) => {
93 impl PyErrArguments for $err {
94 fn arguments(self, py: Python<'_>) -> PyObject {
95 self.to_string()
97 .into_pyobject(py)
98 .unwrap()
99 .into_any()
100 .unbind()
101 }
102 }
103
104 impl std::convert::From<$err> for PyErr {
105 fn from(err: $err) -> PyErr {
106 <$pyexc>::new_err(err)
107 }
108 }
109 };
110}
111
112impl_to_pyerr!(std::array::TryFromSliceError, exceptions::PyValueError);
113impl_to_pyerr!(std::num::ParseIntError, exceptions::PyValueError);
114impl_to_pyerr!(std::num::ParseFloatError, exceptions::PyValueError);
115impl_to_pyerr!(std::num::TryFromIntError, exceptions::PyValueError);
116impl_to_pyerr!(std::str::ParseBoolError, exceptions::PyValueError);
117impl_to_pyerr!(std::ffi::IntoStringError, exceptions::PyUnicodeDecodeError);
118impl_to_pyerr!(std::ffi::NulError, exceptions::PyValueError);
119impl_to_pyerr!(std::str::Utf8Error, exceptions::PyUnicodeDecodeError);
120impl_to_pyerr!(std::string::FromUtf8Error, exceptions::PyUnicodeDecodeError);
121impl_to_pyerr!(
122 std::string::FromUtf16Error,
123 exceptions::PyUnicodeDecodeError
124);
125impl_to_pyerr!(
126 std::char::DecodeUtf16Error,
127 exceptions::PyUnicodeDecodeError
128);
129impl_to_pyerr!(std::net::AddrParseError, exceptions::PyValueError);
130
131#[cfg(test)]
132mod tests {
133 use crate::{PyErr, Python};
134 use std::io;
135
136 #[test]
137 fn io_errors() {
138 use crate::types::any::PyAnyMethods;
139
140 let check_err = |kind, expected_ty| {
141 Python::with_gil(|py| {
142 let rust_err = io::Error::new(kind, "some error msg");
143
144 let py_err: PyErr = rust_err.into();
145 let py_err_msg = format!("{}: some error msg", expected_ty);
146 assert_eq!(py_err.to_string(), py_err_msg);
147 let py_error_clone = py_err.clone_ref(py);
148
149 let rust_err_from_py_err: io::Error = py_err.into();
150 assert_eq!(rust_err_from_py_err.to_string(), py_err_msg);
151 assert_eq!(rust_err_from_py_err.kind(), kind);
152
153 let py_err_recovered_from_rust_err: PyErr = rust_err_from_py_err.into();
154 assert!(py_err_recovered_from_rust_err
155 .value(py)
156 .is(py_error_clone.value(py))); })
158 };
159
160 check_err(io::ErrorKind::BrokenPipe, "BrokenPipeError");
161 check_err(io::ErrorKind::ConnectionRefused, "ConnectionRefusedError");
162 check_err(io::ErrorKind::ConnectionAborted, "ConnectionAbortedError");
163 check_err(io::ErrorKind::ConnectionReset, "ConnectionResetError");
164 check_err(io::ErrorKind::Interrupted, "InterruptedError");
165 check_err(io::ErrorKind::NotFound, "FileNotFoundError");
166 check_err(io::ErrorKind::PermissionDenied, "PermissionError");
167 check_err(io::ErrorKind::AlreadyExists, "FileExistsError");
168 check_err(io::ErrorKind::WouldBlock, "BlockingIOError");
169 check_err(io::ErrorKind::TimedOut, "TimeoutError");
170 }
171}