From 154c483fb14de166e1e5439078a477ced36347bd Mon Sep 17 00:00:00 2001 From: mountain Date: Tue, 7 Jul 2026 15:48:49 +0800 Subject: [PATCH] fix(cloud_api): restore legacy is_retrieval_ready swallow-on-error contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For faithful 0.2.x cloud SDK drop-in compatibility, is_retrieval_ready again swallows PageIndexAPIError and returns False (instead of raising), so existing `while not is_retrieval_ready(...)` polling loops behave exactly as before. Documented that this can loop forever on a permanent error — that is the legacy contract; callers guard their own loops. (The new SDK's own indexing path doesn't use this method — it polls document status with a bounded 120-attempt cap — so the infinite-loop risk is confined to legacy-SDK usage that already had it.) Test updated to assert the swallow behavior. Claude-Session: https://claude.ai/code/session_01Kx5DgKbhK1N8autqXH8SmS --- pageindex/cloud_api.py | 16 ++++++++++------ tests/test_legacy_sdk_contract.py | 9 ++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pageindex/cloud_api.py b/pageindex/cloud_api.py index ae8dd67..a4b1039 100644 --- a/pageindex/cloud_api.py +++ b/pageindex/cloud_api.py @@ -93,13 +93,17 @@ class LegacyCloudAPI: def is_retrieval_ready(self, doc_id: str) -> bool: """Return whether retrieval is ready for ``doc_id``. - API failures (revoked key, network down, unknown doc) propagate as - PageIndexAPIError instead of reading as "not ready" — swallowing them - turned ``while not is_retrieval_ready(...)`` polling loops into - infinite loops. + Faithfully matches the 0.2.x cloud SDK: API errors are swallowed and + reported as "not ready" (False) so existing + ``while not is_retrieval_ready(...)`` polling loops behave identically. + Note this can loop forever on a permanent error (revoked key, deleted + doc) — that is the legacy contract; guard the loop yourself if needed. """ - result = self.get_tree(doc_id) - return result.get("retrieval_ready", False) + try: + result = self.get_tree(doc_id) + return result.get("retrieval_ready", False) + except PageIndexAPIError: + return False def submit_query(self, doc_id: str, query: str, thinking: bool = False) -> dict[str, Any]: payload = { diff --git a/tests/test_legacy_sdk_contract.py b/tests/test_legacy_sdk_contract.py index 6b69e3a..2471f1c 100644 --- a/tests/test_legacy_sdk_contract.py +++ b/tests/test_legacy_sdk_contract.py @@ -326,15 +326,14 @@ def test_empty_api_key_warns_and_falls_back_to_local(caplog, tmp_path, monkeypat assert client._legacy_cloud_api is None -def test_is_retrieval_ready_propagates_api_errors(monkeypatch): - """Regression: API failures (revoked key etc.) were swallowed as False, - turning `while not is_retrieval_ready(...)` into an infinite poll.""" +def test_is_retrieval_ready_swallows_errors_like_legacy_sdk(monkeypatch): + """Faithful 0.2.x contract: API errors are swallowed and reported as + "not ready" (False), so existing polling loops behave identically.""" def fake_request(method, url, **kwargs): return FakeResponse(status_code=401, text="invalid api key") monkeypatch.setattr("pageindex.cloud_api.requests.request", fake_request) - with pytest.raises(PageIndexAPIError): - PageIndexClient("pi-test").is_retrieval_ready("doc-1") + assert PageIndexClient("pi-test").is_retrieval_ready("doc-1") is False def test_legacy_urls_encode_special_char_ids(monkeypatch):