Skip to content

Commit cc97382

Browse files
committed
Implement CatalogABCMeta for enhanced namespace support in Catalog class
1 parent d1bc236 commit cc97382

File tree

3 files changed

+80
-7
lines changed

3 files changed

+80
-7
lines changed

pyiceberg/catalog/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
cast,
3232
)
3333

34+
from pyiceberg.catalog._meta import CatalogABCMeta
3435
from pyiceberg.exceptions import (
3536
NamespaceAlreadyExistsError,
3637
NoSuchNamespaceError,
@@ -331,7 +332,7 @@ class PropertiesUpdateSummary:
331332
missing: list[str]
332333

333334

334-
class Catalog(ABC):
335+
class Catalog(ABC, metaclass=CatalogABCMeta):
335336
"""Base Catalog for table operations like - create, drop, load, list and others.
336337
337338
The catalog table APIs accept a table identifier, which is fully classified table name. The identifier can be a string or
@@ -347,7 +348,6 @@ class Catalog(ABC):
347348

348349
name: str
349350
properties: Properties
350-
_support_namespaces: bool = False
351351

352352
def __init__(self, name: str, **properties: str):
353353
self.name = name
@@ -724,7 +724,7 @@ def namespace_to_string(identifier: str | Identifier, err: type[ValueError] | ty
724724
return ".".join(segment.strip() for segment in tuple_identifier)
725725

726726
@staticmethod
727-
def namespace_level(identifier: Union[str, Identifier]) -> int:
727+
def namespace_level(identifier: str | Identifier) -> int:
728728
"""Get the level of a namespace identifier.
729729
730730
Args:

pyiceberg/catalog/_meta.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
from abc import ABCMeta
18+
from typing import TYPE_CHECKING, Any, Callable, TypeVar
19+
20+
if TYPE_CHECKING:
21+
from pyiceberg.catalog import Catalog
22+
23+
_T = TypeVar("_T", bound="Catalog")
24+
25+
26+
class NamespaceMeta(type):
27+
"""Metaclass for managing namespace support configuration in catalog implementations.
28+
29+
This metaclass automatically handles the inheritance and initialization of namespace-related
30+
attributes for catalog classes. It ensures that namespace support configuration is properly
31+
propagated through class inheritance hierarchies.
32+
33+
Attributes:
34+
_support_namespaces (bool): Indicates whether the catalog supports nested namespaces.
35+
Defaults to False. When True, the catalog can handle hierarchical namespace
36+
structures beyond simple flat namespaces.
37+
_max_namespace_depth (int): Maximum depth allowed for nested namespaces.
38+
Defaults to -1 (unlimited depth). When set to a positive integer,
39+
restricts the nesting level of namespaces that can be created.
40+
"""
41+
42+
_support_namespaces: bool = False
43+
_max_namespace_depth: int = -1
44+
45+
def __new__(mcls, name: str, bases: tuple[type, ...], atrrs: dict[str, Any], /, **kwargs: Any) -> type:
46+
cls = super().__new__(mcls, name, bases, atrrs, **kwargs)
47+
if "_support_namespaces" in atrrs:
48+
pass # Already defined in the class
49+
elif hasattr(bases[0], "_support_namespaces"):
50+
cls._support_namespaces = bases[0]._support_namespaces
51+
else:
52+
cls._support_namespaces = NamespaceMeta._support_namespaces
53+
return cls
54+
55+
56+
class CatalogABCMeta(NamespaceMeta, ABCMeta):
57+
"""Metaclass for catalog implementations that combines namespace and abstract base class functionality.
58+
59+
This metaclass inherits from both NamespaceMeta and ABCMeta.
60+
"""
61+
62+
63+
def multiple_namespaces(
64+
_cls: type[_T] | None = None, /, disabled: bool = False, max_depth: int = -1
65+
) -> type[_T] | Callable[[type[_T]], type[_T]]:
66+
def wrapper(cls: type[_T]) -> type[_T]:
67+
if not hasattr(cls, "_support_namespaces"):
68+
raise ValueError(f"{cls.__name__} must inherit Catalog with CatalogABCMeta and NamespaceMeta to use this decorator")
69+
if max_depth >= 0 and max_depth <= 1 or disabled:
70+
cls._support_namespaces = False
71+
else:
72+
cls._support_namespaces = True
73+
cls._max_namespace_depth = max_depth
74+
return cls
75+
76+
return wrapper if _cls is None else wrapper(_cls)

pyiceberg/table/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,7 @@
3232
ClassVar,
3333
Iterable,
3434
Iterator,
35-
List,
36-
Set,
37-
Tuple,
38-
Type,
35+
Sequence,
3936
TypeVar,
4037
)
4138

0 commit comments

Comments
 (0)