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 9d37f2d3e9 [#9883] improvement(python-client): Add TagUpdatesRequest 
and TagUpdateRequest (#9885)
9d37f2d3e9 is described below

commit 9d37f2d3e935c56b46e5c1dbe1b806cd19186d3d
Author: Lord of Abyss <[email protected]>
AuthorDate: Tue Mar 24 17:23:19 2026 +0800

    [#9883] improvement(python-client): Add TagUpdatesRequest and 
TagUpdateRequest (#9885)
    
    ### What changes were proposed in this pull request?
    
    Add `TagUpdatesRequest` and `TagUpdateRequest`
    
    ### Why are the changes needed?
    
    Fix: #9883
    
    ### Does this PR introduce _any_ user-facing change?
    
    no
    
    ### How was this patch tested?
    
    local unittest.
---
 .../gravitino/dto/requests/__init__.py             |   4 +
 .../gravitino/dto/requests/tag_update_request.py   | 173 +++++++++++++++++++++
 .../gravitino/dto/requests/tag_updates_request.py  |  56 +++++++
 .../dto/requests/test_tag_update_request.py        | 116 ++++++++++++++
 4 files changed, 349 insertions(+)

diff --git a/clients/client-python/gravitino/dto/requests/__init__.py 
b/clients/client-python/gravitino/dto/requests/__init__.py
index 440b9e645b..c8c8c9800e 100644
--- a/clients/client-python/gravitino/dto/requests/__init__.py
+++ b/clients/client-python/gravitino/dto/requests/__init__.py
@@ -16,7 +16,11 @@
 # under the License.
 
 from gravitino.dto.requests.tag_create_request import TagCreateRequest
+from gravitino.dto.requests.tag_update_request import TagUpdateRequest
+from gravitino.dto.requests.tag_updates_request import TagUpdatesRequest
 
 __all__ = [
     "TagCreateRequest",
+    "TagUpdatesRequest",
+    "TagUpdateRequest",
 ]
diff --git a/clients/client-python/gravitino/dto/requests/tag_update_request.py 
b/clients/client-python/gravitino/dto/requests/tag_update_request.py
new file mode 100644
index 0000000000..f99deb98d6
--- /dev/null
+++ b/clients/client-python/gravitino/dto/requests/tag_update_request.py
@@ -0,0 +1,173 @@
+# 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 __future__ import annotations
+
+from abc import ABC, abstractmethod
+from dataclasses import dataclass, field
+
+from dataclasses_json import config, dataclass_json
+
+from gravitino.api.tag.tag_change import TagChange
+from gravitino.rest.rest_message import RESTRequest
+from gravitino.utils.precondition import Precondition
+
+
+@dataclass
+@dataclass_json
+class TagUpdateRequestBase(RESTRequest, ABC):
+    _type: str = field(init=False, metadata=config(field_name="@type"))
+
+    @abstractmethod
+    def tag_change(self) -> TagChange:
+        """
+        Returns the tag change.
+
+        Raises:
+            NotImplementedError: if the method is not implemented.
+
+        Returns:
+            TagUpdateRequestBase: the tag change.
+        """
+        raise NotImplementedError()
+
+
+class TagUpdateRequest:
+    """Request to update a tag."""
+
+    @dataclass_json
+    @dataclass
+    class RenameTagRequest(TagUpdateRequestBase):
+        """The tag update request for renaming a tag."""
+
+        _new_name: str = field(init=True, 
metadata=config(field_name="newName"))
+
+        def __post_init__(self) -> None:
+            self._type = "rename"
+
+        def validate(self) -> None:
+            """
+            Validate the request.
+
+            Raises:
+                ValueError: If the request is invalid, this exception is 
thrown.
+            """
+            Precondition.check_string_not_empty(
+                self._new_name,
+                '"newName" must not be blank',
+            )
+
+        @property
+        def new_name(self) -> str:
+            return self._new_name
+
+        def tag_change(self) -> TagChange.RenameTag:
+            return TagChange.rename(self._new_name)
+
+    @dataclass_json
+    @dataclass
+    class UpdateTagCommentRequest(TagUpdateRequestBase):
+        """The tag update request for updating a tag comment."""
+
+        _new_comment: str = field(metadata=config(field_name="newComment"))
+
+        def __post_init__(self) -> None:
+            self._type = "updateComment"
+
+        def validate(self) -> None:
+            """
+            Validate the request.
+
+            Raises:
+                ValueError: If the request is invalid, this exception is 
thrown.
+            """
+            # always pass
+            pass
+
+        @property
+        def new_comment(self) -> str:
+            return self._new_comment
+
+        def tag_change(self) -> TagChange.UpdateTagComment:
+            return TagChange.UpdateTagComment(self._new_comment)
+
+    @dataclass_json
+    @dataclass
+    class SetTagPropertyRequest(TagUpdateRequestBase):
+        """The tag update request for setting a tag property."""
+
+        _property: str = field(metadata=config(field_name="property"))
+        _value: str = field(metadata=config(field_name="value"))
+
+        def __post_init__(self) -> None:
+            self._type = "setProperty"
+
+        def validate(self) -> None:
+            """
+            Validate the request.
+
+            Raises:
+                ValueError: If the request is invalid, this exception is 
thrown.
+            """
+            Precondition.check_string_not_empty(
+                self._property,
+                '"property" must not be blank',
+            )
+            Precondition.check_string_not_empty(
+                self._value,
+                '"value" must not be blank',
+            )
+
+        @property
+        def prop(self) -> str:
+            return self._property
+
+        @property
+        def value(self) -> str:
+            return self._value
+
+        def tag_change(self) -> TagChange.SetProperty:
+            return TagChange.set_property(self._property, self._value)
+
+    @dataclass_json
+    @dataclass
+    class RemoveTagPropertyRequest(TagUpdateRequestBase):
+        """The tag update request for removing a tag property."""
+
+        _property: str = field(metadata=config(field_name="property"))
+
+        def __post_init__(self) -> None:
+            self._type = "removeProperty"
+
+        def validate(self) -> None:
+            """
+            Validate the request.
+
+            Raises:
+                ValueError: If the request is invalid, this exception is 
thrown.
+            """
+            Precondition.check_string_not_empty(
+                self._property,
+                '"property" must not be blank',
+            )
+
+        @property
+        def prop(self) -> str:
+            return self._property
+
+        def tag_change(self) -> TagChange.RemoveProperty:
+            return TagChange.remove_property(self._property)
diff --git 
a/clients/client-python/gravitino/dto/requests/tag_updates_request.py 
b/clients/client-python/gravitino/dto/requests/tag_updates_request.py
new file mode 100644
index 0000000000..c4be42a561
--- /dev/null
+++ b/clients/client-python/gravitino/dto/requests/tag_updates_request.py
@@ -0,0 +1,56 @@
+# 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 __future__ import annotations
+
+from dataclasses import dataclass, field
+from typing import List
+
+from dataclasses_json import config
+
+from gravitino.dto.requests.tag_update_request import TagUpdateRequest
+from gravitino.rest.rest_message import RESTRequest
+
+
+@dataclass
+class TagUpdatesRequest(RESTRequest):
+    """Represents a request to update a tag."""
+
+    _updates: list[TagUpdateRequest] = field(
+        metadata=config(field_name="updates"), default_factory=list
+    )
+
+    def __init__(self, updates: List[TagUpdateRequest]) -> None:
+        """
+        Creates a new TagUpdatesRequest.
+
+        Args:
+            updates (List[TagUpdateRequest]): The updates to apply to the tag.
+        """
+        self._updates = updates
+
+    def validate(self) -> None:
+        """Validates the request.
+
+        Raises:
+            IllegalArgumentException If the request is invalid, this exception 
is thrown.
+        """
+        if not self._updates:
+            raise ValueError("updates must not be null")
+
+        for update_request in self._updates:
+            update_request.validate()
diff --git 
a/clients/client-python/tests/unittests/dto/requests/test_tag_update_request.py 
b/clients/client-python/tests/unittests/dto/requests/test_tag_update_request.py
new file mode 100644
index 0000000000..cc406c032f
--- /dev/null
+++ 
b/clients/client-python/tests/unittests/dto/requests/test_tag_update_request.py
@@ -0,0 +1,116 @@
+# 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 __future__ import annotations
+
+import json as _json
+import unittest
+
+from gravitino.api.tag.tag_change import TagChange
+from gravitino.dto.requests.tag_update_request import TagUpdateRequest
+
+
+class TestTagUpdateRequest(unittest.TestCase):
+    def test_tag_rename_tag_request_validate(self) -> None:
+        invalid_request = TagUpdateRequest.RenameTagRequest(_new_name="")
+        with self.assertRaises(ValueError):
+            invalid_request.validate()
+
+    def test_tag_rename_tag_request_serde(self) -> None:
+        request = TagUpdateRequest.RenameTagRequest(_new_name="new_name")
+        json_str = _json.dumps(
+            {
+                "@type": "rename",
+                "newName": "new_name",
+            }
+        )
+        self.assertEqual(json_str, request.to_json())
+
+        deserialized_request = 
TagUpdateRequest.RenameTagRequest.from_json(json_str)
+        self.assertEqual("new_name", deserialized_request.new_name)
+        self.assertIsInstance(deserialized_request.tag_change(), 
TagChange.RenameTag)
+
+    def test_update_tag_comment_request_serde(self) -> None:
+        request = TagUpdateRequest.UpdateTagCommentRequest("new_comment")
+        json_str = _json.dumps(
+            {
+                "@type": "updateComment",
+                "newComment": "new_comment",
+            }
+        )
+        self.assertEqual(json_str, request.to_json())
+
+        deserialized_request = 
TagUpdateRequest.UpdateTagCommentRequest.from_json(
+            json_str
+        )
+        self.assertEqual("new_comment", deserialized_request.new_comment)
+        self.assertIsInstance(
+            deserialized_request.tag_change(), TagChange.UpdateTagComment
+        )
+
+    def test_set_tag_property_request_validate(self) -> None:
+        invalid_request = TagUpdateRequest.SetTagPropertyRequest("key", "")
+        with self.assertRaises(ValueError):
+            invalid_request.validate()
+
+        invalid_request = TagUpdateRequest.SetTagPropertyRequest("", "value")
+        with self.assertRaises(ValueError):
+            invalid_request.validate()
+
+        invalid_request = TagUpdateRequest.SetTagPropertyRequest("", "")
+        with self.assertRaises(ValueError):
+            invalid_request.validate()
+
+    def test_set_tag_property_request_serde(self) -> None:
+        request = TagUpdateRequest.SetTagPropertyRequest("key", "value")
+        json_str = _json.dumps(
+            {
+                "@type": "setProperty",
+                "property": "key",
+                "value": "value",
+            }
+        )
+        self.assertEqual(json_str, request.to_json())
+
+        deserialized_request = 
TagUpdateRequest.SetTagPropertyRequest.from_json(
+            json_str
+        )
+        self.assertEqual("key", deserialized_request.prop)
+        self.assertEqual("value", deserialized_request.value)
+        self.assertIsInstance(deserialized_request.tag_change(), 
TagChange.SetProperty)
+
+    def test_remove_tag_property_request_validate(self) -> None:
+        invalid_request = TagUpdateRequest.RemoveTagPropertyRequest("")
+        with self.assertRaises(ValueError):
+            invalid_request.validate()
+
+    def test_remove_tag_property_request_serde(self) -> None:
+        request = TagUpdateRequest.RemoveTagPropertyRequest("key")
+        json_str = _json.dumps(
+            {
+                "@type": "removeProperty",
+                "property": "key",
+            }
+        )
+        self.assertEqual(json_str, request.to_json())
+
+        deserialized_request = 
TagUpdateRequest.RemoveTagPropertyRequest.from_json(
+            json_str
+        )
+        self.assertEqual("key", deserialized_request.prop)
+        self.assertIsInstance(
+            deserialized_request.tag_change(), TagChange.RemoveProperty
+        )

Reply via email to