This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-4088-12d4a9a3ced73da290626bde6019ac2835d5c636
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git

commit e6eb6a93b94c547a5f2b68f5eb68f64a44cc48af
Author: Soumyadyuti Dey <[email protected]>
AuthorDate: Sun Oct 25 03:27:03 2026 +0000

    REST: Preserve view metadata location (#4088)
    
    * REST: preserve view metadata location
    
    * View: clarify metadata location semantics
    
    * View: include metadata location in equality
    
    Match Table.__eq__ and the REST spec, which uses metadata location to detect
    view changes.
    
    Co-authored-by: Copilot App <[email protected]>
    
    ---------
    
    Co-authored-by: Kevin Liu <[email protected]>
    Co-authored-by: Copilot App <[email protected]>
---
 pyiceberg/catalog/rest/__init__.py     |  1 +
 pyiceberg/view/__init__.py             | 10 +++++++++-
 tests/catalog/test_rest.py             |  8 +++++++-
 tests/integration/test_rest_catalog.py |  1 +
 4 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/pyiceberg/catalog/rest/__init__.py 
b/pyiceberg/catalog/rest/__init__.py
index 2b8b4496f..97b2e2350 100644
--- a/pyiceberg/catalog/rest/__init__.py
+++ b/pyiceberg/catalog/rest/__init__.py
@@ -1187,6 +1187,7 @@ class RestCatalog(Catalog):
             identifier=identifier_tuple,
             metadata=view_response.metadata,
             config=view_response.config,
+            metadata_location=view_response.metadata_location,
         )
 
     def _refresh_token(self) -> None:
diff --git a/pyiceberg/view/__init__.py b/pyiceberg/view/__init__.py
index 4f298e5b6..1f7c0e906 100644
--- a/pyiceberg/view/__init__.py
+++ b/pyiceberg/view/__init__.py
@@ -30,16 +30,20 @@ class View:
     _identifier: Identifier
     metadata: ViewMetadata
     config: dict[str, str]
+    # None when no metadata location is available, such as for directly 
constructed views.
+    metadata_location: str | None
 
     def __init__(
         self,
         identifier: Identifier,
         metadata: ViewMetadata,
         config: dict[str, str] = EMPTY_DICT,
+        metadata_location: str | None = None,
     ) -> None:
         self._identifier = identifier
         self.metadata = metadata
         self.config = config
+        self.metadata_location = metadata_location
 
     def name(self) -> Identifier:
         """Return the identifier of this view."""
@@ -92,4 +96,8 @@ class View:
 
     def __eq__(self, other: Any) -> bool:
         """Return the equality of two instances of the View class."""
-        return self.name() == other.name() and self.metadata == other.metadata 
if isinstance(other, View) else False
+        return (
+            self.name() == other.name() and self.metadata == other.metadata 
and self.metadata_location == other.metadata_location
+            if isinstance(other, View)
+            else False
+        )
diff --git a/tests/catalog/test_rest.py b/tests/catalog/test_rest.py
index 4877ee2f7..b1b46e467 100644
--- a/tests/catalog/test_rest.py
+++ b/tests/catalog/test_rest.py
@@ -1799,6 +1799,7 @@ def test_create_view_200(rest_mock: Mocker, 
table_schema_simple: Schema, example
     expected = View(
         identifier=("fokko", "fokko2"),
         metadata=ViewMetadata(**example_view_metadata_rest_json["metadata"]),
+        metadata_location=example_view_metadata_rest_json["metadata-location"],
     )
     assert actual == expected
     assert actual.config == example_view_metadata_rest_json["config"]
@@ -1846,7 +1847,11 @@ def test_load_view_200(rest_mock: Mocker, 
example_view_metadata_rest_json: dict[
     )
     catalog = RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN)
     actual = catalog.load_view(("fokko", "view"))
-    expected = View(identifier=("fokko", "view"), 
metadata=ViewMetadata(**example_view_metadata_rest_json["metadata"]))
+    expected = View(
+        identifier=("fokko", "view"),
+        metadata=ViewMetadata(**example_view_metadata_rest_json["metadata"]),
+        metadata_location=example_view_metadata_rest_json["metadata-location"],
+    )
     assert actual == expected
     assert actual.config == example_view_metadata_rest_json["config"]
 
@@ -2806,6 +2811,7 @@ def test_register_view_200(rest_mock: Mocker, 
example_view_metadata_rest_json: d
     expected = View(
         identifier=("default", "registered_view"),
         metadata=ViewMetadata(**example_view_metadata_rest_json["metadata"]),
+        metadata_location=example_view_metadata_rest_json["metadata-location"],
     )
     assert actual == expected
     assert actual.config == example_view_metadata_rest_json["config"]
diff --git a/tests/integration/test_rest_catalog.py 
b/tests/integration/test_rest_catalog.py
index 05039a982..1705dcfb2 100644
--- a/tests/integration/test_rest_catalog.py
+++ b/tests/integration/test_rest_catalog.py
@@ -92,6 +92,7 @@ def test_load_view(catalog: RestCatalog, table_schema_nested: 
Schema, database_n
     )
     view = catalog.create_view(identifier, table_schema_nested, 
view_version=view_version)
     loaded_view = catalog.load_view(identifier)
+    assert view.metadata_location is not None
     assert view == loaded_view
 
 

Reply via email to