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

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new d2cfbf78a [#4226] Improvement(python-client): Add Metalake Error 
Handler and related exceptions, test cases in client-python (#4271)
d2cfbf78a is described below

commit d2cfbf78a3c97aff9528bc04e049bc47b70a4149
Author: Jing-Jia Hung <[email protected]>
AuthorDate: Tue Jul 30 17:59:17 2024 +0800

    [#4226] Improvement(python-client): Add Metalake Error Handler and related 
exceptions, test cases in client-python (#4271)
    
    ### What changes were proposed in this pull request?
    
    - Add Metalake Error Handler and related exceptions, UT and IT in
    `client-python` based on `client-java `
    - Align exception naming with `client-java `
    
    ### Why are the changes needed?
    
    Fix: #4226
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    UT and IT added.
---
 .../gravitino/client/gravitino_admin_client.py     | 18 +++++++--
 .../gravitino/client/gravitino_client_base.py      |  7 +++-
 clients/client-python/gravitino/constants/error.py |  4 +-
 clients/client-python/gravitino/exceptions/base.py |  6 ++-
 .../exceptions/handlers/metalake_error_handler.py  | 44 ++++++++++++++++++++++
 clients/client-python/setup.py                     | 17 ++++-----
 .../tests/integration/test_metalake.py             | 13 +++++++
 .../tests/unittests/test_error_handler.py          | 35 +++++++++++++++--
 8 files changed, 123 insertions(+), 21 deletions(-)

diff --git a/clients/client-python/gravitino/client/gravitino_admin_client.py 
b/clients/client-python/gravitino/client/gravitino_admin_client.py
index 1bb8ce8e9..5512b9778 100644
--- a/clients/client-python/gravitino/client/gravitino_admin_client.py
+++ b/clients/client-python/gravitino/client/gravitino_admin_client.py
@@ -29,6 +29,7 @@ from gravitino.dto.responses.drop_response import DropResponse
 from gravitino.dto.responses.metalake_list_response import MetalakeListResponse
 from gravitino.dto.responses.metalake_response import MetalakeResponse
 from gravitino.api.metalake_change import MetalakeChange
+from gravitino.exceptions.handlers.metalake_error_handler import 
METALAKE_ERROR_HANDLER
 
 logger = logging.getLogger(__name__)
 
@@ -46,7 +47,9 @@ class GravitinoAdminClient(GravitinoClientBase):
         Returns:
             An array of GravitinoMetalake objects representing the Metalakes.
         """
-        resp = self._rest_client.get(self.API_METALAKES_LIST_PATH)
+        resp = self._rest_client.get(
+            self.API_METALAKES_LIST_PATH, error_handler=METALAKE_ERROR_HANDLER
+        )
         metalake_list_resp = MetalakeListResponse.from_json(
             resp.body, infer_missing=True
         )
@@ -74,7 +77,9 @@ class GravitinoAdminClient(GravitinoClientBase):
         req = MetalakeCreateRequest(name, comment, properties)
         req.validate()
 
-        resp = self._rest_client.post(self.API_METALAKES_LIST_PATH, req)
+        resp = self._rest_client.post(
+            self.API_METALAKES_LIST_PATH, req, 
error_handler=METALAKE_ERROR_HANDLER
+        )
         metalake_response = MetalakeResponse.from_json(resp.body, 
infer_missing=True)
         metalake_response.validate()
         metalake = metalake_response.metalake()
@@ -99,7 +104,9 @@ class GravitinoAdminClient(GravitinoClientBase):
         updates_request.validate()
 
         resp = self._rest_client.put(
-            self.API_METALAKES_IDENTIFIER_PATH + name, updates_request
+            self.API_METALAKES_IDENTIFIER_PATH + name,
+            updates_request,
+            error_handler=METALAKE_ERROR_HANDLER,
         )
         metalake_response = MetalakeResponse.from_json(resp.body, 
infer_missing=True)
         metalake_response.validate()
@@ -117,7 +124,10 @@ class GravitinoAdminClient(GravitinoClientBase):
             True if the Metalake was successfully dropped, false otherwise.
         """
         try:
-            resp = self._rest_client.delete(self.API_METALAKES_IDENTIFIER_PATH 
+ name)
+            resp = self._rest_client.delete(
+                self.API_METALAKES_IDENTIFIER_PATH + name,
+                error_handler=METALAKE_ERROR_HANDLER,
+            )
             drop_response = DropResponse.from_json(resp.body, 
infer_missing=True)
 
             return drop_response.dropped()
diff --git a/clients/client-python/gravitino/client/gravitino_client_base.py 
b/clients/client-python/gravitino/client/gravitino_client_base.py
index 442b77dee..4f3d19c98 100644
--- a/clients/client-python/gravitino/client/gravitino_client_base.py
+++ b/clients/client-python/gravitino/client/gravitino_client_base.py
@@ -27,6 +27,8 @@ from gravitino.client.gravitino_version import 
GravitinoVersion
 from gravitino.dto.version_dto import VersionDTO
 from gravitino.dto.responses.metalake_response import MetalakeResponse
 from gravitino.dto.responses.version_response import VersionResponse
+from gravitino.exceptions.handlers.metalake_error_handler import 
METALAKE_ERROR_HANDLER
+from gravitino.exceptions.handlers.rest_error_handler import REST_ERROR_HANDLER
 from gravitino.utils import HTTPClient
 from gravitino.exceptions.base import GravitinoRuntimeException
 from gravitino.constants.version import VERSION_INI, Version
@@ -75,7 +77,8 @@ class GravitinoClientBase:
 
         self.check_metalake_name(name)
         response = self._rest_client.get(
-            GravitinoClientBase.API_METALAKES_IDENTIFIER_PATH + name
+            GravitinoClientBase.API_METALAKES_IDENTIFIER_PATH + name,
+            error_handler=METALAKE_ERROR_HANDLER,
         )
         metalake_response = MetalakeResponse.from_json(
             response.body, infer_missing=True
@@ -126,7 +129,7 @@ class GravitinoClientBase:
         Returns:
             A GravitinoVersion instance representing the version of the 
Gravitino API.
         """
-        resp = self._rest_client.get("api/version")
+        resp = self._rest_client.get("api/version", 
error_handler=REST_ERROR_HANDLER)
         version_response = VersionResponse.from_json(resp.body, 
infer_missing=True)
         version_response.validate()
 
diff --git a/clients/client-python/gravitino/constants/error.py 
b/clients/client-python/gravitino/constants/error.py
index ed2424200..e4b0ab61e 100644
--- a/clients/client-python/gravitino/constants/error.py
+++ b/clients/client-python/gravitino/constants/error.py
@@ -24,7 +24,7 @@ from gravitino.exceptions.base import (
     IllegalArgumentException,
     NotFoundException,
     InternalError,
-    AlreadyExistException,
+    AlreadyExistsException,
     NotEmptyException,
     UnsupportedOperationException,
 )
@@ -63,7 +63,7 @@ EXCEPTION_MAPPING = {
     IllegalArgumentException: ErrorConstants.ILLEGAL_ARGUMENTS_CODE,
     InternalError: ErrorConstants.INTERNAL_ERROR_CODE,
     NotFoundException: ErrorConstants.NOT_FOUND_CODE,
-    AlreadyExistException: ErrorConstants.ALREADY_EXISTS_CODE,
+    AlreadyExistsException: ErrorConstants.ALREADY_EXISTS_CODE,
     NotEmptyException: ErrorConstants.NON_EMPTY_CODE,
     UnsupportedOperationException: ErrorConstants.UNSUPPORTED_OPERATION_CODE,
 }
diff --git a/clients/client-python/gravitino/exceptions/base.py 
b/clients/client-python/gravitino/exceptions/base.py
index c9c46c575..418304d7d 100644
--- a/clients/client-python/gravitino/exceptions/base.py
+++ b/clients/client-python/gravitino/exceptions/base.py
@@ -67,10 +67,14 @@ class NoSuchMetalakeException(NotFoundException):
     """An exception thrown when a metalake is not found."""
 
 
-class AlreadyExistException(GravitinoRuntimeException):
+class AlreadyExistsException(GravitinoRuntimeException):
     """Base exception thrown when an entity or resource already exists."""
 
 
+class MetalakeAlreadyExistsException(AlreadyExistsException):
+    """An exception thrown when a metalake already exists."""
+
+
 class NotEmptyException(GravitinoRuntimeException):
     """Base class for all exceptions thrown when a resource is not empty."""
 
diff --git 
a/clients/client-python/gravitino/exceptions/handlers/metalake_error_handler.py 
b/clients/client-python/gravitino/exceptions/handlers/metalake_error_handler.py
new file mode 100644
index 000000000..476b6f603
--- /dev/null
+++ 
b/clients/client-python/gravitino/exceptions/handlers/metalake_error_handler.py
@@ -0,0 +1,44 @@
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+from gravitino.constants.error import ErrorConstants
+from gravitino.dto.responses.error_response import ErrorResponse
+from gravitino.exceptions.handlers.rest_error_handler import RestErrorHandler
+from gravitino.exceptions.base import (
+    NoSuchMetalakeException,
+    MetalakeAlreadyExistsException,
+)
+
+
+class MetalakeErrorHandler(RestErrorHandler):
+
+    def handle(self, error_response: ErrorResponse):
+
+        error_message = error_response.format_error_message()
+        code = error_response.code()
+
+        if code == ErrorConstants.NOT_FOUND_CODE:
+            raise NoSuchMetalakeException(error_message)
+        if code == ErrorConstants.ALREADY_EXISTS_CODE:
+            raise MetalakeAlreadyExistsException(error_message)
+
+        super().handle(error_response)
+
+
+METALAKE_ERROR_HANDLER = MetalakeErrorHandler()
diff --git a/clients/client-python/setup.py b/clients/client-python/setup.py
index 02790f1e3..3e7c4d510 100644
--- a/clients/client-python/setup.py
+++ b/clients/client-python/setup.py
@@ -17,7 +17,6 @@ specific language governing permissions and limitations
 under the License.
 """
 
-
 from setuptools import find_packages, setup
 
 
@@ -39,14 +38,14 @@ setup(
     python_requires=">=3.8",
     packages=find_packages(exclude=["tests*", "scripts*"]),
     classifiers=[
-        'Development Status :: 3 - Alpha',
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: Apache Software License',
-        'Programming Language :: Python :: 3.8',
-        'Programming Language :: Python :: 3.9',
-        'Programming Language :: Python :: 3.10',
-        'Programming Language :: Python :: 3.11',
-        'Programming Language :: Python :: 3.12',
+        "Development Status :: 3 - Alpha",
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: Apache Software License",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
+        "Programming Language :: Python :: 3.12",
     ],
     install_requires=open("requirements.txt").read(),
     extras_require={
diff --git a/clients/client-python/tests/integration/test_metalake.py 
b/clients/client-python/tests/integration/test_metalake.py
index cd588578c..76e56227a 100644
--- a/clients/client-python/tests/integration/test_metalake.py
+++ b/clients/client-python/tests/integration/test_metalake.py
@@ -23,6 +23,10 @@ from typing import Dict, List
 from gravitino import GravitinoAdminClient, GravitinoMetalake, MetalakeChange
 from gravitino.dto.dto_converters import DTOConverters
 from gravitino.dto.requests.metalake_updates_request import 
MetalakeUpdatesRequest
+from gravitino.exceptions.base import (
+    NoSuchMetalakeException,
+    MetalakeAlreadyExistsException,
+)
 from tests.integration.integration_test_env import IntegrationTestEnv
 
 logger = logging.getLogger(__name__)
@@ -75,6 +79,11 @@ class TestMetalake(IntegrationTestEnv):
             self.metalake_properties,
         )
 
+    def test_failed_create_metalake(self):
+        self.create_metalake(self.metalake_name)
+        with self.assertRaises(MetalakeAlreadyExistsException):
+            _ = self.create_metalake(self.metalake_name)
+
     def test_alter_metalake(self):
         self.create_metalake(self.metalake_name)
 
@@ -139,3 +148,7 @@ class TestMetalake(IntegrationTestEnv):
         self.assertEqual(metalake.comment(), self.metalake_comment)
         self.assertEqual(metalake.properties(), self.metalake_properties)
         self.assertEqual(metalake.audit_info().creator(), "anonymous")
+
+    def test_failed_load_metalakes(self):
+        with self.assertRaises(NoSuchMetalakeException):
+            _ = self.gravitino_admin_client.load_metalake(self.metalake_name)
diff --git a/clients/client-python/tests/unittests/test_error_handler.py 
b/clients/client-python/tests/unittests/test_error_handler.py
index 2600beac9..e5547493c 100644
--- a/clients/client-python/tests/unittests/test_error_handler.py
+++ b/clients/client-python/tests/unittests/test_error_handler.py
@@ -23,17 +23,20 @@ from gravitino.dto.responses.error_response import 
ErrorResponse
 from gravitino.exceptions.base import (
     NoSuchSchemaException,
     NoSuchFilesetException,
+    NoSuchMetalakeException,
+    MetalakeAlreadyExistsException,
     InternalError,
     RESTException,
     NotFoundException,
     IllegalArgumentException,
-    AlreadyExistException,
+    AlreadyExistsException,
     NotEmptyException,
     UnsupportedOperationException,
 )
 
 from gravitino.exceptions.handlers.rest_error_handler import REST_ERROR_HANDLER
 from gravitino.exceptions.handlers.fileset_error_handler import 
FILESET_ERROR_HANDLER
+from gravitino.exceptions.handlers.metalake_error_handler import 
METALAKE_ERROR_HANDLER
 
 
 class TestErrorHandler(unittest.TestCase):
@@ -69,10 +72,10 @@ class TestErrorHandler(unittest.TestCase):
                 )
             )
 
-        with self.assertRaises(AlreadyExistException):
+        with self.assertRaises(AlreadyExistsException):
             REST_ERROR_HANDLER.handle(
                 ErrorResponse.generate_error_response(
-                    AlreadyExistException, "mock error"
+                    AlreadyExistsException, "mock error"
                 )
             )
 
@@ -118,3 +121,29 @@ class TestErrorHandler(unittest.TestCase):
             FILESET_ERROR_HANDLER.handle(
                 ErrorResponse.generate_error_response(Exception, "mock error")
             )
+
+    def test_metalake_error_handler(self):
+
+        with self.assertRaises(NoSuchMetalakeException):
+            METALAKE_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    NoSuchMetalakeException, "mock error"
+                )
+            )
+
+        with self.assertRaises(MetalakeAlreadyExistsException):
+            METALAKE_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    MetalakeAlreadyExistsException, "mock error"
+                )
+            )
+
+        with self.assertRaises(InternalError):
+            METALAKE_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(InternalError, "mock 
error")
+            )
+
+        with self.assertRaises(RESTException):
+            METALAKE_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(Exception, "mock error")
+            )

Reply via email to