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

manjusaka pushed a commit to branch manjusaka/polish-exception
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


The following commit(s) were added to refs/heads/manjusaka/polish-exception by 
this push:
     new d0fa9a22e update code
d0fa9a22e is described below

commit d0fa9a22ed2642be3ca7c2f57ce25bf53b904d34
Author: Manjusaka <[email protected]>
AuthorDate: Mon Nov 6 22:35:12 2023 +0800

    update code
    
    Signed-off-by: Manjusaka <[email protected]>
---
 bindings/python/python/opendal/exceptions.pyi | 30 ++++++++++----------
 bindings/python/src/errors.rs                 |  9 ++++--
 bindings/python/src/lib.rs                    | 40 ++++++++++-----------------
 bindings/python/src/operator.rs               | 10 ++++---
 bindings/python/tests/test_async_copy.py      | 10 +++----
 bindings/python/tests/test_async_delete.py    |  4 +--
 bindings/python/tests/test_async_rename.py    | 16 +++++------
 bindings/python/tests/test_read.py            |  6 ++--
 bindings/python/tests/test_sync_copy.py       | 10 +++----
 bindings/python/tests/test_sync_delete.py     |  4 +--
 bindings/python/tests/test_sync_rename.py     | 16 +++++------
 bindings/python/tests/test_write.py           |  6 ++--
 bindings/python/upgrade.md                    | 19 +++++++++++++
 13 files changed, 97 insertions(+), 83 deletions(-)

diff --git a/bindings/python/python/opendal/exceptions.pyi 
b/bindings/python/python/opendal/exceptions.pyi
index 9ca922335..af37d7b6d 100644
--- a/bindings/python/python/opendal/exceptions.pyi
+++ b/bindings/python/python/opendal/exceptions.pyi
@@ -15,72 +15,72 @@
 # specific language governing permissions and limitations
 # under the License.
 
-class Error(Exception):
-    """OpenDAL unrelated errors"""
+class Unknown(Exception):
+    """Unknown error"""
 
     pass
 
-class UnexpectedError(Exception):
+class Unexpected(Exception):
     """Unexpected errors"""
 
     pass
 
-class UnsupportedError(Exception):
+class Unsupported(Exception):
     """Unsupported operation"""
 
     pass
 
-class ConfigInvalidError(Exception):
+class ConfigInvalid(Exception):
     """Config is invalid"""
 
     pass
 
-class NotFoundError(Exception):
+class NotFound(Exception):
     """Not found"""
 
     pass
 
-class PermissionDeniedError(Exception):
+class PermissionDenied(Exception):
     """Permission denied"""
 
     pass
 
-class IsADirectoryError(Exception):
+class IsADirectory(Exception):
     """Is a directory"""
 
     pass
 
-class NotADirectoryError(Exception):
+class NotADirectory(Exception):
     """Not a directory"""
 
     pass
 
-class AlreadyExistsError(Exception):
+class AlreadyExists(Exception):
     """Already exists"""
 
     pass
 
-class IsSameFileError(Exception):
+class IsSameFile(Exception):
     """Is same file"""
 
     pass
 
-class ConditionNotMatchError(Exception):
+class ConditionNotMatch(Exception):
     """Condition not match"""
 
     pass
 
-class ContentTruncatedError(Exception):
+class ContentTruncated(Exception):
     """Content truncated"""
 
     pass
 
-class ContentIncompleteError(Exception):
+class ContentIncomplete(Exception):
     """Content incomplete"""
 
     pass
 
-class InvalidInputError(Exception):
+class InvalidInput(Exception):
     """Invalid input"""
 
     pass
diff --git a/bindings/python/src/errors.rs b/bindings/python/src/errors.rs
index 5d7f98e49..af9a10e80 100644
--- a/bindings/python/src/errors.rs
+++ b/bindings/python/src/errors.rs
@@ -63,7 +63,12 @@ create_exception!(
     "Content incomplete"
 );
 create_exception!(opendal, InvalidInputError, PyException, "Invalid input");
