This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch branch-0.6
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-0.6 by this push:
new fd8c7755d [#4228] improvement(client-python): Add Schema Error Handler
and related exceptions, test cases in client-python (#4381)
fd8c7755d is described below
commit fd8c7755d8d6e743ec9bba124d88c8730ab72cdb
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Aug 6 09:25:03 2024 +0800
[#4228] improvement(client-python): Add Schema Error Handler and related
exceptions, test cases in client-python (#4381)
### What changes were proposed in this pull request?
Add Schema Error Handler and related exceptions, test cases in
`client-python` based on `client-java`
### Why are the changes needed?
Fix: #4228
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
UTs and ITs are added and test with `./gradlew
client:client-python:test`
Co-authored-by: Jing-Jia Hung <[email protected]>
---
.../gravitino/catalog/base_schema_catalog.py | 10 ++++-
clients/client-python/gravitino/exceptions/base.py | 9 ++++
.../exceptions/handlers/schema_error_handler.py | 49 ++++++++++++++++++++++
.../client-python/tests/integration/test_schema.py | 14 +++++++
.../tests/unittests/test_error_handler.py | 48 +++++++++++++++++++++
5 files changed, 128 insertions(+), 2 deletions(-)
diff --git a/clients/client-python/gravitino/catalog/base_schema_catalog.py
b/clients/client-python/gravitino/catalog/base_schema_catalog.py
index 83d4ea229..2b146b27e 100644
--- a/clients/client-python/gravitino/catalog/base_schema_catalog.py
+++ b/clients/client-python/gravitino/catalog/base_schema_catalog.py
@@ -32,6 +32,7 @@ from gravitino.dto.requests.schema_updates_request import
SchemaUpdatesRequest
from gravitino.dto.responses.drop_response import DropResponse
from gravitino.dto.responses.entity_list_response import EntityListResponse
from gravitino.dto.responses.schema_response import SchemaResponse
+from gravitino.exceptions.handlers.schema_error_handler import
SCHEMA_ERROR_HANDLER
from gravitino.namespace import Namespace
from gravitino.utils import HTTPClient
from gravitino.rest.rest_utils import encode_string
@@ -89,7 +90,8 @@ class BaseSchemaCatalog(CatalogDTO, SupportsSchemas):
A list of schema names under the given catalog namespace.
"""
resp = self.rest_client.get(
-
BaseSchemaCatalog.format_schema_request_path(self._schema_namespace())
+
BaseSchemaCatalog.format_schema_request_path(self._schema_namespace()),
+ error_handler=SCHEMA_ERROR_HANDLER,
)
entity_list_response = EntityListResponse.from_json(
resp.body, infer_missing=True
@@ -124,6 +126,7 @@ class BaseSchemaCatalog(CatalogDTO, SupportsSchemas):
resp = self.rest_client.post(
BaseSchemaCatalog.format_schema_request_path(self._schema_namespace()),
json=req,
+ error_handler=SCHEMA_ERROR_HANDLER,
)
schema_response = SchemaResponse.from_json(resp.body,
infer_missing=True)
schema_response.validate()
@@ -145,7 +148,8 @@ class BaseSchemaCatalog(CatalogDTO, SupportsSchemas):
resp = self.rest_client.get(
BaseSchemaCatalog.format_schema_request_path(self._schema_namespace())
+ "/"
- + encode_string(schema_name)
+ + encode_string(schema_name),
+ error_handler=SCHEMA_ERROR_HANDLER,
)
schema_response = SchemaResponse.from_json(resp.body,
infer_missing=True)
schema_response.validate()
@@ -175,6 +179,7 @@ class BaseSchemaCatalog(CatalogDTO, SupportsSchemas):
+ "/"
+ encode_string(schema_name),
updates_request,
+ error_handler=SCHEMA_ERROR_HANDLER,
)
schema_response = SchemaResponse.from_json(resp.body,
infer_missing=True)
schema_response.validate()
@@ -200,6 +205,7 @@ class BaseSchemaCatalog(CatalogDTO, SupportsSchemas):
+ "/"
+ encode_string(schema_name),
params=params,
+ error_handler=SCHEMA_ERROR_HANDLER,
)
drop_resp = DropResponse.from_json(resp.body, infer_missing=True)
drop_resp.validate()
diff --git a/clients/client-python/gravitino/exceptions/base.py
b/clients/client-python/gravitino/exceptions/base.py
index 7700e151a..59b2e05a4 100644
--- a/clients/client-python/gravitino/exceptions/base.py
+++ b/clients/client-python/gravitino/exceptions/base.py
@@ -67,6 +67,10 @@ class NoSuchMetalakeException(NotFoundException):
"""An exception thrown when a metalake is not found."""
+class NoSuchCatalogException(NotFoundException):
+ """An exception thrown when a catalog is not found."""
+
+
class AlreadyExistsException(GravitinoRuntimeException):
"""Base exception thrown when an entity or resource already exists."""
@@ -75,6 +79,10 @@ class MetalakeAlreadyExistsException(AlreadyExistsException):
"""An exception thrown when a metalake already exists."""
+class SchemaAlreadyExistsException(AlreadyExistsException):
+ """An exception thrown when a schema already exists."""
+
+
class NotEmptyException(GravitinoRuntimeException):
"""Base class for all exceptions thrown when a resource is not empty."""
@@ -93,3 +101,4 @@ class UnauthorizedException(GravitinoRuntimeException):
class BadRequestException(GravitinoRuntimeException):
"""An exception thrown when the request is invalid."""
+
diff --git
a/clients/client-python/gravitino/exceptions/handlers/schema_error_handler.py
b/clients/client-python/gravitino/exceptions/handlers/schema_error_handler.py
new file mode 100644
index 000000000..647466873
--- /dev/null
+++
b/clients/client-python/gravitino/exceptions/handlers/schema_error_handler.py
@@ -0,0 +1,49 @@
+"""
+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 (
+ NoSuchCatalogException,
+ NoSuchSchemaException,
+ SchemaAlreadyExistsException,
+)
+
+
+class SchemaErrorHandler(RestErrorHandler):
+
+ def handle(self, error_response: ErrorResponse):
+
+ error_message = error_response.format_error_message()
+ code = error_response.code()
+ exception_type = error_response.type()
+
+ if code == ErrorConstants.NOT_FOUND_CODE:
+ if exception_type == NoSuchCatalogException.__name__:
+ raise NoSuchCatalogException(error_message)
+ if exception_type == NoSuchSchemaException.__name__:
+ raise NoSuchSchemaException(error_message)
+ if code == ErrorConstants.ALREADY_EXISTS_CODE:
+ raise SchemaAlreadyExistsException(error_message)
+
+ super().handle(error_response)
+
+
+SCHEMA_ERROR_HANDLER = SchemaErrorHandler()
diff --git a/clients/client-python/tests/integration/test_schema.py
b/clients/client-python/tests/integration/test_schema.py
index eb250f64a..7be2406fd 100644
--- a/clients/client-python/tests/integration/test_schema.py
+++ b/clients/client-python/tests/integration/test_schema.py
@@ -29,6 +29,10 @@ from gravitino import (
SchemaChange,
Schema,
)
+from gravitino.exceptions.base import (
+ NoSuchSchemaException,
+ SchemaAlreadyExistsException,
+)
from tests.integration.integration_test_env import IntegrationTestEnv
@@ -133,6 +137,11 @@ class TestSchema(IntegrationTestEnv):
self.assertEqual(schema.properties(), self.schema_properties)
self.assertEqual(schema.audit_info().creator(), "anonymous")
+ def test_failed_create_schema(self):
+ self.create_schema()
+ with self.assertRaises(SchemaAlreadyExistsException):
+ _ = self.create_schema()
+
def test_drop_schema(self):
self.create_schema()
catalog = self.gravitino_client.load_catalog(name=self.catalog_name)
@@ -158,6 +167,11 @@ class TestSchema(IntegrationTestEnv):
self.assertEqual(schema.properties(), self.schema_properties)
self.assertEqual(schema.audit_info().creator(), "anonymous")
+ def test_failed_load_schema(self):
+ catalog = self.gravitino_client.load_catalog(name=self.catalog_name)
+ with self.assertRaises(NoSuchSchemaException):
+ _ = catalog.as_schemas().load_schema(schema_name=self.schema_name)
+
def test_alter_schema(self):
self.create_schema()
schema_properties_new_value = self.schema_properties_value2 + "_new"
diff --git a/clients/client-python/tests/unittests/test_error_handler.py
b/clients/client-python/tests/unittests/test_error_handler.py
index e5547493c..fd92af495 100644
--- a/clients/client-python/tests/unittests/test_error_handler.py
+++ b/clients/client-python/tests/unittests/test_error_handler.py
@@ -21,6 +21,7 @@ import unittest
from gravitino.dto.responses.error_response import ErrorResponse
from gravitino.exceptions.base import (
+ NoSuchCatalogException,
NoSuchSchemaException,
NoSuchFilesetException,
NoSuchMetalakeException,
@@ -31,12 +32,14 @@ from gravitino.exceptions.base import (
IllegalArgumentException,
AlreadyExistsException,
NotEmptyException,
+ SchemaAlreadyExistsException,
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
+from gravitino.exceptions.handlers.schema_error_handler import
SCHEMA_ERROR_HANDLER
class TestErrorHandler(unittest.TestCase):
@@ -147,3 +150,48 @@ class TestErrorHandler(unittest.TestCase):
METALAKE_ERROR_HANDLER.handle(
ErrorResponse.generate_error_response(Exception, "mock error")
)
+
+ def test_schema_error_handler(self):
+
+ with self.assertRaises(NoSuchCatalogException):
+ SCHEMA_ERROR_HANDLER.handle(
+ ErrorResponse.generate_error_response(
+ NoSuchCatalogException, "mock error"
+ )
+ )
+
+ with self.assertRaises(NoSuchSchemaException):
+ SCHEMA_ERROR_HANDLER.handle(
+ ErrorResponse.generate_error_response(
+ NoSuchSchemaException, "mock error"
+ )
+ )
+
+ with self.assertRaises(SchemaAlreadyExistsException):
+ SCHEMA_ERROR_HANDLER.handle(
+ ErrorResponse.generate_error_response(
+ SchemaAlreadyExistsException, "mock error"
+ )
+ )
+
+ with self.assertRaises(NotEmptyException):
+ SCHEMA_ERROR_HANDLER.handle(
+ ErrorResponse.generate_error_response(NotEmptyException, "mock
error")
+ )
+
+ with self.assertRaises(UnsupportedOperationException):
+ SCHEMA_ERROR_HANDLER.handle(
+ ErrorResponse.generate_error_response(
+ UnsupportedOperationException, "mock error"
+ )
+ )
+
+ with self.assertRaises(InternalError):
+ SCHEMA_ERROR_HANDLER.handle(
+ ErrorResponse.generate_error_response(InternalError, "mock
error")
+ )
+
+ with self.assertRaises(RESTException):
+ SCHEMA_ERROR_HANDLER.handle(
+ ErrorResponse.generate_error_response(Exception, "mock error")
+ )