From 9377d82f4d6494d104614eda5d3ef896950b526d Mon Sep 17 00:00:00 2001 From: Yuya Ebihara Date: Sat, 16 May 2026 10:57:56 +0900 Subject: [PATCH] REST: Add support for page-size in list_views --- pyiceberg/catalog/rest/__init__.py | 12 ++++++++- tests/catalog/test_rest.py | 43 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/pyiceberg/catalog/rest/__init__.py b/pyiceberg/catalog/rest/__init__.py index 7fa81312d1..e18752be93 100644 --- a/pyiceberg/catalog/rest/__init__.py +++ b/pyiceberg/catalog/rest/__init__.py @@ -262,6 +262,8 @@ class IdentifierKind(Enum): VIEW_ENDPOINTS_SUPPORTED = "view-endpoints-supported" VIEW_ENDPOINTS_SUPPORTED_DEFAULT = False +PAGE_SIZE = "rest-page-size" + NAMESPACE_SEPARATOR_PROPERTY = "namespace-separator" DEFAULT_NAMESPACE_SEPARATOR = b"\x1f".decode(UTF8) @@ -1126,12 +1128,20 @@ def list_views(self, namespace: str | Identifier) -> list[Identifier]: namespace_tuple = self._check_valid_namespace_identifier(namespace) namespace_concat = self._encode_namespace_path(namespace_tuple) url = self.url(Endpoints.list_views, namespace=namespace_concat) + params = {} + page_size = property_as_int(self.properties, PAGE_SIZE, None) + if page_size is not None: + if page_size <= 0: + raise ValueError(f"{PAGE_SIZE} must be a positive integer") + params["pageSize"] = str(page_size) views: list[Identifier] = [] page_token: str | None = None while True: - params = {"pageToken": page_token} if page_token else None + if page_token: + params["pageToken"] = page_token + response = self._session.get(url, params=params) try: response.raise_for_status() diff --git a/tests/catalog/test_rest.py b/tests/catalog/test_rest.py index 2adfe9f06e..c86152107c 100644 --- a/tests/catalog/test_rest.py +++ b/tests/catalog/test_rest.py @@ -35,6 +35,7 @@ DEFAULT_ENDPOINTS, EMPTY_BODY_SHA256, OAUTH2_SERVER_URI, + PAGE_SIZE, SIGV4_MAX_RETRIES, SIGV4_MAX_RETRIES_DEFAULT, SNAPSHOT_LOADING_MODE, @@ -725,6 +726,48 @@ def test_list_views_paginated_200_none_next_page_token(rest_mock: Mocker) -> Non ] +def test_list_views_page_size(rest_mock: Mocker) -> None: + namespace = "examples" + rest_mock.get( + f"{TEST_URI}v1/namespaces/{namespace}/views", + json={ + "identifiers": [ + {"namespace": ["examples"], "name": "view1"}, + {"namespace": ["examples"], "name": "view2"}, + ], + }, + status_code=200, + request_headers=TEST_HEADERS, + ) + + result = RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN, **{PAGE_SIZE: "100"}).list_views(namespace) + assert rest_mock.last_request.url == f"{TEST_URI}v1/namespaces/examples/views?pageSize=100" + + assert result == [ + ("examples", "view1"), + ("examples", "view2"), + ] + + +def test_list_views_invalid_page_size(rest_mock: Mocker) -> None: + namespace = "examples" + rest_mock.get( + f"{TEST_URI}v1/namespaces/{namespace}/views", + json={ + "identifiers": [ + {"namespace": ["examples"], "name": "view1"}, + {"namespace": ["examples"], "name": "view2"}, + ], + }, + status_code=200, + request_headers=TEST_HEADERS, + ) + + with pytest.raises(ValueError) as e: + RestCatalog("rest", uri=TEST_URI, token=TEST_TOKEN, **{PAGE_SIZE: "0"}).list_views(namespace) + assert str(e.value) == "rest-page-size must be a positive integer" + + def test_list_views_200_sigv4(rest_mock: Mocker) -> None: namespace = "examples" rest_mock.get(