This is an automated email from the ASF dual-hosted git repository.

jerryshao 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 4e6d65b9c7 [#11009] feat(core): add privileges in python client 
(#11026)
4e6d65b9c7 is described below

commit 4e6d65b9c787d7fa007c0b46bca3dd4d59eec23e
Author: Lord of Abyss <[email protected]>
AuthorDate: Wed May 13 15:46:12 2026 +0800

    [#11009] feat(core): add privileges in python client (#11026)
    
    ### What changes were proposed in this pull request?
    Add privilege support in the Python client, including privilege factory
    methods, view/function privileges, metadata object types, and related
    unit tests.
    
    ### Why are the changes needed?
    The Python client lacked complete privilege implementations, so callers
    could not create or validate privilege objects consistently with other
    clients.
    
    Fix: #11009
    
    ### Does this PR introduce any user-facing change?
    Yes. The Python client now exposes privilege objects through
    Privileges.allow() and Privileges.deny(), and adds VIEW and FUNCTION
    metadata object types.
    
    ### How was this patch tested?
    
    unit Test
---
 .../gravitino/api/authorization/privileges.py      | 1479 +++++++++++++++++++-
 .../client-python/gravitino/api/metadata_object.py |    6 +
 .../gravitino/api/metadata_objects.py              |    6 +-
 .../unittests/authorization/test_privileges.py     |  407 ++++++
 .../tests/unittests/test_metadata_objects.py       |   59 +-
 5 files changed, 1950 insertions(+), 7 deletions(-)

diff --git a/clients/client-python/gravitino/api/authorization/privileges.py 
b/clients/client-python/gravitino/api/authorization/privileges.py
index 36e57d8407..cfd1b5ab29 100644
--- a/clients/client-python/gravitino/api/authorization/privileges.py
+++ b/clients/client-python/gravitino/api/authorization/privileges.py
@@ -1,3 +1,4 @@
+# pylint: disable=too-many-lines
 # 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
@@ -18,9 +19,10 @@ from __future__ import annotations
 
 from abc import ABC, abstractmethod
 from enum import Enum
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Optional
 
 from gravitino.api.metadata_object import MetadataObject
+from gravitino.exceptions.base import IllegalArgumentException
 
 if TYPE_CHECKING:
     pass
@@ -142,9 +144,15 @@ class Privilege(ABC):
         REGISTER_MODEL = (0, 1 << 18)
         """The privilege to create a model."""
 
+        CREATE_MODEL = REGISTER_MODEL
+        """Deprecated. Please use REGISTER_MODEL."""
+
         LINK_MODEL_VERSION = (0, 1 << 19)
         """The privilege to create a model version."""
 
+        CREATE_MODEL_VERSION = LINK_MODEL_VERSION
+        """Deprecated. Please use LINK_MODEL_VERSION."""
+
         USE_MODEL = (0, 1 << 20)
         """The privilege to view model metadata and download all model 
versions."""
 
@@ -169,6 +177,21 @@ class Privilege(ABC):
         RUN_JOB = (0, 1 << 27)
         """The privilege to run a job."""
 
+        CREATE_VIEW = (0, 1 << 28)
+        """The privilege to create a view."""
+
+        SELECT_VIEW = (0, 1 << 29)
+        """The privilege to select data from a view."""
+
+        REGISTER_FUNCTION = (0, 1 << 30)
+        """The privilege to register a function."""
+
+        EXECUTE_FUNCTION = (0, 1 << 31)
+        """The privilege to execute (invoke) a function."""
+
+        MODIFY_FUNCTION = (0, 1 << 32)
+        """The privilege to alter a function's metadata."""
+
         def __init__(self, high_bits: int, low_bits: int) -> None:
             """
             Initialize the Name with the high and low bits.
@@ -218,6 +241,1454 @@ class Privilege(ABC):
         DENY = "DENY"
 
 
-class Privileges:
-    # TODO Implement the Privileges class.
-    pass
+class GenericPrivilege(Privilege):
+    """Abstract class representing a generic privilege."""
+
+    def __init__(
+        self,
+        condition: Privilege.Condition,
+        name: Privilege.Name,
+    ) -> None:
+        self._condition = condition
+        self._name = name
+
+    def name(self) -> Privilege.Name:
+        return self._name
+
+    def condition(self) -> Privilege.Condition:
+        return self._condition
+
+    def simple_string(self) -> str:
+        return f"{self._condition.name} {self._name.name.lower().replace('_', 
' ')}"
+
+    def __hash__(self) -> int:
+        return hash((self._condition, self._name))
+
+    def __eq__(self, value: object) -> bool:
+        if not isinstance(value, GenericPrivilege):
+            return False
+        return self._condition == value._condition and self._name == 
value._name
+
+
+class CreateCatalog(GenericPrivilege):
+    """The privilege to create a catalog."""
+
+    _ALLOW_INSTANCE: Optional[CreateCatalog] = None
+    _DENY_INSTANCE: Optional[CreateCatalog] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The privilege with allow condition.
+        """
+        if CreateCatalog._ALLOW_INSTANCE is None:
+            CreateCatalog._ALLOW_INSTANCE = CreateCatalog(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_CATALOG
+            )
+        return CreateCatalog._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if CreateCatalog._DENY_INSTANCE is None:
+            CreateCatalog._DENY_INSTANCE = CreateCatalog(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_CATALOG
+            )
+        return CreateCatalog._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class UseCatalog(GenericPrivilege):
+    """The privilege to use a catalog."""
+
+    _ALLOW_INSTANCE: Optional[UseCatalog] = None
+    _DENY_INSTANCE: Optional[UseCatalog] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if UseCatalog._ALLOW_INSTANCE is None:
+            UseCatalog._ALLOW_INSTANCE = UseCatalog(
+                Privilege.Condition.ALLOW, Privilege.Name.USE_CATALOG
+            )
+
+        return UseCatalog._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if UseCatalog._DENY_INSTANCE is None:
+            UseCatalog._DENY_INSTANCE = UseCatalog(
+                Privilege.Condition.DENY, Privilege.Name.USE_CATALOG
+            )
+
+        return UseCatalog._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.CATALOG]
+
+
+class UseSchema(GenericPrivilege):
+    """The privilege to use a schema."""
+
+    _ALLOW_INSTANCE: Optional[UseSchema] = None
+    _DENY_INSTANCE: Optional[UseSchema] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if UseSchema._ALLOW_INSTANCE is None:
+            UseSchema._ALLOW_INSTANCE = UseSchema(
+                Privilege.Condition.ALLOW, Privilege.Name.USE_SCHEMA
+            )
+
+        return UseSchema._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if UseSchema._DENY_INSTANCE is None:
+            UseSchema._DENY_INSTANCE = UseSchema(
+                Privilege.Condition.DENY, Privilege.Name.USE_SCHEMA
+            )
+
+        return UseSchema._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.SCHEMA_SUPPORTED_TYPES
+
+
+class CreateSchema(GenericPrivilege):
+    """Privilege to create a schema."""
+
+    _ALLOW_INSTANCE: Optional[CreateSchema] = None
+    _DENY_INSTANCE: Optional[CreateSchema] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if CreateSchema._ALLOW_INSTANCE is None:
+            CreateSchema._ALLOW_INSTANCE = CreateSchema(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_SCHEMA
+            )
+
+        return CreateSchema._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if CreateSchema._DENY_INSTANCE is None:
+            CreateSchema._DENY_INSTANCE = CreateSchema(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_SCHEMA
+            )
+
+        return CreateSchema._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.CATALOG]
+
+
+class CreateTable(GenericPrivilege):
+    """The privilege to create a table."""
+
+    _ALLOW_INSTANCE: Optional[CreateTable] = None
+    _DENY_INSTANCE: Optional[CreateTable] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if CreateTable._ALLOW_INSTANCE is None:
+            CreateTable._ALLOW_INSTANCE = CreateTable(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_TABLE
+            )
+
+        return CreateTable._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if CreateTable._DENY_INSTANCE is None:
+            CreateTable._DENY_INSTANCE = CreateTable(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_TABLE
+            )
+
+        return CreateTable._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.SCHEMA_SUPPORTED_TYPES
+
+
+class SelectTable(GenericPrivilege):
+    """
+    Privilege to select table.
+    """
+
+    _ALLOW_INSTANCE: Optional[SelectTable] = None
+    _DENY_INSTANCE: Optional[SelectTable] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if SelectTable._ALLOW_INSTANCE is None:
+            SelectTable._ALLOW_INSTANCE = SelectTable(
+                Privilege.Condition.ALLOW, Privilege.Name.SELECT_TABLE
+            )
+
+        return SelectTable._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if SelectTable._DENY_INSTANCE is None:
+            SelectTable._DENY_INSTANCE = SelectTable(
+                Privilege.Condition.DENY, Privilege.Name.SELECT_TABLE
+            )
+
+        return SelectTable._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.TABLE_SUPPORTED_TYPES
+
+
+class ModifyTable(GenericPrivilege):
+    """The privilege to write data to a table or modify the table schema."""
+
+    _ALLOW_INSTANCE: Optional[ModifyTable] = None
+    _DENY_INSTANCE: Optional[ModifyTable] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if ModifyTable._ALLOW_INSTANCE is None:
+            ModifyTable._ALLOW_INSTANCE = ModifyTable(
+                Privilege.Condition.ALLOW, Privilege.Name.MODIFY_TABLE
+            )
+
+        return ModifyTable._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if ModifyTable._DENY_INSTANCE is None:
+            ModifyTable._DENY_INSTANCE = ModifyTable(
+                Privilege.Condition.DENY, Privilege.Name.MODIFY_TABLE
+            )
+
+        return ModifyTable._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.TABLE_SUPPORTED_TYPES
+
+
+class CreateFileset(GenericPrivilege):
+    """The privilege to create a fileset."""
+
+    _ALLOW_INSTANCE: Optional[CreateFileset] = None
+    _DENY_INSTANCE: Optional[CreateFileset] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if CreateFileset._ALLOW_INSTANCE is None:
+            CreateFileset._ALLOW_INSTANCE = CreateFileset(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_FILESET
+            )
+
+        return CreateFileset._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if CreateFileset._DENY_INSTANCE is None:
+            CreateFileset._DENY_INSTANCE = CreateFileset(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_FILESET
+            )
+
+        return CreateFileset._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.SCHEMA_SUPPORTED_TYPES
+
+
+class ReadFileset(GenericPrivilege):
+    """
+    Privilege to read fileset.
+    """
+
+    _ALLOW_INSTANCE: Optional[ReadFileset] = None
+    _DENY_INSTANCE: Optional[ReadFileset] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if ReadFileset._ALLOW_INSTANCE is None:
+            ReadFileset._ALLOW_INSTANCE = ReadFileset(
+                Privilege.Condition.ALLOW, Privilege.Name.READ_FILESET
+            )
+
+        return ReadFileset._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if ReadFileset._DENY_INSTANCE is None:
+            ReadFileset._DENY_INSTANCE = ReadFileset(
+                Privilege.Condition.DENY, Privilege.Name.READ_FILESET
+            )
+
+        return ReadFileset._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.FILESET_SUPPORTED_TYPES
+
+
+class WriteFileset(GenericPrivilege):
+    """
+    Privilege to write fileset.
+    """
+
+    _ALLOW_INSTANCE: Optional[WriteFileset] = None
+    _DENY_INSTANCE: Optional[WriteFileset] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if WriteFileset._ALLOW_INSTANCE is None:
+            WriteFileset._ALLOW_INSTANCE = WriteFileset(
+                Privilege.Condition.ALLOW, Privilege.Name.WRITE_FILESET
+            )
+
+        return WriteFileset._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if WriteFileset._DENY_INSTANCE is None:
+            WriteFileset._DENY_INSTANCE = WriteFileset(
+                Privilege.Condition.DENY, Privilege.Name.WRITE_FILESET
+            )
+
+        return WriteFileset._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.FILESET_SUPPORTED_TYPES
+
+
+class CreateTopic(GenericPrivilege):
+    """The privilege to create a topic."""
+
+    _ALLOW_INSTANCE: Optional[CreateTopic] = None
+    _DENY_INSTANCE: Optional[CreateTopic] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if CreateTopic._ALLOW_INSTANCE is None:
+            CreateTopic._ALLOW_INSTANCE = CreateTopic(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_TOPIC
+            )
+
+        return CreateTopic._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if CreateTopic._DENY_INSTANCE is None:
+            CreateTopic._DENY_INSTANCE = CreateTopic(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_TOPIC
+            )
+
+        return CreateTopic._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.SCHEMA_SUPPORTED_TYPES
+
+
+class ConsumeTopic(GenericPrivilege):
+    """
+    Privilege for consuming a topic.
+    """
+
+    _ALLOW_INSTANCE: Optional[ConsumeTopic] = None
+    _DENY_INSTANCE: Optional[ConsumeTopic] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if ConsumeTopic._ALLOW_INSTANCE is None:
+            ConsumeTopic._ALLOW_INSTANCE = ConsumeTopic(
+                Privilege.Condition.ALLOW, Privilege.Name.CONSUME_TOPIC
+            )
+
+        return ConsumeTopic._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if ConsumeTopic._DENY_INSTANCE is None:
+            ConsumeTopic._DENY_INSTANCE = ConsumeTopic(
+                Privilege.Condition.DENY, Privilege.Name.CONSUME_TOPIC
+            )
+
+        return ConsumeTopic._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.TOPIC_SUPPORTED_TYPES
+
+
+class ProduceTopic(GenericPrivilege):
+    """The privilege to produce to a topic."""
+
+    _ALLOW_INSTANCE: Optional[ProduceTopic] = None
+    _DENY_INSTANCE: Optional[ProduceTopic] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if ProduceTopic._ALLOW_INSTANCE is None:
+            ProduceTopic._ALLOW_INSTANCE = ProduceTopic(
+                Privilege.Condition.ALLOW, Privilege.Name.PRODUCE_TOPIC
+            )
+
+        return ProduceTopic._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if ProduceTopic._DENY_INSTANCE is None:
+            ProduceTopic._DENY_INSTANCE = ProduceTopic(
+                Privilege.Condition.DENY, Privilege.Name.PRODUCE_TOPIC
+            )
+
+        return ProduceTopic._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.TOPIC_SUPPORTED_TYPES
+
+
+class ManageUsers(GenericPrivilege):
+    """The privilege to manage users."""
+
+    _ALLOW_INSTANCE: Optional[ManageUsers] = None
+    _DENY_INSTANCE: Optional[ManageUsers] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if ManageUsers._ALLOW_INSTANCE is None:
+            ManageUsers._ALLOW_INSTANCE = ManageUsers(
+                Privilege.Condition.ALLOW, Privilege.Name.MANAGE_USERS
+            )
+        return ManageUsers._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if ManageUsers._DENY_INSTANCE is None:
+            ManageUsers._DENY_INSTANCE = ManageUsers(
+                Privilege.Condition.DENY, Privilege.Name.MANAGE_USERS
+            )
+        return ManageUsers._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class ManageGroups(GenericPrivilege):
+    """The privilege to manage groups."""
+
+    _ALLOW_INSTANCE: Optional[ManageGroups] = None
+    _DENY_INSTANCE: Optional[ManageGroups] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if ManageGroups._ALLOW_INSTANCE is None:
+            ManageGroups._ALLOW_INSTANCE = ManageGroups(
+                Privilege.Condition.ALLOW, Privilege.Name.MANAGE_GROUPS
+            )
+
+        return ManageGroups._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if ManageGroups._DENY_INSTANCE is None:
+            ManageGroups._DENY_INSTANCE = ManageGroups(
+                Privilege.Condition.DENY, Privilege.Name.MANAGE_GROUPS
+            )
+
+        return ManageGroups._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class CreateRole(GenericPrivilege):
+    """The privilege to create a role."""
+
+    _ALLOW_INSTANCE: Optional[CreateRole] = None
+    _DENY_INSTANCE: Optional[CreateRole] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if CreateRole._ALLOW_INSTANCE is None:
+            CreateRole._ALLOW_INSTANCE = CreateRole(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_ROLE
+            )
+
+        return CreateRole._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if CreateRole._DENY_INSTANCE is None:
+            CreateRole._DENY_INSTANCE = CreateRole(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_ROLE
+            )
+
+        return CreateRole._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class ManageGrants(GenericPrivilege):
+    """
+    The privilege to grant or revoke privileges on securable objects. If bound 
on the metalake,
+    we can grant or revoke the role for users or groups. Unlike most 
privileges,
+    this can be bound at any level of the object hierarchy — METALAKE,
+    CATALOG, SCHEMA, TABLE, VIEW, TOPIC, FILESET, FUNCTION, or MODEL.
+    A grant at a parent level implicitly covers all descendants within it.
+    """
+
+    _ALLOW_INSTANCE: Optional[ManageGrants] = None
+    _DENY_INSTANCE: Optional[ManageGrants] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if ManageGrants._ALLOW_INSTANCE is None:
+            ManageGrants._ALLOW_INSTANCE = ManageGrants(
+                Privilege.Condition.ALLOW, Privilege.Name.MANAGE_GRANTS
+            )
+
+        return ManageGrants._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if ManageGrants._DENY_INSTANCE is None:
+            ManageGrants._DENY_INSTANCE = ManageGrants(
+                Privilege.Condition.DENY, Privilege.Name.MANAGE_GRANTS
+            )
+
+        return ManageGrants._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.MANAGE_GRANTS_SUPPORTED_TYPES
+
+
+class RegisterModel(GenericPrivilege):
+    """The privilege to register a model"""
+
+    _ALLOW_INSTANCE: Optional[RegisterModel] = None
+    _DENY_INSTANCE: Optional[RegisterModel] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if RegisterModel._ALLOW_INSTANCE is None:
+            RegisterModel._ALLOW_INSTANCE = RegisterModel(
+                Privilege.Condition.ALLOW, Privilege.Name.REGISTER_MODEL
+            )
+
+        return RegisterModel._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if RegisterModel._DENY_INSTANCE is None:
+            RegisterModel._DENY_INSTANCE = RegisterModel(
+                Privilege.Condition.DENY, Privilege.Name.REGISTER_MODEL
+            )
+
+        return RegisterModel._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.SCHEMA_SUPPORTED_TYPES
+
+
+class UseModel(GenericPrivilege):
+    """The privilege to view the metadata of the model and download all the 
model versions"""
+
+    _ALLOW_INSTANCE: Optional[UseModel] = None
+    _DENY_INSTANCE: Optional[UseModel] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if UseModel._ALLOW_INSTANCE is None:
+            UseModel._ALLOW_INSTANCE = UseModel(
+                Privilege.Condition.ALLOW, Privilege.Name.USE_MODEL
+            )
+
+        return UseModel._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if UseModel._DENY_INSTANCE is None:
+            UseModel._DENY_INSTANCE = UseModel(
+                Privilege.Condition.DENY, Privilege.Name.USE_MODEL
+            )
+
+        return UseModel._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.MODEL_SUPPORTED_TYPES
+
+
+class LinkModelVersion(GenericPrivilege):
+    """The privilege to link a model version"""
+
+    _ALLOW_INSTANCE: Optional[LinkModelVersion] = None
+    _DENY_INSTANCE: Optional[LinkModelVersion] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if LinkModelVersion._ALLOW_INSTANCE is None:
+            LinkModelVersion._ALLOW_INSTANCE = LinkModelVersion(
+                Privilege.Condition.ALLOW, Privilege.Name.LINK_MODEL_VERSION
+            )
+
+        return LinkModelVersion._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if LinkModelVersion._DENY_INSTANCE is None:
+            LinkModelVersion._DENY_INSTANCE = LinkModelVersion(
+                Privilege.Condition.DENY, Privilege.Name.LINK_MODEL_VERSION
+            )
+
+        return LinkModelVersion._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.MODEL_SUPPORTED_TYPES
+
+
+class CreateTag(GenericPrivilege):
+    """The privilege to create a tag"""
+
+    _ALLOW_INSTANCE: Optional[CreateTag] = None
+    _DENY_INSTANCE: Optional[CreateTag] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if CreateTag._ALLOW_INSTANCE is None:
+            CreateTag._ALLOW_INSTANCE = CreateTag(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_TAG
+            )
+
+        return CreateTag._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if CreateTag._DENY_INSTANCE is None:
+            CreateTag._DENY_INSTANCE = CreateTag(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_TAG
+            )
+
+        return CreateTag._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class ApplyTag(GenericPrivilege):
+    """The privilege to apply tag to object."""
+
+    _ALLOW_INSTANCE: Optional[ApplyTag] = None
+    _DENY_INSTANCE: Optional[ApplyTag] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if ApplyTag._ALLOW_INSTANCE is None:
+            ApplyTag._ALLOW_INSTANCE = ApplyTag(
+                Privilege.Condition.ALLOW, Privilege.Name.APPLY_TAG
+            )
+        return ApplyTag._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if ApplyTag._DENY_INSTANCE is None:
+            ApplyTag._DENY_INSTANCE = ApplyTag(
+                Privilege.Condition.DENY, Privilege.Name.APPLY_TAG
+            )
+        return ApplyTag._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.TAG]
+
+
+class CreatePolicy(GenericPrivilege):
+    """The privilege to create a policy"""
+
+    _ALLOW_INSTANCE: Optional[CreatePolicy] = None
+    _DENY_INSTANCE: Optional[CreatePolicy] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if CreatePolicy._ALLOW_INSTANCE is None:
+            CreatePolicy._ALLOW_INSTANCE = CreatePolicy(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_POLICY
+            )
+
+        return CreatePolicy._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if CreatePolicy._DENY_INSTANCE is None:
+            CreatePolicy._DENY_INSTANCE = CreatePolicy(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_POLICY
+            )
+
+        return CreatePolicy._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class RunJob(GenericPrivilege):
+    """The privilege to run a job."""
+
+    _ALLOW_INSTANCE: Optional[RunJob] = None
+    _DENY_INSTANCE: Optional[RunJob] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if RunJob._ALLOW_INSTANCE is None:
+            RunJob._ALLOW_INSTANCE = RunJob(
+                Privilege.Condition.ALLOW, Privilege.Name.RUN_JOB
+            )
+
+        return RunJob._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if RunJob._DENY_INSTANCE is None:
+            RunJob._DENY_INSTANCE = RunJob(
+                Privilege.Condition.DENY, Privilege.Name.RUN_JOB
+            )
+        return RunJob._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class ApplyPolicy(GenericPrivilege):
+    """The privilege to apply policy to object."""
+
+    _ALLOW_INSTANCE: Optional[ApplyPolicy] = None
+    _DENY_INSTANCE: Optional[ApplyPolicy] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if ApplyPolicy._ALLOW_INSTANCE is None:
+            ApplyPolicy._ALLOW_INSTANCE = ApplyPolicy(
+                Privilege.Condition.ALLOW, Privilege.Name.APPLY_POLICY
+            )
+
+        return ApplyPolicy._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if ApplyPolicy._DENY_INSTANCE is None:
+            ApplyPolicy._DENY_INSTANCE = ApplyPolicy(
+                Privilege.Condition.DENY, Privilege.Name.APPLY_POLICY
+            )
+        return ApplyPolicy._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.POLICY]
+
+
+class RegisterJobTemplate(GenericPrivilege):
+    """The privilege to register a job template"""
+
+    _ALLOW_INSTANCE: Optional[RegisterJobTemplate] = None
+    _DENY_INSTANCE: Optional[RegisterJobTemplate] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if RegisterJobTemplate._ALLOW_INSTANCE is None:
+            RegisterJobTemplate._ALLOW_INSTANCE = RegisterJobTemplate(
+                Privilege.Condition.ALLOW, Privilege.Name.REGISTER_JOB_TEMPLATE
+            )
+
+        return RegisterJobTemplate._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if RegisterJobTemplate._DENY_INSTANCE is None:
+            RegisterJobTemplate._DENY_INSTANCE = RegisterJobTemplate(
+                Privilege.Condition.DENY, Privilege.Name.REGISTER_JOB_TEMPLATE
+            )
+
+        return RegisterJobTemplate._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type == MetadataObject.Type.METALAKE
+
+
+class UseJobTemplate(GenericPrivilege):
+    """The privilege to use a job template."""
+
+    _ALLOW_INSTANCE: Optional[UseJobTemplate] = None
+    _DENY_INSTANCE: Optional[UseJobTemplate] = None
+
+    @staticmethod
+    def allow() -> Privilege:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+
+        """
+        if UseJobTemplate._ALLOW_INSTANCE is None:
+            UseJobTemplate._ALLOW_INSTANCE = UseJobTemplate(
+                Privilege.Condition.ALLOW, Privilege.Name.USE_JOB_TEMPLATE
+            )
+
+        return UseJobTemplate._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> Privilege:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+
+        """
+        if UseJobTemplate._DENY_INSTANCE is None:
+            UseJobTemplate._DENY_INSTANCE = UseJobTemplate(
+                Privilege.Condition.DENY, Privilege.Name.USE_JOB_TEMPLATE
+            )
+
+        return UseJobTemplate._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in [
+            MetadataObject.Type.METALAKE,
+            MetadataObject.Type.JOB_TEMPLATE,
+        ]
+
+
+class CreateView(GenericPrivilege):
+    """The privilege to create a view."""
+
+    _ALLOW_INSTANCE: Optional[CreateView] = None
+    _DENY_INSTANCE: Optional[CreateView] = None
+
+    @staticmethod
+    def allow() -> CreateView:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if CreateView._ALLOW_INSTANCE is None:
+            CreateView._ALLOW_INSTANCE = CreateView(
+                Privilege.Condition.ALLOW, Privilege.Name.CREATE_VIEW
+            )
+        return CreateView._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> CreateView:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if CreateView._DENY_INSTANCE is None:
+            CreateView._DENY_INSTANCE = CreateView(
+                Privilege.Condition.DENY, Privilege.Name.CREATE_VIEW
+            )
+        return CreateView._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.SCHEMA_SUPPORTED_TYPES
+
+
+class SelectView(GenericPrivilege):
+    """The privilege to select data from a view."""
+
+    _ALLOW_INSTANCE: Optional[SelectView] = None
+    _DENY_INSTANCE: Optional[SelectView] = None
+
+    @staticmethod
+    def allow() -> SelectView:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if SelectView._ALLOW_INSTANCE is None:
+            SelectView._ALLOW_INSTANCE = SelectView(
+                Privilege.Condition.ALLOW, Privilege.Name.SELECT_VIEW
+            )
+        return SelectView._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> SelectView:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if SelectView._DENY_INSTANCE is None:
+            SelectView._DENY_INSTANCE = SelectView(
+                Privilege.Condition.DENY, Privilege.Name.SELECT_VIEW
+            )
+        return SelectView._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.VIEW_SUPPORTED_TYPES
+
+
+class RegisterFunction(GenericPrivilege):
+    """The privilege to register a function."""
+
+    _ALLOW_INSTANCE: Optional[RegisterFunction] = None
+    _DENY_INSTANCE: Optional[RegisterFunction] = None
+
+    @staticmethod
+    def allow() -> RegisterFunction:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if RegisterFunction._ALLOW_INSTANCE is None:
+            RegisterFunction._ALLOW_INSTANCE = RegisterFunction(
+                Privilege.Condition.ALLOW, Privilege.Name.REGISTER_FUNCTION
+            )
+
+        return RegisterFunction._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> RegisterFunction:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if RegisterFunction._DENY_INSTANCE is None:
+            RegisterFunction._DENY_INSTANCE = RegisterFunction(
+                Privilege.Condition.DENY, Privilege.Name.REGISTER_FUNCTION
+            )
+        return RegisterFunction._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.SCHEMA_SUPPORTED_TYPES
+
+
+class ExecuteFunction(GenericPrivilege):
+    """The privilege to execute (invoke) a function and view its metadata."""
+
+    _ALLOW_INSTANCE: Optional[ExecuteFunction] = None
+    _DENY_INSTANCE: Optional[ExecuteFunction] = None
+
+    @staticmethod
+    def allow() -> ExecuteFunction:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if ExecuteFunction._ALLOW_INSTANCE is None:
+            ExecuteFunction._ALLOW_INSTANCE = ExecuteFunction(
+                Privilege.Condition.ALLOW, Privilege.Name.EXECUTE_FUNCTION
+            )
+        return ExecuteFunction._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> ExecuteFunction:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if ExecuteFunction._DENY_INSTANCE is None:
+            ExecuteFunction._DENY_INSTANCE = ExecuteFunction(
+                Privilege.Condition.DENY, Privilege.Name.EXECUTE_FUNCTION
+            )
+        return ExecuteFunction._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.FUNCTION_SUPPORTED_TYPES
+
+
+class ModifyFunction(GenericPrivilege):
+    """
+    The privilege to alter a function's metadata.
+    """
+
+    _ALLOW_INSTANCE: Optional[ModifyFunction] = None
+    _DENY_INSTANCE: Optional[ModifyFunction] = None
+
+    @staticmethod
+    def allow() -> ModifyFunction:
+        """
+        Retrieve the instance with allow condition of the privilege.
+
+        Returns:
+            Privilege: The instance with allow condition of the privilege.
+        """
+        if ModifyFunction._ALLOW_INSTANCE is None:
+            ModifyFunction._ALLOW_INSTANCE = ModifyFunction(
+                Privilege.Condition.ALLOW, Privilege.Name.MODIFY_FUNCTION
+            )
+        return ModifyFunction._ALLOW_INSTANCE
+
+    @staticmethod
+    def deny() -> ModifyFunction:
+        """
+        Retrieve the instance with deny condition of the privilege.
+
+        Returns:
+            Privilege: The instance with deny condition of the privilege.
+        """
+        if ModifyFunction._DENY_INSTANCE is None:
+            ModifyFunction._DENY_INSTANCE = ModifyFunction(
+                Privilege.Condition.DENY, Privilege.Name.MODIFY_FUNCTION
+            )
+        return ModifyFunction._DENY_INSTANCE
+
+    def can_bind_to(self, obj_type: MetadataObject.Type) -> bool:
+        return obj_type in Privileges.FUNCTION_SUPPORTED_TYPES
+
+
+class Privileges:
+    _PRIVILEGE_TYPES = {
+        Privilege.Name.CREATE_CATALOG: CreateCatalog,
+        Privilege.Name.USE_CATALOG: UseCatalog,
+        Privilege.Name.CREATE_SCHEMA: CreateSchema,
+        Privilege.Name.USE_SCHEMA: UseSchema,
+        Privilege.Name.CREATE_TABLE: CreateTable,
+        Privilege.Name.MODIFY_TABLE: ModifyTable,
+        Privilege.Name.SELECT_TABLE: SelectTable,
+        Privilege.Name.CREATE_FILESET: CreateFileset,
+        Privilege.Name.WRITE_FILESET: WriteFileset,
+        Privilege.Name.READ_FILESET: ReadFileset,
+        Privilege.Name.CREATE_TOPIC: CreateTopic,
+        Privilege.Name.PRODUCE_TOPIC: ProduceTopic,
+        Privilege.Name.CONSUME_TOPIC: ConsumeTopic,
+        Privilege.Name.MANAGE_USERS: ManageUsers,
+        Privilege.Name.MANAGE_GROUPS: ManageGroups,
+        Privilege.Name.CREATE_ROLE: CreateRole,
+        Privilege.Name.MANAGE_GRANTS: ManageGrants,
+        Privilege.Name.REGISTER_MODEL: RegisterModel,
+        Privilege.Name.LINK_MODEL_VERSION: LinkModelVersion,
+        Privilege.Name.USE_MODEL: UseModel,
+        Privilege.Name.CREATE_TAG: CreateTag,
+        Privilege.Name.APPLY_TAG: ApplyTag,
+        Privilege.Name.CREATE_POLICY: CreatePolicy,
+        Privilege.Name.APPLY_POLICY: ApplyPolicy,
+        Privilege.Name.REGISTER_JOB_TEMPLATE: RegisterJobTemplate,
+        Privilege.Name.USE_JOB_TEMPLATE: UseJobTemplate,
+        Privilege.Name.RUN_JOB: RunJob,
+        Privilege.Name.CREATE_VIEW: CreateView,
+        Privilege.Name.SELECT_VIEW: SelectView,
+        Privilege.Name.REGISTER_FUNCTION: RegisterFunction,
+        Privilege.Name.EXECUTE_FUNCTION: ExecuteFunction,
+        Privilege.Name.MODIFY_FUNCTION: ModifyFunction,
+    }
+
+    TABLE_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+        MetadataObject.Type.TABLE,
+    }
+    MODEL_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+        MetadataObject.Type.MODEL,
+    }
+    TOPIC_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+        MetadataObject.Type.TOPIC,
+    }
+    FILESET_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+        MetadataObject.Type.FILESET,
+    }
+    VIEW_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+        MetadataObject.Type.VIEW,
+    }
+    FUNCTION_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+        MetadataObject.Type.FUNCTION,
+    }
+    MANAGE_GRANTS_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+        MetadataObject.Type.TABLE,
+        MetadataObject.Type.TOPIC,
+        MetadataObject.Type.FILESET,
+        MetadataObject.Type.MODEL,
+        MetadataObject.Type.VIEW,
+        MetadataObject.Type.FUNCTION,
+    }
+    SCHEMA_SUPPORTED_TYPES = {
+        MetadataObject.Type.METALAKE,
+        MetadataObject.Type.CATALOG,
+        MetadataObject.Type.SCHEMA,
+    }
+
+    @staticmethod
+    def allow(privilege: str) -> Privilege:
+        return Privileges._privilege_type(privilege).allow()
+
+    @staticmethod
+    def deny(privilege: str) -> Privilege:
+        return Privileges._privilege_type(privilege).deny()
+
+    @staticmethod
+    def _privilege_type(privilege: str):
+        try:
+            name = Privilege.Name[privilege]
+            return Privileges._PRIVILEGE_TYPES[name]
+        except KeyError as exc:
+            raise IllegalArgumentException(
+                f"Doesn't support the privilege: {privilege}"
+            ) from exc
diff --git a/clients/client-python/gravitino/api/metadata_object.py 
b/clients/client-python/gravitino/api/metadata_object.py
index 2c492bb42e..a46a9ba44a 100644
--- a/clients/client-python/gravitino/api/metadata_object.py
+++ b/clients/client-python/gravitino/api/metadata_object.py
@@ -56,6 +56,9 @@ class MetadataObject(ABC):
         MySQL, etc.
         """
 
+        VIEW = "view"
+        """A view is mapped to the view of relational data sources like Apache 
Hive, MySQL, etc."""
+
         TOPIC = "topic"
         """A topic is mapped the topic of messaging data sources like Apache 
