This is an automated email from the ASF dual-hosted git repository. liuxun 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 2668aaf2bd [#5202] feat(client-python): Support Column and its default value part1 (#6542) 2668aaf2bd is described below commit 2668aaf2bd01120318fb80f8dd010364cd330d0d Author: George T. C. Lai <tsungchih...@gmail.com> AuthorDate: Fri Mar 28 15:00:44 2025 +0800 [#5202] feat(client-python): Support Column and its default value part1 (#6542) ### What changes were proposed in this pull request? This is first part (totally 4 planned) of implementation to the following classes from Java to support Column and its default value, including: - SupportsTags.java - Tag.java - NoSuchTagException.java - TagAlreadyExistsException.java ### Why are the changes needed? We need to support Column and its default value in python client. #5202 ### Does this PR introduce _any_ user-facing change? No ### How was this patch tested? Unit tests --------- Signed-off-by: George T. C. Lai <tsungchih...@gmail.com> --- .../client-python/gravitino/api/tag/__init__.py | 16 +++ .../gravitino/api/tag/supports_tags.py | 87 +++++++++++++++ clients/client-python/gravitino/api/tag/tag.py | 118 +++++++++++++++++++++ clients/client-python/gravitino/exceptions/base.py | 8 ++ 4 files changed, 229 insertions(+) diff --git a/clients/client-python/gravitino/api/tag/__init__.py b/clients/client-python/gravitino/api/tag/__init__.py new file mode 100644 index 0000000000..13a83393a9 --- /dev/null +++ b/clients/client-python/gravitino/api/tag/__init__.py @@ -0,0 +1,16 @@ +# 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. diff --git a/clients/client-python/gravitino/api/tag/supports_tags.py b/clients/client-python/gravitino/api/tag/supports_tags.py new file mode 100644 index 0000000000..89b405f890 --- /dev/null +++ b/clients/client-python/gravitino/api/tag/supports_tags.py @@ -0,0 +1,87 @@ +# 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 abc import ABC, abstractmethod +from typing import List + +from gravitino.api.tag.tag import Tag + + +class SupportsTags(ABC): + """Interface for supporting getting or associate tags to objects. + + This interface will be mixed with metadata objects to provide tag operations. + """ + + @abstractmethod + def list_tags(self) -> List[str]: + """List all the tag names for the specific object. + + Returns: + List[str]: The list of tag names. + """ + pass + + @abstractmethod + def list_tags_info(self) -> List[Tag]: + """List all the tags with details for the specific object. + + Returns: + List[Tag]: The list of tags. + """ + pass + + @abstractmethod + def get_tag(self, name: str) -> Tag: + """Get a tag by its name for the specific object. + + Args: + name (str): The name of the tag. + + Raises: + NoSuchTagException: If the tag does not associate with the object. + + Returns: + Tag: The tag. + """ + pass + + @abstractmethod + def associate_tags( + self, tags_to_add: List[str], tags_to_remove: List[str] + ) -> List[str]: + """Associate tags to the specific object. + + The `tags_to_add` will be added to the object, and the `tags_to_remove` will be removed from the object. + + Note that: + 1. Adding or removing tags that are not existed will be ignored. + 2. If the same name tag is in both `tags_to_add` and `tags_to_remove`, it will be ignored. + 3. If the tag is already associated with the object, it will raise `TagAlreadyAssociatedException`. + + Args: + tags_to_add (List[str]): The arrays of tag name to be added to the object. + tags_to_remove (List[str]): The array of tag name to be removed from the object. + + Raises: + TagAlreadyAssociatedException: If the tag is already associated with the object. + + Returns: + List[str]: The array of tag names that are associated with the object. + """ + pass diff --git a/clients/client-python/gravitino/api/tag/tag.py b/clients/client-python/gravitino/api/tag/tag.py new file mode 100644 index 0000000000..6e2a510461 --- /dev/null +++ b/clients/client-python/gravitino/api/tag/tag.py @@ -0,0 +1,118 @@ +# 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 abc import ABC, abstractmethod +from typing import ClassVar, Dict, List, Optional + +from gravitino.api.auditable import Auditable +from gravitino.api.metadata_object import MetadataObject +from gravitino.exceptions.base import UnsupportedOperationException + + +class AssociatedObjects(ABC): + """The interface of the associated objects of the tag.""" + + @abstractmethod + def count(self) -> int: + """Get the number of associated objects. + + Returns: + int: The number of associated objects. + """ + objects = self.objects() + return 0 if objects is None else len(objects) + + @abstractmethod + def objects(self) -> Optional[List[MetadataObject]]: + """Get the associated objects. + + Returns: + Optional[List[MetadataObject]]: The list of objects that are associated with this tag.. + """ + pass + + +class Tag(Auditable): + """The interface of a tag. + + A tag is a label that can be attached to a catalog, schema, table, fileset, topic, + or column. It can be used to categorize, classify, or annotate these objects. + """ + + PROPERTY_COLOR: ClassVar[str] = "color" + """ + A reserved property to specify the color of the tag. The color is a string of hex code that + represents the color of the tag. The color is used to visually distinguish the tag from other + tags. + """ + + @abstractmethod + def name(self) -> str: + """Get the name of the tag. + + Returns: + str: The name of the tag. + """ + pass + + @abstractmethod + def comment(self) -> str: + """Get the comment of the tag. + + Returns: + str: The comment of the tag. + """ + pass + + @abstractmethod + def properties(self) -> Dict[str, str]: + """Get the properties of the tag. + + Returns: + Dict[str, str]: The properties of the tag. + """ + pass + + @abstractmethod + def inherited(self) -> Optional[bool]: + """Check if the tag is inherited from a parent object or not. + + If the tag is inherited, it will return `True`, if it is owned by the object itself, it will return `False`. + + **Note**. The return value is optional, only when the tag is associated with an object, and called from the + object, the return value will be present. Otherwise, it will be empty. + + Returns: + Optional[bool]: + True if the tag is inherited, false if it is owned by the object itself. Empty if the + tag is not associated with any object. + """ + pass + + def associated_objects(self) -> AssociatedObjects: + """The associated objects of the tag. + + Raises: + UnsupportedOperationException: The associated_objects method is not supported. + + Returns: + AssociatedObjects: The associated objects of the tag. + """ + raise UnsupportedOperationException( + "The associated_objects method is not supported." + ) diff --git a/clients/client-python/gravitino/exceptions/base.py b/clients/client-python/gravitino/exceptions/base.py index e06bcc1b70..f742381214 100644 --- a/clients/client-python/gravitino/exceptions/base.py +++ b/clients/client-python/gravitino/exceptions/base.py @@ -159,3 +159,11 @@ class BadRequestException(GravitinoRuntimeException): class IllegalStateException(GravitinoRuntimeException): """An exception thrown when the state is invalid.""" + + +class NoSuchTagException(NotFoundException): + """An exception thrown when a tag with specified name is not existed.""" + + +class TagAlreadyExistsException(AlreadyExistsException): + """An exception thrown when a tag with specified name already associated to a metadata object."""