This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch improve-python-errors
in repository https://gitbox.apache.org/repos/asf/opendal.git

commit d7707edb93d3151028793d5d1e3d71177a83dad9
Author: Xuanwo <git...@xuanwo.io>
AuthorDate: Thu Jun 19 15:02:52 2025 +0800

    fix(bindings/python): Fix Writer doesn't throw correct error code
    
    Signed-off-by: Xuanwo <git...@xuanwo.io>
---
 bindings/python/src/errors.rs | 19 ++++++++++++++++++-
 bindings/python/src/file.rs   |  7 ++-----
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/bindings/python/src/errors.rs b/bindings/python/src/errors.rs
index 575962cbf..336c36a52 100644
--- a/bindings/python/src/errors.rs
+++ b/bindings/python/src/errors.rs
@@ -17,6 +17,7 @@
 
 use pyo3::create_exception;
 use pyo3::exceptions::PyException;
+use pyo3::exceptions::PyIOError;
 
 use crate::*;
 
@@ -57,7 +58,7 @@ create_exception!(
     "Condition not match"
 );
 
-pub fn format_pyerr(err: ocore::Error) -> PyErr {
+fn format_pyerr_impl(err: &ocore::Error) -> PyErr {
     let e = format!("{err:?}");
     match err.kind() {
         ocore::ErrorKind::Unexpected => Unexpected::new_err(e),
@@ -73,3 +74,19 @@ pub fn format_pyerr(err: ocore::Error) -> PyErr {
         _ => Unexpected::new_err(e),
     }
 }
+
+pub fn format_pyerr(err: ocore::Error) -> PyErr {
+    format_pyerr_impl(&err)
+}
+
+/// Format a std::io::Error into a PyErr, checking if it wraps an OpenDAL error
+pub fn format_pyerr_from_io_error(err: std::io::Error) -> PyErr {
+    // Check if this io::Error wraps an OpenDAL error
+    if let Some(opendal_err) = err.get_ref().and_then(|e| 
e.downcast_ref::<ocore::Error>()) {
+        // If it does, format it as an OpenDAL error to preserve the error type
+        format_pyerr_impl(opendal_err)
+    } else {
+        // Otherwise, format it as a regular IO error
+        PyIOError::new_err(err.to_string())
+    }
+}
diff --git a/bindings/python/src/file.rs b/bindings/python/src/file.rs
index a84fa8ade..10aa24d80 100644
--- a/bindings/python/src/file.rs
+++ b/bindings/python/src/file.rs
@@ -268,8 +268,7 @@ impl File {
 
     fn close(&mut self) -> PyResult<()> {
         if let FileState::Writer(w) = &mut self.0 {
-            w.close()
-                .map_err(|err| PyIOError::new_err(err.to_string()))?;
+            w.close().map_err(format_pyerr_from_io_error)?;
         };
         self.0 = FileState::Closed;
         Ok(())
@@ -514,9 +513,7 @@ impl AsyncFile {
         future_into_py(py, async move {
             let mut state = state.lock().await;
             if let AsyncFileState::Writer(w) = &mut *state {
-                w.close()
-                    .await
-                    .map_err(|err| PyIOError::new_err(err.to_string()))?;
+                w.close().await.map_err(format_pyerr_from_io_error)?;
             }
             *state = AsyncFileState::Closed;
             Ok(())

Reply via email to