Kafka,
         Apache Pulsar, etc.
@@ -84,6 +87,9 @@ class MetadataObject(ABC):
         JOB_TEMPLATE = "job_template"
         """A job template represents a reusable template for creating jobs in 
Gravitino."""
 
+        FUNCTION = "function"
+        """A function represents a user-defined function registered in 
Gravitino."""
+
     @abstractmethod
     def parent(self) -> Optional[str]:
         """The parent full name of the object.
diff --git a/clients/client-python/gravitino/api/metadata_objects.py 
b/clients/client-python/gravitino/api/metadata_objects.py
index 7d7b4babfe..73199d9533 100644
--- a/clients/client-python/gravitino/api/metadata_objects.py
+++ b/clients/client-python/gravitino/api/metadata_objects.py
@@ -47,6 +47,8 @@ class MetadataObjects:
             MetadataObject.Type.TABLE,
             MetadataObject.Type.TOPIC,
             MetadataObject.Type.MODEL,
+            MetadataObject.Type.VIEW,
+            MetadataObject.Type.FUNCTION,
         },
         4: {MetadataObject.Type.COLUMN},
     }
@@ -92,7 +94,7 @@ class MetadataObjects:
         )
         Precondition.check_argument(
             names_len != 3 or type_ in MetadataObjects._NAMES_LEN_CONDS[3],
-            "If the length of names is 3, it must be FILESET, TABLE, TOPIC or 
MODEL",
+            "If the length of names is 3, it must be FILESET, TABLE, TOPIC, 
MODEL, VIEW or FUNCTION",
         )
         Precondition.check_argument(
             names_len != 4 or type_ in MetadataObjects._NAMES_LEN_CONDS[4],
@@ -138,6 +140,8 @@ class MetadataObjects:
             MetadataObject.Type.FILESET,
             MetadataObject.Type.TOPIC,
             MetadataObject.Type.MODEL,
+            MetadataObject.Type.FUNCTION,
+            MetadataObject.Type.VIEW,
         }:
             parent_type = MetadataObject.Type.SCHEMA
         elif object_type is MetadataObject.Type.SCHEMA:
diff --git 
a/clients/client-python/tests/unittests/authorization/test_privileges.py 
b/clients/client-python/tests/unittests/authorization/test_privileges.py
new file mode 100644
index 0000000000..daa3317989
--- /dev/null
+++ b/clients/client-python/tests/unittests/authorization/test_privileges.py
@@ -0,0 +1,407 @@
+# 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 unittest
+
+from gravitino.api.authorization.privileges import (
+    ApplyPolicy,
+    ApplyTag,
+    ConsumeTopic,
+    CreateCatalog,
+    CreateFileset,
+    CreatePolicy,
+    CreateRole,
+    CreateSchema,
+    CreateTable,
+    CreateTag,
+    CreateTopic,
+    CreateView,
+    ExecuteFunction,
+    LinkModelVersion,
+    ManageGrants,
+    ManageGroups,
+    ManageUsers,
+    ModifyFunction,
+    ModifyTable,
+    Privilege,
+    Privileges,
+    ProduceTopic,
+    ReadFileset,
+    RegisterFunction,
+    RegisterJobTemplate,
+    RegisterModel,
+    RunJob,
+    SelectTable,
+    SelectView,
+    UseCatalog,
+    UseJobTemplate,
+    UseModel,
+    UseSchema,
+    WriteFileset,
+)
+from gravitino.api.metadata_object import MetadataObject
+from gravitino.exceptions.base import IllegalArgumentException
+
+
+class TestPrivileges(unittest.TestCase):
+    def test_allow_and_deny_return_instances_for_all_privileges(self) -> None:
+        for name in Privilege.Name:
+            with self.subTest(privilege=name.name):
+                allow_privilege = Privileges.allow(name.name)
+                deny_privilege = Privileges.deny(name.name)
+
+                self.assertEqual(name, allow_privilege.name())
+                self.assertEqual(Privilege.Condition.ALLOW, 
allow_privilege.condition())
+                self.assertIs(allow_privilege, Privileges.allow(name.name))
+
+                self.assertEqual(name, deny_privilege.name())
+                self.assertEqual(Privilege.Condition.DENY, 
deny_privilege.condition())
+                self.assertIs(deny_privilege, Privileges.deny(name.name))
+
+    def test_allow_raises_illegal_argument_exception_for_unknown_privilege(
+        self,
+    ) -> None:
+        with self.assertRaises(IllegalArgumentException):
+            Privileges.allow("NO_SUCH_PRIVILEGE")
+
+    def 
test_deny_raises_illegal_argument_exception_for_unknown_privilege(self) -> None:
+        with self.assertRaises(IllegalArgumentException):
+            Privileges.deny("NO_SUCH_PRIVILEGE")
+
+    def test_deprecated_model_privilege_names_are_supported(self) -> None:
+        self.assertEqual(
+            Privilege.Name.REGISTER_MODEL.low_bits,
+            Privilege.Name.CREATE_MODEL.low_bits,
+        )
+        self.assertEqual(
+            Privilege.Name.LINK_MODEL_VERSION.low_bits,
+            Privilege.Name.CREATE_MODEL_VERSION.low_bits,
+        )
+
+        self.assertEqual(
+            Privilege.Name.REGISTER_MODEL,
+            Privileges.allow("CREATE_MODEL").name(),
+        )
+        self.assertEqual(
+            Privilege.Name.REGISTER_MODEL,
+            Privileges.deny("CREATE_MODEL").name(),
+        )
+        self.assertEqual(
+            Privilege.Name.LINK_MODEL_VERSION,
+            Privileges.allow("CREATE_MODEL_VERSION").name(),
+        )
+        self.assertEqual(
+            Privilege.Name.LINK_MODEL_VERSION,
+            Privileges.deny("CREATE_MODEL_VERSION").name(),
+        )
+
+    def test_create_catalog_binding(self) -> None:
+        allow_privilege = CreateCatalog.allow()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    allow_privilege.can_bind_to(obj_type),
+                )
+
+    def test_use_catalog_binding(self) -> None:
+        deny_privilege = UseCatalog.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type
+                    in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.CATALOG],
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_use_schema_binding(self) -> None:
+        allow_privilege = UseSchema.allow()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.SCHEMA_SUPPORTED_TYPES,
+                    allow_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_schema_binding(self) -> None:
+        deny_privilege = CreateSchema.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type
+                    in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.CATALOG],
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_table_binding(self) -> None:
+        deny_privilege = CreateTable.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.SCHEMA_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_select_table_binding(self) -> None:
+        deny_privilege = SelectTable.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.TABLE_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_modify_table_binding(self) -> None:
+        deny_privilege = ModifyTable.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.TABLE_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_fileset_binding(self) -> None:
+        deny_privilege = CreateFileset.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.SCHEMA_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_read_fileset_binding(self) -> None:
+        deny_privilege = ReadFileset.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.FILESET_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_write_fileset_binding(self) -> None:
+        deny_privilege = WriteFileset.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.FILESET_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_topic_binding(self) -> None:
+        deny_privilege = CreateTopic.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.SCHEMA_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_consume_topic_binding(self) -> None:
+        deny_privilege = ConsumeTopic.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.TOPIC_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_produce_topic_binding(self) -> None:
+        deny_privilege = ProduceTopic.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.TOPIC_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_manage_users_binding(self) -> None:
+        deny_privilege = ManageUsers.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_manage_groups_binding(self) -> None:
+        deny_privilege = ManageGroups.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_role_binding(self) -> None:
+        deny_privilege = CreateRole.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_manage_grants_binding(self) -> None:
+        deny_privilege = ManageGrants.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.MANAGE_GRANTS_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_register_model_binding(self) -> None:
+        deny_privilege = RegisterModel.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.SCHEMA_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_use_model_binding(self) -> None:
+        deny_privilege = UseModel.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.MODEL_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_link_model_version_binding(self) -> None:
+        deny_privilege = LinkModelVersion.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.MODEL_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_tag_binding(self) -> None:
+        deny_privilege = CreateTag.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_apply_tag_binding(self) -> None:
+        deny_privilege = ApplyTag.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.TAG],
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_policy_binding(self) -> None:
+        deny_privilege = CreatePolicy.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_run_job_binding(self) -> None:
+        deny_privilege = RunJob.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_apply_policy_binding(self) -> None:
+        deny_privilege = ApplyPolicy.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type
+                    in [MetadataObject.Type.METALAKE, 
MetadataObject.Type.POLICY],
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_register_job_template_binding(self) -> None:
+        deny_privilege = RegisterJobTemplate.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type == MetadataObject.Type.METALAKE,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_use_job_template_binding(self) -> None:
+        deny_privilege = UseJobTemplate.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type
+                    in [
+                        MetadataObject.Type.METALAKE,
+                        MetadataObject.Type.JOB_TEMPLATE,
+                    ],
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_create_view_binding(self) -> None:
+        deny_privilege = CreateView.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.SCHEMA_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_select_view_binding(self) -> None:
+        deny_privilege = SelectView.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.VIEW_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_register_function_binding(self) -> None:
+        deny_privilege = RegisterFunction.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.SCHEMA_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_execute_function_binding(self) -> None:
+        deny_privilege = ExecuteFunction.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.FUNCTION_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
+
+    def test_modify_function_binding(self) -> None:
+        deny_privilege = ModifyFunction.deny()
+        for obj_type in MetadataObject.Type:
+            with self.subTest(obj_type=obj_type.name):
+                self.assertEqual(
+                    obj_type in Privileges.FUNCTION_SUPPORTED_TYPES,
+                    deny_privilege.can_bind_to(obj_type),
+                )
diff --git a/clients/client-python/tests/unittests/test_metadata_objects.py 
b/clients/client-python/tests/unittests/test_metadata_objects.py
index 412f4e02b3..2e47aa480f 100644
--- a/clients/client-python/tests/unittests/test_metadata_objects.py
+++ b/clients/client-python/tests/unittests/test_metadata_objects.py
@@ -67,6 +67,22 @@ class TestMetadataObjects(unittest.TestCase):
         self.assertEqual(MetadataObject.Type.TABLE, obj.type())
         self.assertEqual("catalog1.schema1", obj.parent())
 
+    def test_of_with_list_names_view(self):
+        obj = MetadataObjects.of(
+            ["catalog1", "schema1", "view1"], MetadataObject.Type.VIEW
+        )
+        self.assertEqual("view1", obj.name())
+        self.assertEqual(MetadataObject.Type.VIEW, obj.type())
+        self.assertEqual("catalog1.schema1", obj.parent())
+
+    def test_of_with_list_names_function(self):
+        obj = MetadataObjects.of(
+            ["catalog1", "schema1", "function1"], MetadataObject.Type.FUNCTION
+        )
+        self.assertEqual("function1", obj.name())
+        self.assertEqual(MetadataObject.Type.FUNCTION, obj.type())
+        self.assertEqual("catalog1.schema1", obj.parent())
+
     def test_of_with_list_names_column(self):
         obj = MetadataObjects.of(
             ["catalog1", "schema1", "table1", "col1"], 
MetadataObject.Type.COLUMN
@@ -101,7 +117,7 @@ class TestMetadataObjects(unittest.TestCase):
 
         with self.assertRaisesRegex(
             IllegalArgumentException,
-            "If the length of names is 3, it must be FILESET, TABLE, TOPIC or 
MODEL",
+            "If the length of names is 3, it must be FILESET, TABLE, TOPIC, 
MODEL, VIEW or FUNCTION",
         ):
             MetadataObjects.of(
                 ["catalog1", "schema1", "table1"], MetadataObject.Type.COLUMN
@@ -145,6 +161,26 @@ class TestMetadataObjects(unittest.TestCase):
         self.assertEqual(MetadataObject.Type.SCHEMA, parent.type())
         self.assertEqual("catalog1", parent.parent())
 
+    def test_parent_view(self):
+        obj = MetadataObjects.of(
+            ["catalog1", "schema1", "view1"], MetadataObject.Type.VIEW
+        )
+        parent = MetadataObjects.parent(obj)
+        self.assertIsNotNone(parent)
+        self.assertEqual("schema1", parent.name())
+        self.assertEqual(MetadataObject.Type.SCHEMA, parent.type())
+        self.assertEqual("catalog1", parent.parent())
+
+    def test_parent_function(self):
+        obj = MetadataObjects.of(
+            ["catalog1", "schema1", "function1"], MetadataObject.Type.FUNCTION
+        )
+        parent = MetadataObjects.parent(obj)
+        self.assertIsNotNone(parent)
+        self.assertEqual("schema1", parent.name())
+        self.assertEqual(MetadataObject.Type.SCHEMA, parent.type())
+        self.assertEqual("catalog1", parent.parent())
+
     def test_parent_column(self):
         obj = MetadataObjects.of(
             ["catalog1", "schema1", "table1", "col1"], 
MetadataObject.Type.COLUMN
@@ -170,7 +206,12 @@ class TestMetadataObjects(unittest.TestCase):
         self.assertEqual(
             "catalog1.schema1.table1",
             MetadataObjects.get_parent_full_name(
-                ["catalog1", "schema1", "table1", "col1"]
+                [
+                    "catalog1",
+                    "schema1",
+                    "table1",
+                    "col1",
+                ]
             ),
         )
 
@@ -225,6 +266,20 @@ class TestMetadataObjects(unittest.TestCase):
         self.assertEqual(MetadataObject.Type.TABLE, obj.type())
         self.assertEqual("catalog1.schema1", obj.parent())
 
+    def test_parse_view(self):
+        obj = MetadataObjects.parse("catalog1.schema1.view1", 
MetadataObject.Type.VIEW)
+        self.assertEqual("view1", obj.name())
+        self.assertEqual(MetadataObject.Type.VIEW, obj.type())
+        self.assertEqual("catalog1.schema1", obj.parent())
+
+    def test_parse_function(self):
+        obj = MetadataObjects.parse(
+            "catalog1.schema1.function1", MetadataObject.Type.FUNCTION
+        )
+        self.assertEqual("function1", obj.name())
+        self.assertEqual(MetadataObject.Type.FUNCTION, obj.type())
+        self.assertEqual("catalog1.schema1", obj.parent())
+
     def test_parse_invalid_blank_name(self):
         with self.assertRaisesRegex(
             IllegalArgumentException, "Metadata object full name cannot be 
blank"

Reply via email to