Skip to content

Commit a268e5b

Browse files
authored
Add create_namespace_if_not_exists method (#725)
1 parent 6d52325 commit a268e5b

File tree

5 files changed

+63
-1
lines changed

5 files changed

+63
-1
lines changed

pyiceberg/catalog/__init__.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@
3636
cast,
3737
)
3838

39-
from pyiceberg.exceptions import NoSuchNamespaceError, NoSuchTableError, NotInstalledError, TableAlreadyExistsError
39+
from pyiceberg.exceptions import (
40+
NamespaceAlreadyExistsError,
41+
NoSuchNamespaceError,
42+
NoSuchTableError,
43+
NotInstalledError,
44+
TableAlreadyExistsError,
45+
)
4046
from pyiceberg.io import FileIO, load_file_io
4147
from pyiceberg.manifest import ManifestFile
4248
from pyiceberg.partitioning import UNPARTITIONED_PARTITION_SPEC, PartitionSpec
@@ -477,6 +483,18 @@ def create_namespace(self, namespace: Union[str, Identifier], properties: Proper
477483
NamespaceAlreadyExistsError: If a namespace with the given name already exists.
478484
"""
479485

486+
def create_namespace_if_not_exists(self, namespace: Union[str, Identifier], properties: Properties = EMPTY_DICT) -> None:
487+
"""Create a namespace if it does not exist.
488+
489+
Args:
490+
namespace (str | Identifier): Namespace identifier.
491+
properties (Properties): A string dictionary of properties for the given namespace.
492+
"""
493+
try:
494+
self.create_namespace(namespace, properties)
495+
except NamespaceAlreadyExistsError:
496+
pass
497+
480498
@abstractmethod
481499
def drop_namespace(self, namespace: Union[str, Identifier]) -> None:
482500
"""Drop a namespace.

tests/catalog/integration_test_dynamodb.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ def test_create_duplicate_namespace(test_catalog: Catalog, database_name: str) -
184184
test_catalog.create_namespace(database_name)
185185

186186

187+
def test_create_namepsace_if_not_exists(test_catalog: Catalog, database_name: str) -> None:
188+
test_catalog.create_namespace(database_name)
189+
test_catalog.create_namespace_if_not_exists(database_name)
190+
assert (database_name,) in test_catalog.list_namespaces()
191+
192+
187193
def test_create_namespace_with_comment_and_location(test_catalog: Catalog, database_name: str) -> None:
188194
test_location = get_s3_path(get_bucket_name(), database_name)
189195
test_properties = {

tests/catalog/integration_test_glue.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,12 @@ def test_create_duplicate_namespace(test_catalog: Catalog, database_name: str) -
291291
test_catalog.create_namespace(database_name)
292292

293293

294+
def test_create_namespace_if_not_exists(test_catalog: Catalog, database_name: str) -> None:
295+
test_catalog.create_namespace(database_name)
296+
test_catalog.create_namespace_if_not_exists(database_name)
297+
assert (database_name,) in test_catalog.list_namespaces()
298+
299+
294300
def test_create_namespace_with_comment_and_location(test_catalog: Catalog, database_name: str) -> None:
295301
test_location = get_s3_path(get_bucket_name(), database_name)
296302
test_properties = {

tests/catalog/test_rest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,24 @@ def test_create_namespace_200(rest_mock: Mocker) -> None:
500500
RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN).create_namespace(namespace)
501501

502502

503+
def test_create_namespace_if_exists_409(rest_mock: Mocker) -> None:
504+
namespace = "examples"
505+
rest_mock.post(
506+
f"{TEST_URI}v1/namespaces",
507+
json={
508+
"error": {
509+
"message": "Namespace already exists: fokko in warehouse 8bcb0838-50fc-472d-9ddb-8feb89ef5f1e",
510+
"type": "AlreadyExistsException",
511+
"code": 409,
512+
}
513+
},
514+
status_code=409,
515+
request_headers=TEST_HEADERS,
516+
)
517+
518+
RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN).create_namespace_if_not_exists(namespace)
519+
520+
503521
def test_create_namespace_409(rest_mock: Mocker) -> None:
504522
namespace = "examples"
505523
rest_mock.post(

tests/catalog/test_sql.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,20 @@ def test_create_namespace(catalog: SqlCatalog, database_name: str) -> None:
633633
assert (database_name,) in catalog.list_namespaces()
634634

635635

636+
@pytest.mark.parametrize(
637+
'catalog',
638+
[
639+
lazy_fixture('catalog_memory'),
640+
lazy_fixture('catalog_sqlite'),
641+
],
642+
)
643+
def test_create_namespace_if_not_exists(catalog: SqlCatalog, database_name: str) -> None:
644+
catalog.create_namespace(database_name)
645+
assert (database_name,) in catalog.list_namespaces()
646+
catalog.create_namespace_if_not_exists(database_name)
647+
assert (database_name,) in catalog.list_namespaces()
648+
649+
636650
@pytest.mark.parametrize(
637651
'catalog',
638652
[

0 commit comments

Comments
 (0)