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-4152-e6eb6a93b94c547a5f2b68f5eb68f64a44cc48af in repository https://gitbox.apache.org/repos/asf/iceberg-python.git
commit 5becad1aefcc7de7767d2aa30cef07b48c61aff3 Author: Kevin Liu <[email protected]> AuthorDate: Sun Oct 25 04:00:43 2026 +0000 REST: Require metadata-location in view responses (#4152) Require metadata-location in REST view responses The REST spec marks metadata-location as required in LoadViewResult, and Java's LoadViewResponseParser rejects responses without it. Make ViewResponse.metadata_location required to match. Behavior change: create_view, load_view, and register_view now raise a pydantic ValidationError for non-compliant servers that omit metadata-location, instead of silently accepting the response. Co-authored-by: Copilot App <[email protected]> --- pyiceberg/catalog/rest/__init__.py | 2 +- tests/catalog/test_rest.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pyiceberg/catalog/rest/__init__.py b/pyiceberg/catalog/rest/__init__.py index 97b2e2350..80f853f01 100644 --- a/pyiceberg/catalog/rest/__init__.py +++ b/pyiceberg/catalog/rest/__init__.py @@ -361,7 +361,7 @@ class LoadCredentialsResponse(IcebergBaseModel): class ViewResponse(IcebergBaseModel): - metadata_location: str | None = Field(alias="metadata-location", default=None) + metadata_location: str = Field(..., alias="metadata-location") metadata: ViewMetadata config: Properties = Field(default_factory=dict) diff --git a/tests/catalog/test_rest.py b/tests/catalog/test_rest.py index b1b46e467..e355a6873 100644 --- a/tests/catalog/test_rest.py +++ b/tests/catalog/test_rest.py @@ -26,6 +26,7 @@ from unittest import mock from urllib.parse import parse_qs, urlsplit import pytest +from pydantic import ValidationError from requests import Request from requests.adapters import HTTPAdapter from requests.exceptions import HTTPError @@ -1856,6 +1857,19 @@ def test_load_view_200(rest_mock: Mocker, example_view_metadata_rest_json: dict[ assert actual.config == example_view_metadata_rest_json["config"] +def test_load_view_missing_metadata_location(rest_mock: Mocker, example_view_metadata_rest_json: dict[str, Any]) -> None: + response = {k: v for k, v in example_view_metadata_rest_json.items() if k != "metadata-location"} + rest_mock.get( + f"{TEST_URI}v1/namespaces/fokko/views/view", + json=response, + status_code=200, + request_headers=TEST_HEADERS, + ) + catalog = RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN) + with pytest.raises(ValidationError, match="metadata-location"): + catalog.load_view(("fokko", "view")) + + def test_load_view_404(rest_mock: Mocker) -> None: rest_mock.get( f"{TEST_URI}v1/namespaces/fokko/views/non_existent_view",
