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"