mchades commented on code in PR #12442:
URL: https://github.com/apache/gravitino/pull/12442#discussion_r3796640677


##########
clients/client-python/gravitino/dto/requests/tag_associate_request.py:
##########
@@ -27,45 +28,162 @@
 
 @dataclass_json
 @dataclass
-class TagsAssociateRequest(RESTRequest):
-    """
-    Represents a request to associate tags.
-    """
+class TagValuePairRequest(RESTRequest):
+    """Represents a tag assignment value pair request."""
+
+    _name: str = field(metadata=config(field_name="name"))
+    _value: Optional[str] = field(default=None, 
metadata=config(field_name="value"))
 
-    _tags_to_add: list[str] = field(metadata=config(field_name="tagsToAdd"))
-    _tags_to_remove: list[str] = 
field(metadata=config(field_name="tagsToRemove"))
+    @property
+    def name(self) -> str:
+        """Gets the tag name."""
+        return self._name
 
     @property
-    def tags_to_add(self) -> list[str]:
-        """
-        Gets the tags to add.
-        """
+    def value(self) -> Optional[str]:
+        """Gets the tag assignment value."""
+        return self._value
+
+    def validate(self) -> None:
+        """Validates the request."""
+        Precondition.check_argument(
+            StringUtils.is_not_blank(self._name),
+            "Tag name must not be null or empty",
+        )
+        if self._value is not None:
+            Precondition.check_argument(
+                self._value.strip() != "",
+                "Tag value must not be empty",
+            )
+            Precondition.check_argument(
+                len(self._value) <= 256,
+                "Tag value must not be longer than 256 characters",
+            )
+
+
+@dataclass_json
+@dataclass
+class TagNamesAssociateRequest(RESTRequest):
+    """Represents a request to associate tag names."""
+
+    _tags_to_add: Optional[list[str]] = field(
+        default=None, metadata=config(field_name="tagsToAdd")
+    )
+    _tags_to_remove: Optional[list[str]] = field(
+        default=None, metadata=config(field_name="tagsToRemove")
+    )
+
+    @property
+    def tags_to_add(self) -> Optional[list[str]]:
+        """Gets the tags to add."""
         return self._tags_to_add
 
     @property
-    def tags_to_remove(self) -> list[str]:
-        """
-        Gets the tags to remove.
-        """
+    def tags_to_remove(self) -> Optional[list[str]]:
+        """Gets the tags to remove."""
         return self._tags_to_remove
 
     def validate(self) -> None:
-        """
-        Validates the request.
-        """
+        """Validates the request."""
         Precondition.check_argument(
             self._tags_to_add is not None or self._tags_to_remove is not None,
             "tagsToAdd and tagsToRemove cannot both be null",
         )
 
-        self._validate_tags(self._tags_to_add, "tagsToAdd")
-        self._validate_tags(self._tags_to_remove, "tagsToRemove")
+        self._validate_tag_names(self._tags_to_add, "tagsToAdd")
+        self._validate_tag_names(self._tags_to_remove, "tagsToRemove")
 
-    def _validate_tags(self, tags: list[str] | None, field_name: str) -> None:
-        if tags is None:
+    def _validate_tag_names(
+        self, tag_names: Optional[list[str]], field_name: str
+    ) -> None:
+        if tag_names is None:
             return
 
         Precondition.check_argument(
-            all(StringUtils.is_not_blank(tag) for tag in tags),
+            all(StringUtils.is_not_blank(tag_name) for tag_name in tag_names),
             f"{field_name} must not contain null or empty tag names",
         )
+
+
+@dataclass_json
+@dataclass
+class TagsAssociateRequest(RESTRequest):

Review Comment:
   [P2] Preserve the legacy `TagsAssociateRequest` wire contract
   
   This reuses the public `TagsAssociateRequest` name for the V2 tag-value 
payload. At the merge-base, `TagsAssociateRequest(["tagA"], ["tagB"])` 
serializes to string arrays; at this head the same call serializes to `{name, 
value}` objects. Downstream code that constructs this DTO and posts it as 
`application/json` will therefore send the wrong schema to the V1 endpoint. 
Please keep `TagsAssociateRequest` as the name-array DTO and introduce a 
separately named `TagValuesAssociateRequest` for `assign_tags`, matching the 
Java request types.



##########
clients/client-python/gravitino/dto/tag_dto.py:
##########
@@ -33,6 +33,12 @@ class TagDTO(Tag):
     _name: str = field(metadata=config(field_name="name"))
     _comment: str = field(metadata=config(field_name="comment"))
     _properties: dict[str, str] = 
field(metadata=config(field_name="properties"))
+    _allowed_values: Optional[list[str]] = field(

Review Comment:
   [P2] Keep the existing positional constructor arguments stable
   
   Inserting these fields before `_audit` and `_inherited` changes the meaning 
of the existing `TagDTO(name, comment, properties, audit, inherited)` call. On 
this head, `audit` is bound to `_allowed_values`, `inherited` is bound to 
`_assignment_values`, `audit_info()`/`inherited()` return `None`, and `hash()` 
can raise `TypeError`. Please append the new fields after the existing 
positional fields, or provide a compatibility initializer; using keyword 
arguments in the builder would also prevent this from recurring.



##########
clients/client-python/gravitino/api/tag/supports_tags.py:
##########
@@ -61,6 +61,23 @@ def get_tag(self, name: str) -> Tag:
         """
         pass
 
+    @abstractmethod

Review Comment:
   [P2] Provide compatibility defaults for the new tag APIs
   
   Making this method abstract prevents every existing custom `SupportsTags` 
implementation from being instantiated after an upgrade, even when it only uses 
the legacy APIs. The new abstract `Tag.allowed_values()` and 
`Tag.assignment_values()` methods have the same problem. Please make the new 
APIs concrete compatibility defaults—`assign_tags()` can raise 
`UnsupportedOperationException`, while the two `Tag` accessors can return 
`None`—and override them in the built-in implementations. This also matches the 
default-method strategy used by the Java interfaces.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to