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',
     [

Reply via email to