-create_exception!(opendal, Error, PyException, "OpenDAL unrelated errors");
+create_exception!(
+    opendal,
+    Unknown,
+    PyException,
+    "OpenDAL Python binding unknown error"
+);
 
 pub fn format_pyerr(err: ocore::Error) -> PyErr {
     use ocore::ErrorKind::*;
@@ -81,6 +86,6 @@ pub fn format_pyerr(err: ocore::Error) -> PyErr {
         ContentTruncated => ContentTruncatedError::new_err(err.to_string()),
         ContentIncomplete => ContentIncompleteError::new_err(err.to_string()),
         InvalidInput => InvalidInputError::new_err(err.to_string()),
-        _ => Error::new_err(err.to_string()),
+        _ => Unknown::new_err(err.to_string()),
     }
 }
diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs
index bada6d204..f52e86188 100644
--- a/bindings/python/src/lib.rs
+++ b/bindings/python/src/lib.rs
@@ -95,32 +95,20 @@ fn _opendal(py: Python, m: &PyModule) -> PyResult<()> {
         .set_item("opendal.layers", layers_module)?;
 
     let exception_module = PyModule::new(py, "exceptions")?;
-    exception_module.add("Error", py.get_type::<Error>())?;
-    exception_module.add("UnexpectedError", py.get_type::<UnexpectedError>())?;
-    exception_module.add("UnsupportedError", 
py.get_type::<UnsupportedError>())?;
-    exception_module.add("ConfigInvalidError", 
py.get_type::<ConfigInvalidError>())?;
-    exception_module.add("NotFoundError", py.get_type::<NotFoundError>())?;
-    exception_module.add(
-        "PermissionDeniedError",
-        py.get_type::<PermissionDeniedError>(),
-    )?;
-    exception_module.add("IsADirectoryError", 
py.get_type::<IsADirectoryError>())?;
-    exception_module.add("NotADirectoryError", 
py.get_type::<NotADirectoryError>())?;
-    exception_module.add("AlreadyExistsError", 
py.get_type::<AlreadyExistsError>())?;
-    exception_module.add("IsSameFileError", py.get_type::<IsSameFileError>())?;
-    exception_module.add(
-        "ConditionNotMatchError",
-        py.get_type::<ConditionNotMatchError>(),
-    )?;
-    exception_module.add(
-        "ContentTruncatedError",
-        py.get_type::<ContentTruncatedError>(),
-    )?;
-    exception_module.add(
-        "ContentIncompleteError",
-        py.get_type::<ContentIncompleteError>(),
-    )?;
-    exception_module.add("InvalidInputError", 
py.get_type::<InvalidInputError>())?;
+    exception_module.add("Unknown", py.get_type::<Unknown>())?;
+    exception_module.add("Unexpected", py.get_type::<UnexpectedError>())?;
+    exception_module.add("Unsupported", py.get_type::<UnsupportedError>())?;
+    exception_module.add("ConfigInvalid", 
py.get_type::<ConfigInvalidError>())?;
+    exception_module.add("NotFound", py.get_type::<NotFoundError>())?;
+    exception_module.add("PermissionDenied", 
py.get_type::<PermissionDeniedError>())?;
+    exception_module.add("IsADirectory", py.get_type::<IsADirectoryError>())?;
+    exception_module.add("NotADirectory", 
py.get_type::<NotADirectoryError>())?;
+    exception_module.add("AlreadyExists", 
py.get_type::<AlreadyExistsError>())?;
+    exception_module.add("IsSameFile", py.get_type::<IsSameFileError>())?;
+    exception_module.add("ConditionNotMatch", 
py.get_type::<ConditionNotMatchError>())?;
+    exception_module.add("ContentTruncated", 
py.get_type::<ContentTruncatedError>())?;
+    exception_module.add("ContentIncomplete", 
py.get_type::<ContentIncompleteError>())?;
+    exception_module.add("InvalidInput", py.get_type::<InvalidInputError>())?;
     m.add_submodule(exception_module)?;
     py.import("sys")?
         .getattr("modules")?
diff --git a/bindings/python/src/operator.rs b/bindings/python/src/operator.rs
index 5bc95a2cc..ac2326323 100644
--- a/bindings/python/src/operator.rs
+++ b/bindings/python/src/operator.rs
@@ -86,7 +86,7 @@ impl Operator {
             let w = this.writer(&path).map_err(format_pyerr)?;
             Ok(File::new_writer(w))
         } else {
-            Err(Error::new_err(format!(
+            Err(UnsupportedError::new_err(format!(
                 "OpenDAL doesn't support mode: {mode}"
             )))
         }
@@ -245,7 +245,7 @@ impl AsyncOperator {
                 let w = this.writer(&path).await.map_err(format_pyerr)?;
                 Ok(AsyncFile::new_writer(w))
             } else {
-                Err(Error::new_err(format!(
+                Err(UnsupportedError::new_err(format!(
                     "OpenDAL doesn't support mode: {mode}"
                 )))
             }
@@ -547,9 +547,11 @@ impl PresignedRequest {
         let mut headers = HashMap::new();
         for (k, v) in self.0.header().iter() {
             let k = k.as_str();
-            let v = v.to_str().map_err(|err| Error::new_err(err.to_string()))?;
+            let v = v
+                .to_str()
+                .map_err(|err| Unknown::new_err(err.to_string()))?;
             if headers.insert(k, v).is_some() {
-                return Err(Error::new_err("duplicate header"));
+                return Err(Unknown::new_err("duplicate header"));
             }
         }
         Ok(headers)
diff --git a/bindings/python/tests/test_async_copy.py 
b/bindings/python/tests/test_async_copy.py
index 551709e1b..424e3427c 100644
--- a/bindings/python/tests/test_async_copy.py
+++ b/bindings/python/tests/test_async_copy.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import IsADirectoryError, IsSameFileError, 
NotFoundError
+from opendal.exceptions import IsADirectory, IsSameFile, NotFound
 
 
 @pytest.mark.asyncio
@@ -43,7 +43,7 @@ async def test_async_copy(service_name, operator, 
async_operator):
 async def test_async_copy_non_exist(service_name, operator, async_operator):
     source_path = f"random_file_{str(uuid4())}"
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         await async_operator.copy(source_path, target_path)
 
 
@@ -53,7 +53,7 @@ async def test_async_copy_source_directory(service_name, 
operator, async_operato
     source_path = f"random_file_{str(uuid4())}/"
     await async_operator.create_dir(source_path)
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         await async_operator.copy(source_path, target_path)
 
 
@@ -65,7 +65,7 @@ async def test_async_copy_target_directory(service_name, 
operator, async_operato
     await async_operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}/"
     await async_operator.create_dir(target_path)
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         await async_operator.copy(source_path, target_path)
     await async_operator.delete(source_path)
     await async_operator.delete(target_path)
@@ -77,7 +77,7 @@ async def test_async_copy_self(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}"
     content = os.urandom(1024)
     await async_operator.write(source_path, content)
-    with pytest.raises(IsSameFileError) as e_info:
+    with pytest.raises(IsSameFile) as e_info:
         await async_operator.copy(source_path, source_path)
     await async_operator.delete(source_path)
 
diff --git a/bindings/python/tests/test_async_delete.py 
b/bindings/python/tests/test_async_delete.py
index ab1051b58..ff3d41d0c 100644
--- a/bindings/python/tests/test_async_delete.py
+++ b/bindings/python/tests/test_async_delete.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import NotFoundError
+from opendal.exceptions import NotFound
 
 
 @pytest.mark.asyncio
@@ -44,6 +44,6 @@ async def test_async_remove_all(service_name, operator, 
async_operator):
     await async_operator.remove_all(f"{parent}/x/")
     for path in excepted:
         if not path.endswith("/"):
-            with pytest.raises(NotFoundError) as e_info:
+            with pytest.raises(NotFound) as e_info:
                 await async_operator.read(f"{parent}/{path}")
     await async_operator.remove_all(f"{parent}/")
diff --git a/bindings/python/tests/test_async_rename.py 
b/bindings/python/tests/test_async_rename.py
index 33737600d..8c718fc52 100644
--- a/bindings/python/tests/test_async_rename.py
+++ b/bindings/python/tests/test_async_rename.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import IsADirectoryError, IsSameFileError, 
NotFoundError
+from opendal.exceptions import IsADirectory, IsSameFile, NotFound
 
 
 @pytest.mark.asyncio
@@ -31,7 +31,7 @@ async def test_async_rename_file(service_name, operator, 
async_operator):
     await async_operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}"
     await async_operator.rename(source_path, target_path)
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         await async_operator.read(source_path)
     assert await async_operator.read(target_path) == content
     await async_operator.delete(target_path)
@@ -43,7 +43,7 @@ async def test_async_rename_file(service_name, operator, 
async_operator):
 async def test_async_rename_non_exists_file(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}"
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         await async_operator.rename(source_path, target_path)
 
 
@@ -53,7 +53,7 @@ async def test_async_rename_directory(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}/"
     await async_operator.create_dir(source_path)
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         await async_operator.rename(source_path, target_path)
 
 
@@ -64,7 +64,7 @@ async def test_async_rename_file_to_directory(service_name, 
operator, async_oper
     content = os.urandom(1024)
     await async_operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}/"
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         await async_operator.rename(source_path, target_path)
     await async_operator.delete(source_path)
 
@@ -75,7 +75,7 @@ async def test_async_rename_self(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}"
     content = os.urandom(1024)
     await async_operator.write(source_path, content)
-    with pytest.raises(IsSameFileError) as e_info:
+    with pytest.raises(IsSameFile) as e_info:
         await async_operator.rename(source_path, source_path)
     await async_operator.delete(source_path)
 
@@ -88,7 +88,7 @@ async def test_async_rename_nested(service_name, operator, 
async_operator):
     await async_operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}/{str(uuid4())}/{str(uuid4())}"
     await async_operator.rename(source_path, target_path)
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         await async_operator.read(source_path)
     assert await async_operator.read(target_path) == content
     await async_operator.delete(target_path)
@@ -106,7 +106,7 @@ async def test_async_rename_overwrite(service_name, 
operator, async_operator):
     await async_operator.write(source_path, source_content)
     await async_operator.write(target_path, target_content)
     await async_operator.rename(source_path, target_path)
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         await async_operator.read(source_path)
     assert await async_operator.read(target_path) == source_content
     await async_operator.delete(target_path)
diff --git a/bindings/python/tests/test_read.py 
b/bindings/python/tests/test_read.py
index 9e6b40460..82eb1e9fd 100644
--- a/bindings/python/tests/test_read.py
+++ b/bindings/python/tests/test_read.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import IsADirectoryError, IsSameFileError, 
NotFoundError
+from opendal.exceptions import IsADirectory, IsSameFile, NotFound
 
 
 @pytest.mark.need_capability("read", "write", "delete")
@@ -135,12 +135,12 @@ async def test_async_read_stat(service_name, operator, 
async_operator):
 
 @pytest.mark.need_capability("read")
 def test_sync_read_not_exists(service_name, operator, async_operator):
-    with pytest.raises(NotFoundError):
+    with pytest.raises(NotFound):
         operator.read(str(uuid4()))
 
 
 @pytest.mark.asyncio
 @pytest.mark.need_capability("read")
 async def test_async_read_not_exists(service_name, operator, async_operator):
-    with pytest.raises(NotFoundError):
+    with pytest.raises(NotFound):
         await async_operator.read(str(uuid4()))
diff --git a/bindings/python/tests/test_sync_copy.py 
b/bindings/python/tests/test_sync_copy.py
index de2ad35c9..0c4f2bb54 100644
--- a/bindings/python/tests/test_sync_copy.py
+++ b/bindings/python/tests/test_sync_copy.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import IsADirectoryError, IsSameFileError, 
NotFoundError
+from opendal.exceptions import IsADirectory, IsSameFile, NotFound
 
 
 @pytest.mark.need_capability("read", "write", "copy")
@@ -41,7 +41,7 @@ def test_sync_copy(service_name, operator, async_operator):
 def test_sync_copy_non_exist(service_name, operator, async_operator):
     source_path = f"random_file_{str(uuid4())}"
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         operator.copy(source_path, target_path)
 
 
@@ -50,7 +50,7 @@ def test_sync_copy_source_directory(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}/"
     operator.create_dir(source_path)
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         operator.copy(source_path, target_path)
 
 
@@ -61,7 +61,7 @@ def test_sync_copy_target_directory(service_name, operator, 
async_operator):
     operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}/"
     operator.create_dir(target_path)
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         operator.copy(source_path, target_path)
     operator.delete(source_path)
     operator.delete(target_path)
@@ -72,7 +72,7 @@ def test_sync_copy_self(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}"
     content = os.urandom(1024)
     operator.write(source_path, content)
-    with pytest.raises(IsSameFileError) as e_info:
+    with pytest.raises(IsSameFile) as e_info:
         operator.copy(source_path, source_path)
     operator.delete(source_path)
 
diff --git a/bindings/python/tests/test_sync_delete.py 
b/bindings/python/tests/test_sync_delete.py
index d969e5587..7deb5c5f2 100644
--- a/bindings/python/tests/test_sync_delete.py
+++ b/bindings/python/tests/test_sync_delete.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import NotFoundError
+from opendal.exceptions import NotFound
 
 
 @pytest.mark.need_capability("read", "write", "delete", "list", "blocking")
@@ -43,6 +43,6 @@ def test_sync_remove_all(service_name, operator, 
async_operator):
     operator.remove_all(f"{parent}/x/")
     for path in excepted:
         if not path.endswith("/"):
-            with pytest.raises(NotFoundError) as e_info:
+            with pytest.raises(NotFound) as e_info:
                 operator.read(f"{parent}/{path}")
     operator.remove_all(f"{parent}/")
diff --git a/bindings/python/tests/test_sync_rename.py 
b/bindings/python/tests/test_sync_rename.py
index 12e0c73e4..3caced059 100644
--- a/bindings/python/tests/test_sync_rename.py
+++ b/bindings/python/tests/test_sync_rename.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import IsADirectoryError, IsSameFileError, 
NotFoundError
+from opendal.exceptions import IsADirectory, IsSameFile, NotFound
 
 
 @pytest.mark.need_capability("read", "write", "rename")
@@ -30,7 +30,7 @@ def test_sync_rename_file(service_name, operator, 
async_operator):
     operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}"
     operator.rename(source_path, target_path)
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         operator.read(source_path)
     assert operator.read(target_path) == content
     operator.delete(target_path)
@@ -41,7 +41,7 @@ def test_sync_rename_file(service_name, operator, 
async_operator):
 def test_sync_rename_non_exists_file(service_name, operator, async_operator):
     source_path = f"random_file_{str(uuid4())}"
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         operator.rename(source_path, target_path)
 
 
@@ -50,7 +50,7 @@ def test_sync_rename_directory(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}/"
     operator.create_dir(source_path)
     target_path = f"random_file_{str(uuid4())}"
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         operator.rename(source_path, target_path)
 
 
@@ -60,7 +60,7 @@ def test_sync_rename_file_to_directory(service_name, 
operator, async_operator):
     content = os.urandom(1024)
     operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}/"
-    with pytest.raises(IsADirectoryError) as e_info:
+    with pytest.raises(IsADirectory) as e_info:
         operator.rename(source_path, target_path)
     operator.delete(source_path)
 
@@ -70,7 +70,7 @@ def test_sync_rename_self(service_name, operator, 
async_operator):
     source_path = f"random_file_{str(uuid4())}"
     content = os.urandom(1024)
     operator.write(source_path, content)
-    with pytest.raises(IsSameFileError) as e_info:
+    with pytest.raises(IsSameFile) as e_info:
         operator.rename(source_path, source_path)
     operator.delete(source_path)
 
@@ -82,7 +82,7 @@ def test_sync_rename_nested(service_name, operator, 
async_operator):
     operator.write(source_path, content)
     target_path = f"random_file_{str(uuid4())}/{str(uuid4())}/{str(uuid4())}"
     operator.rename(source_path, target_path)
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         operator.read(source_path)
     assert operator.read(target_path) == content
     operator.delete(target_path)
@@ -99,7 +99,7 @@ def test_sync_rename_overwrite(service_name, operator, 
async_operator):
     operator.write(source_path, source_content)
     operator.write(target_path, target_content)
     operator.rename(source_path, target_path)
-    with pytest.raises(NotFoundError) as e_info:
+    with pytest.raises(NotFound) as e_info:
         operator.read(source_path)
     assert operator.read(target_path) == source_content
     operator.delete(target_path)
diff --git a/bindings/python/tests/test_write.py 
b/bindings/python/tests/test_write.py
index 8f7d1a0ed..e98c6e959 100644
--- a/bindings/python/tests/test_write.py
+++ b/bindings/python/tests/test_write.py
@@ -20,7 +20,7 @@ from random import randint
 from uuid import uuid4
 
 import pytest
-from opendal.exceptions import NotFoundError
+from opendal.exceptions import NotFound
 
 
 @pytest.mark.need_capability("write", "delete", "stat")
@@ -85,7 +85,7 @@ def test_sync_delete(service_name, operator, async_operator):
     size = len(content)
     operator.write(filename, content)
     operator.delete(filename)
-    with pytest.raises(NotFoundError):
+    with pytest.raises(NotFound):
         operator.stat(filename)
 
 
@@ -98,5 +98,5 @@ async def test_async_delete(service_name, operator, 
async_operator):
     size = len(content)
     await async_operator.write(filename, content)
     await async_operator.delete(filename)
-    with pytest.raises(NotFoundError):
+    with pytest.raises(NotFound):
         await operator.stat(filename)
diff --git a/bindings/python/upgrade.md b/bindings/python/upgrade.md
index de9041e61..58f9b3c80 100644
--- a/bindings/python/upgrade.md
+++ b/bindings/python/upgrade.md
@@ -27,3 +27,22 @@ Open a file for reading in async way:
 async with await op.open(filename, "rb") as r:
     content = await r.read()
 ```
+
+## Breaking change for Errors
+
+We remove the old error classes and provide a couple of Exception based class 
for the error handling.
+
+1. `opendal.Error` is removed, use `opendal.exceptions.Unknown` instead.
+2. `opendal.exceptions.Unexpected` is added.
+3. `opendal.exceptions.Unsupported` is added.
+4. `opendal.exceptions.ConfigInvalid` is added.
+5. `opendal.exceptions.NotFound` is added.
+6. `opendal.exceptions.PermissionDenied` is added.
+7. `opendal.exceptions.IsADirectory` is added.
+8. `opendal.exceptions.NotADirectory` is added.
+9. `opendal.exceptions.AlreadyExists` is added.
+10. `opendal.exceptions.IsSameFile` is added.
+11. `opendal.exceptions.ConditionNotMatch` is added.
+12. `opendal.exceptions.ContentTruncated` is added.
+13. `opendal.exceptions.ContentIncomplete` is added.
+14. `opendal.exceptions.InvalidInput` is added.

Reply via email to