This is an automated email from the ASF dual-hosted git repository.
honahx pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git
The following commit(s) were added to refs/heads/main by this push:
new a268e5bd Add create_namespace_if_not_exists method (#725)
a268e5bd is described below
commit a268e5bdd3f3b2eee36e00bc43578ef6c28c7e51
Author: Andre Luis Anastacio <[email protected]>
AuthorDate: Wed May 15 04:14:04 2024 -0300
Add create_namespace_if_not_exists method (#725)
---
pyiceberg/catalog/__init__.py | 20 +++++++++++++++++++-
tests/catalog/integration_test_dynamodb.py | 6 ++++++
tests/catalog/integration_test_glue.py | 6 ++++++
tests/catalog/test_rest.py | 18 ++++++++++++++++++
tests/catalog/test_sql.py | 14 ++++++++++++++
5 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/pyiceberg/catalog/__init__.py b/pyiceberg/catalog/__init__.py
index 5bb9ec27..0b70fe32 100644
--- a/pyiceberg/catalog/__init__.py
+++ b/pyiceberg/catalog/__init__.py
@@ -36,7 +36,13 @@ from typing import (
cast,
)
-from pyiceberg.exceptions import NoSuchNamespaceError, NoSuchTableError,
NotInstalledError, TableAlreadyExistsError
+from pyiceberg.exceptions import (
+ NamespaceAlreadyExistsError,
+ NoSuchNamespaceError,
+ NoSuchTableError,
+ NotInstalledError,
+ TableAlreadyExistsError,
+)
from pyiceberg.io import FileIO, load_file_io
from pyiceberg.manifest import ManifestFile
from pyiceberg.partitioning import UNPARTITIONED_PARTITION_SPEC, PartitionSpec
@@ -477,6 +483,18 @@ class Catalog(ABC):
NamespaceAlreadyExistsError: If a namespace with the given name
already exists.
"""
+ def create_namespace_if_not_exists(self, namespace: Union[str,
Identifier], properties: Properties = EMPTY_DICT) -> None:
+ """Create a namespace if it does not exist.
+
+ Args:
+ namespace (str | Identifier): Namespace identifier.
+ properties (Properties): A string dictionary of properties for the
given namespace.
+ """
+ try:
+ self.create_namespace(namespace, properties)
+ except NamespaceAlreadyExistsError:
+ pass
+
@abstractmethod
def drop_namespace(self, namespace: Union[str, Identifier]) -> None:
"""Drop a namespace.
diff --git a/tests/catalog/integration_test_dynamodb.py
b/tests/catalog/integration_test_dynamodb.py
index 5b9584c6..05d51bb0 100644
--- a/tests/catalog/integration_test_dynamodb.py
+++ b/tests/catalog/integration_test_dynamodb.py
@@ -184,6 +184,12 @@ def test_create_duplicate_namespace(test_catalog: Catalog,
database_name: str) -
test_catalog.create_namespace(database_name)
+def test_create_namepsace_if_not_exists(test_catalog: Catalog, database_name:
str) -> None:
+ test_catalog.create_namespace(database_name)
+ test_catalog.create_namespace_if_not_exists(database_name)
+ assert (database_name,) in test_catalog.list_namespaces()
+
+
def test_create_namespace_with_comment_and_location(test_catalog: Catalog,
database_name: str) -> None:
test_location = get_s3_path(get_bucket_name(), database_name)
test_properties = {
diff --git a/tests/catalog/integration_test_glue.py
b/tests/catalog/integration_test_glue.py
index a2c430de..5b4aa587 100644
--- a/tests/catalog/integration_test_glue.py
+++ b/tests/catalog/integration_test_glue.py
@@ -291,6 +291,12 @@ def test_create_duplicate_namespace(test_catalog: Catalog,
database_name: str) -
test_catalog.create_namespace(database_name)
+def test_create_namespace_if_not_exists(test_catalog: Catalog, database_name:
str) -> None:
+ test_catalog.create_namespace(database_name)
+ test_catalog.create_namespace_if_not_exists(database_name)
+ assert (database_name,) in test_catalog.list_namespaces()
+
+
def test_create_namespace_with_comment_and_location(test_catalog: Catalog,
database_name: str) -> None:
test_location = get_s3_path(get_bucket_name(), database_name)
test_properties = {
diff --git a/tests/catalog/test_rest.py b/tests/catalog/test_rest.py
index b8410d68..ec5a6a22 100644
--- a/tests/catalog/test_rest.py
+++ b/tests/catalog/test_rest.py
@@ -500,6 +500,24 @@ def test_create_namespace_200(rest_mock: Mocker) -> None:
RestCatalog("rest", uri=TEST_URI,
token=TEST_TOKEN).create_namespace(namespace)
+def test_create_namespace_if_exists_409(rest_mock: Mocker) -> None:
+ namespace = "examples"
+ rest_mock.post(
+ f"{TEST_URI}v1/namespaces",
+ json={
+ "error": {
+ "message": "Namespace already exists: fokko in warehouse
8bcb0838-50fc-472d-9ddb-8feb89ef5f1e",
+ "type": "AlreadyExistsException",
+ "code": 409,
+ }
+ },
+ status_code=409,
+ request_headers=TEST_HEADERS,
+ )
+
+ RestCatalog("rest", uri=TEST_URI,
token=TEST_TOKEN).create_namespace_if_not_exists(namespace)
+
+
def test_create_namespace_409(rest_mock: Mocker) -> None:
namespace = "examples"
rest_mock.post(
diff --git a/tests/catalog/test_sql.py b/tests/catalog/test_sql.py
index 97965268..efa7b746 100644
--- a/tests/catalog/test_sql.py
+++ b/tests/catalog/test_sql.py
@@ -633,6 +633,20 @@ def test_create_namespace(catalog: SqlCatalog,
database_name: str) -> None:
assert (database_name,) in catalog.list_namespaces()
[email protected](
+ 'catalog',
+ [
+ lazy_fixture('catalog_memory'),
+ lazy_fixture('catalog_sqlite'),
+ ],
+)
+def test_create_namespace_if_not_exists(catalog: SqlCatalog, database_name:
str) -> None:
+ catalog.create_namespace(database_name)
+ assert (database_name,) in catalog.list_namespaces()
+ catalog.create_namespace_if_not_exists(database_name)
+ assert (database_name,) in catalog.list_namespaces()
+
+
@pytest.mark.parametrize(
'catalog',
[