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 33e410eb13 [#8796] feat(client-python): add partition name list 
response (#9024)
33e410eb13 is described below

commit 33e410eb138f6fba5ed1890340cab7d43440baaa
Author: George T. C. Lai <[email protected]>
AuthorDate: Wed Nov 12 03:47:31 2025 +0800

    [#8796] feat(client-python): add partition name list response (#9024)
    
    ### What changes were proposed in this pull request?
    
    We need to add class `PartitionNameListResponse` and the corresponding
    error handler.
    
    - `PartitionNameListResponse`
    - `ErrorHandlers.PartitionNameListResponse`
    
    ### Why are the changes needed?
    
    We need to enable table operations in Python client that requires
    implementation of class `PartitionNameListResponse` used in
    `RelationalTable`.
    
    Fix: #8796
    
    ### Does this PR introduce _any_ user-facing change?
    
    No
    
    ### How was this patch tested?
    
    Unit tests
    
    ---------
    
    Signed-off-by: George T. C. Lai <[email protected]>
---
 .../dto/responses/partition_name_list_response.py  |  49 +++++++++
 clients/client-python/gravitino/exceptions/base.py |  12 +++
 .../exceptions/handlers/partition_error_handler.py |  71 +++++++++++++
 .../tests/unittests/test_error_handler.py          | 113 ++++++++++++++++++---
 .../tests/unittests/test_responses.py              |  18 ++++
 5 files changed, 249 insertions(+), 14 deletions(-)

diff --git 
a/clients/client-python/gravitino/dto/responses/partition_name_list_response.py 
b/clients/client-python/gravitino/dto/responses/partition_name_list_response.py
new file mode 100644
index 0000000000..c8bd7a2bed
--- /dev/null
+++ 
b/clients/client-python/gravitino/dto/responses/partition_name_list_response.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 dataclasses import dataclass, field
+
+from dataclasses_json import config
+
+from gravitino.dto.responses.base_response import BaseResponse
+from gravitino.exceptions.base import IllegalArgumentException
+
+
+@dataclass
+class PartitionNameListResponse(BaseResponse):
+    """Represents a response containing a list of partition names."""
+
+    _partition_names: list[str] = field(metadata=config(field_name="names"))
+
+    def partition_names(self) -> list[str]:
+        """Get the list of partition names.
+
+        Returns:
+            list[str]: The list of partition names.
+        """
+        return self._partition_names
+
+    def validate(self) -> None:
+        """Validates the response data.
+
+        Raises:
+            IllegalArgumentException: if partition names are not set.
+        """
+
+        super().validate()
+        if self._partition_names is None:
+            raise IllegalArgumentException("partition names must not be null")
diff --git a/clients/client-python/gravitino/exceptions/base.py 
b/clients/client-python/gravitino/exceptions/base.py
index 0193ad78fe..62422082e2 100644
--- a/clients/client-python/gravitino/exceptions/base.py
+++ b/clients/client-python/gravitino/exceptions/base.py
@@ -191,3 +191,15 @@ class NoSuchJobException(NotFoundException):
 
 class ForbiddenException(GravitinoRuntimeException):
     """An exception thrown when a user is forbidden to perform an action."""
+
+
+class NoSuchTableException(NotFoundException):
+    """An exception thrown when a table with specified name is not existed."""
+
+
+class NoSuchPartitionException(NotFoundException):
+    """An exception thrown when a partition with specified name is not 
existed."""
+
+
+class PartitionAlreadyExistsException(AlreadyExistsException):
+    """An exception thrown when a partition with specified name already 
exists."""
diff --git 
a/clients/client-python/gravitino/exceptions/handlers/partition_error_handler.py
 
b/clients/client-python/gravitino/exceptions/handlers/partition_error_handler.py
new file mode 100644
index 0000000000..52fb36c3e7
--- /dev/null
+++ 
b/clients/client-python/gravitino/exceptions/handlers/partition_error_handler.py
@@ -0,0 +1,71 @@
+# 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.base import (
+    CatalogNotInUseException,
+    IllegalArgumentException,
+    MetalakeNotInUseException,
+    NoSuchPartitionException,
+    NoSuchSchemaException,
+    NoSuchTableException,
+    NotFoundException,
+    NotInUseException,
+    PartitionAlreadyExistsException,
+    UnsupportedOperationException,
+)
+from gravitino.exceptions.handlers.rest_error_handler import RestErrorHandler
+
+
+class PartitionErrorHandler(RestErrorHandler):
+    def handle(self, error_response: ErrorResponse):
+        error_message = error_response.format_error_message()
+        code = ErrorConstants(error_response.code())
+        exception_type = error_response.type()
+
+        if code is ErrorConstants.ILLEGAL_ARGUMENTS_CODE:
+            raise IllegalArgumentException(error_message)
+
+        if code is ErrorConstants.NOT_FOUND_CODE:
+            if exception_type == NoSuchSchemaException.__name__:
+                raise NoSuchSchemaException(error_message)
+            if exception_type == NoSuchTableException.__name__:
+                raise NoSuchTableException(error_message)
+            if exception_type == NoSuchPartitionException.__name__:
+                raise NoSuchPartitionException(error_message)
+            raise NotFoundException(error_message)
+
+        if code is ErrorConstants.ALREADY_EXISTS_CODE:
+            raise PartitionAlreadyExistsException(error_message)
+
+        if code is ErrorConstants.INTERNAL_ERROR_CODE:
+            raise RuntimeError(error_message)
+
+        if code is ErrorConstants.UNSUPPORTED_OPERATION_CODE:
+            raise UnsupportedOperationException(error_message)
+
+        if code is ErrorConstants.NOT_IN_USE_CODE:
+            if exception_type == CatalogNotInUseException.__name__:
+                raise CatalogNotInUseException(error_message)
+            if exception_type == MetalakeNotInUseException.__name__:
+                raise MetalakeNotInUseException(error_message)
+            raise NotInUseException(error_message)
+        super().handle(error_response)
+
+
+PARTITION_ERROR_HANDLER = PartitionErrorHandler()
diff --git a/clients/client-python/tests/unittests/test_error_handler.py 
b/clients/client-python/tests/unittests/test_error_handler.py
index 688e6c3480..291daa6d49 100644
--- a/clients/client-python/tests/unittests/test_error_handler.py
+++ b/clients/client-python/tests/unittests/test_error_handler.py
@@ -19,32 +19,40 @@ import unittest
 
 from gravitino.dto.responses.error_response import ErrorResponse
 from gravitino.exceptions.base import (
+    AlreadyExistsException,
+    CatalogAlreadyExistsException,
+    CatalogNotInUseException,
+    ConnectionFailedException,
+    IllegalArgumentException,
+    InternalError,
+    MetalakeAlreadyExistsException,
+    MetalakeNotInUseException,
+    NonEmptySchemaException,
     NoSuchCatalogException,
-    NoSuchSchemaException,
+    NoSuchCredentialException,
     NoSuchFilesetException,
     NoSuchMetalakeException,
-    MetalakeAlreadyExistsException,
-    InternalError,
-    RESTException,
-    NotFoundException,
-    IllegalArgumentException,
-    AlreadyExistsException,
+    NoSuchPartitionException,
+    NoSuchSchemaException,
+    NoSuchTableException,
     NotEmptyException,
-    NonEmptySchemaException,
+    NotFoundException,
+    NotInUseException,
+    PartitionAlreadyExistsException,
+    RESTException,
     SchemaAlreadyExistsException,
     UnsupportedOperationException,
-    ConnectionFailedException,
-    CatalogAlreadyExistsException,
-    NoSuchCredentialException,
 )
+from gravitino.exceptions.handlers.catalog_error_handler import 
CATALOG_ERROR_HANDLER
 from gravitino.exceptions.handlers.credential_error_handler import (
     CREDENTIAL_ERROR_HANDLER,
 )
-
-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.catalog_error_handler import 
CATALOG_ERROR_HANDLER
+from gravitino.exceptions.handlers.partition_error_handler import (
+    PARTITION_ERROR_HANDLER,
+)
+from gravitino.exceptions.handlers.rest_error_handler import REST_ERROR_HANDLER
 from gravitino.exceptions.handlers.schema_error_handler import 
SCHEMA_ERROR_HANDLER
 
 
@@ -255,3 +263,80 @@ class TestErrorHandler(unittest.TestCase):
             SCHEMA_ERROR_HANDLER.handle(
                 ErrorResponse.generate_error_response(Exception, "mock error")
             )
+
+    def test_partition_error_handler(self):
+        with self.assertRaises(IllegalArgumentException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    IllegalArgumentException, "mock error"
+                )
+            )
+
+        with self.assertRaises(NoSuchSchemaException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    NoSuchSchemaException, "mock error"
+                )
+            )
+
+        with self.assertRaises(NoSuchTableException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    NoSuchTableException, "mock error"
+                )
+            )
+
+        with self.assertRaises(NoSuchPartitionException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    NoSuchPartitionException, "mock error"
+                )
+            )
+
+        with self.assertRaises(NotFoundException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(NotFoundException, "mock 
error")
+            )
+
+        with self.assertRaises(PartitionAlreadyExistsException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    PartitionAlreadyExistsException, "mock error"
+                )
+            )
+
+        with self.assertRaises(RuntimeError):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(RuntimeError, "mock 
error")
+            )
+
+        with self.assertRaises(UnsupportedOperationException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    UnsupportedOperationException, "mock error"
+                )
+            )
+
+        with self.assertRaises(CatalogNotInUseException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    CatalogNotInUseException, "mock error"
+                )
+            )
+
+        with self.assertRaises(MetalakeNotInUseException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(
+                    MetalakeNotInUseException, "mock error"
+                )
+            )
+
+        with self.assertRaises(NotInUseException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(NotInUseException, "mock 
error")
+            )
+
+        with self.assertRaises(RESTException):
+            PARTITION_ERROR_HANDLER.handle(
+                ErrorResponse.generate_error_response(Exception, "mock error")
+            )
diff --git a/clients/client-python/tests/unittests/test_responses.py 
b/clients/client-python/tests/unittests/test_responses.py
index 3cc451ffc4..423a87acfa 100644
--- a/clients/client-python/tests/unittests/test_responses.py
+++ b/clients/client-python/tests/unittests/test_responses.py
@@ -23,6 +23,9 @@ from gravitino.dto.responses.model_response import 
ModelResponse
 from gravitino.dto.responses.model_version_list_response import 
ModelVersionListResponse
 from gravitino.dto.responses.model_version_response import ModelVersionResponse
 from gravitino.dto.responses.model_version_uri_response import 
ModelVersionUriResponse
+from gravitino.dto.responses.partition_name_list_response import (
+    PartitionNameListResponse,
+)
 from gravitino.exceptions.base import IllegalArgumentException
 
 
@@ -275,3 +278,18 @@ class TestResponses(unittest.TestCase):
             json_str_missing_1, infer_missing=True
         )
         self.assertRaises(IllegalArgumentException, resp_missing_1.validate)
+
+    def test_partition_name_list_response(self):
+        partition_names = [f"partition_{i}" for i in range(3)]
+        json_data = {"code": 0, "names": partition_names}
+        json_str = json.dumps(json_data)
+        resp: PartitionNameListResponse = 
PartitionNameListResponse.from_json(json_str)
+        self.assertListEqual(resp.partition_names(), partition_names)
+        resp.validate()
+
+    def test_partition_name_list_response_exception(self):
+        json_data = {"code": 0, "names": None}
+        json_str = json.dumps(json_data)
+        resp: PartitionNameListResponse = 
PartitionNameListResponse.from_json(json_str)
+        with self.assertRaises(IllegalArgumentException):
+            resp.validate()

Reply via email to