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")
+ )