Skip to content

Commit ef6be83

Browse files
committed
just need to add abstract methods
1 parent 52d810e commit ef6be83

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed

pyiceberg/catalog/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,21 @@ def drop_view(self, identifier: Union[str, Identifier]) -> None:
670670
NoSuchViewError: If a view with the given name does not exist.
671671
"""
672672

673+
@abstractmethod
674+
def rename_view(self, from_identifier: Union[str, Identifier], to_identifier: Union[str, Identifier]) -> None:
675+
"""Rename a fully classified view name.
676+
677+
Args:
678+
from_identifier (str | Identifier): Existing view identifier.
679+
to_identifier (str | Identifier): New view identifier.
680+
681+
Returns:
682+
Table: the updated table instance with its metadata.
683+
684+
Raises:
685+
NoSuchViewError: If a table with the name does not exist.
686+
"""
687+
673688
@staticmethod
674689
def identifier_to_tuple(identifier: Union[str, Identifier]) -> Identifier:
675690
"""Parse an identifier to a tuple.

pyiceberg/catalog/rest/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
NoSuchViewError,
5454
TableAlreadyExistsError,
5555
UnauthorizedError,
56+
ViewAlreadyExistsError,
5657
)
5758
from pyiceberg.io import AWS_ACCESS_KEY_ID, AWS_REGION, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
5859
from pyiceberg.partitioning import UNPARTITIONED_PARTITION_SPEC, PartitionSpec, assign_fresh_partition_spec_ids
@@ -101,6 +102,7 @@ class Endpoints:
101102
list_views: str = "namespaces/{namespace}/views"
102103
drop_view: str = "namespaces/{namespace}/views/{view}"
103104
view_exists: str = "namespaces/{namespace}/views/{view}"
105+
rename_view: str = "views/rename"
104106

105107

106108
class IdentifierKind(Enum):
@@ -877,6 +879,18 @@ def drop_view(self, identifier: Union[str]) -> None:
877879
except HTTPError as exc:
878880
_handle_non_200_response(exc, {404: NoSuchViewError})
879881

882+
@retry(**_RETRY_ARGS)
883+
def rename_view(self, from_identifier: Union[str, Identifier], to_identifier: Union[str, Identifier]) -> None:
884+
payload = {
885+
"source": self._split_identifier_for_json(from_identifier),
886+
"destination": self._split_identifier_for_json(to_identifier),
887+
}
888+
response = self._session.post(self.url(Endpoints.rename_view), json=payload)
889+
try:
890+
response.raise_for_status()
891+
except HTTPError as exc:
892+
_handle_non_200_response(exc, {404: NoSuchViewError, 409: ViewAlreadyExistsError})
893+
880894
def close(self) -> None:
881895
"""Close the catalog and release Session connection adapters.
882896

pyiceberg/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ class NoSuchViewError(Exception):
4444
"""Raises when the view can't be found in the REST catalog."""
4545

4646

47+
class ViewAlreadyExistsError(Exception):
48+
"""Raises when the view being created already exists in the REST catalog."""
49+
50+
4751
class NoSuchIdentifierError(Exception):
4852
"""Raises when the identifier can't be found in the REST catalog."""
4953

tests/catalog/test_rest.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
OAuthError,
3939
ServerError,
4040
TableAlreadyExistsError,
41+
ViewAlreadyExistsError,
4142
)
4243
from pyiceberg.io import load_file_io
4344
from pyiceberg.partitioning import PartitionField, PartitionSpec
@@ -1918,3 +1919,65 @@ def test_rest_catalog_context_manager_with_exception_sigv4(self, rest_mock: Mock
19181919

19191920
assert catalog is not None and hasattr(catalog, "_session")
19201921
assert len(catalog._session.adapters) == self.EXPECTED_ADAPTERS_SIGV4
1922+
1923+
1924+
def test_rename_view_204(rest_mock: Mocker) -> None:
1925+
from_identifier = ("some_namespace", "old_view")
1926+
to_identifier = ("some_namespace", "new_view")
1927+
rest_mock.post(
1928+
f"{TEST_URI}v1/views/rename",
1929+
json={
1930+
"source": {"namespace": ["some_namespace"], "name": "old_view"},
1931+
"destination": {"namespace": ["some_namespace"], "name": "new_view"},
1932+
},
1933+
status_code=204,
1934+
request_headers=TEST_HEADERS,
1935+
)
1936+
catalog = RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN)
1937+
catalog.rename_view(from_identifier, to_identifier)
1938+
assert (
1939+
rest_mock.last_request.text
1940+
== """{"source": {"namespace": ["some_namespace"], "name": "old_view"}, "destination": {"namespace": ["some_namespace"], "name": "new_view"}}"""
1941+
)
1942+
1943+
1944+
def test_rename_view_404(rest_mock: Mocker) -> None:
1945+
from_identifier = ("some_namespace", "non_existent_view")
1946+
to_identifier = ("some_namespace", "new_view")
1947+
rest_mock.post(
1948+
f"{TEST_URI}v1/views/rename",
1949+
json={
1950+
"error": {
1951+
"message": "View does not exist: some_namespace.non_existent_view",
1952+
"type": "NoSuchViewException",
1953+
"code": 404,
1954+
}
1955+
},
1956+
status_code=404,
1957+
request_headers=TEST_HEADERS,
1958+
)
1959+
catalog = RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN)
1960+
with pytest.raises(NoSuchViewError) as exc_info:
1961+
catalog.rename_view(from_identifier, to_identifier)
1962+
assert "View does not exist: some_namespace.non_existent_view" in str(exc_info.value)
1963+
1964+
1965+
def test_rename_view_409(rest_mock: Mocker) -> None:
1966+
from_identifier = ("some_namespace", "old_view")
1967+
to_identifier = ("some_namespace", "existing_view")
1968+
rest_mock.post(
1969+
f"{TEST_URI}v1/views/rename",
1970+
json={
1971+
"error": {
1972+
"message": "View already exists: some_namespace.existing_view",
1973+
"type": "ViewAlreadyExistsException",
1974+
"code": 409,
1975+
}
1976+
},
1977+
status_code=409,
1978+
request_headers=TEST_HEADERS,
1979+
)
1980+
catalog = RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN)
1981+
with pytest.raises(ViewAlreadyExistsError) as exc_info:
1982+
catalog.rename_view(from_identifier, to_identifier)
1983+
assert "View already exists: some_namespace.existing_view" in str(exc_info.value)

0 commit comments

Comments
 (0)