This is an automated email from the ASF dual-hosted git repository.
bugraoz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new a551e03c68e Send `limit` parameter in `execute_list` server requests
(#63048)
a551e03c68e is described below
commit a551e03c68ec8dee23a42db88ae750f1c670953b
Author: leon.jeon <[email protected]>
AuthorDate: Mon Mar 9 21:22:00 2026 +0000
Send `limit` parameter in `execute_list` server requests (#63048)
* Send limit parameter in execute_list server requests
execute_list uses a local limit (default 50) for offset arithmetic
but did not include it in server requests. The server falls back
to its own fallback_page_limit which happens to also default to 50,
so current behavior is correct. However, if the server config
differs, offsets diverge and pages overlap.
Include limit in shared_params so pagination is robust regardless
of server configuration.
Co-Authored-By: claude-flow <[email protected]>
* Update airflow-ctl/tests/airflow_ctl/api/test_operations.py
Co-authored-by: Henry Chen <[email protected]>
---------
Co-authored-by: claude-flow <[email protected]>
Co-authored-by: Henry Chen <[email protected]>
---
airflow-ctl/src/airflowctl/api/operations.py | 2 +-
.../tests/airflow_ctl/api/test_operations.py | 32 ++++++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/airflow-ctl/src/airflowctl/api/operations.py
b/airflow-ctl/src/airflowctl/api/operations.py
index e4a046ed774..445d490c08d 100644
--- a/airflow-ctl/src/airflowctl/api/operations.py
+++ b/airflow-ctl/src/airflowctl/api/operations.py
@@ -164,7 +164,7 @@ class BaseOperations:
limit: int = 50,
params: dict | None = None,
) -> T | ServerResponseError:
- shared_params = {**(params or {})}
+ shared_params = {"limit": limit, **(params or {})}
self.response = self.client.get(path, params=shared_params)
first_pass = data_model.model_validate_json(self.response.content)
total_entries = first_pass.total_entries # type: ignore[attr-defined]
diff --git a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
index 65f058d6656..f75a3c9678f 100644
--- a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
+++ b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
@@ -194,6 +194,38 @@ class TestBaseOperations:
assert expected_response == response
+ def test_execute_list_sends_limit_to_server(self):
+ """``limit`` must be included in request params so the server returns
+ the expected page size. Without it the server uses its own default
+ (e.g. 100) which causes duplicate entries when ``limit`` differs."""
+ mock_client = Mock()
+ mock_client.get.return_value = Mock(
+ content=json.dumps({"hellos": [{"name": "hello"}] * 3,
"total_entries": 3})
+ )
+ base_operation = BaseOperations(client=mock_client)
+
+ base_operation.execute_list(path="hello",
data_model=HelloCollectionResponse, limit=50)
+
+ call_params = mock_client.get.call_args_list[0]
+ assert call_params.kwargs["params"]["limit"] == 50
+
+ def test_execute_list_sends_limit_on_subsequent_pages(self):
+ """Every paginated request must include ``limit`` so that offset
+ arithmetic stays consistent with the actual page size returned."""
+ mock_client = Mock()
+ mock_client.get.side_effect = [
+ Mock(content=json.dumps({"hellos": [{"name": "a"}, {"name": "b"}],
"total_entries": 3})),
+ Mock(content=json.dumps({"hellos": [{"name": "c"}],
"total_entries": 3})),
+ ]
+ base_operation = BaseOperations(client=mock_client)
+
+ response = base_operation.execute_list(path="hello",
data_model=HelloCollectionResponse, limit=2)
+
+ assert len(response.hellos) == 3
+ # Verify limit is sent on both the first and second request
+ for call in mock_client.get.call_args_list:
+ assert call.kwargs["params"]["limit"] == 2
+
class TestAssetsOperations:
asset_id: int = 1