From a9bb019d05c3f48fd7779ebb763ebd9cd839c2cf Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 22 Jul 2026 12:28:54 +0800 Subject: [PATCH] fix: resolve api_key at request time to restore 0.2.x override semantics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0.2.8 stored self.api_key on the client and _headers() re-read it per request, so reading client.api_key and reassigning it after construction both worked. The refactor handed the key to the internal backends and never set it on PageIndexClient: reads raised AttributeError and reassignment silently kept requests on the old key. Same shape as the BASE_URL snapshot fixed in dea211b — apply the same callable-indirection pattern to api_key on both CloudBackend and LegacyCloudAPI (which also stops CloudBackend snapshotting its headers dict at construction). --- pageindex/backend/cloud.py | 15 +++++++++++---- pageindex/client.py | 10 ++++++---- pageindex/cloud_api.py | 13 +++++++++++-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/pageindex/backend/cloud.py b/pageindex/backend/cloud.py index 2827cc7..81c1cde 100644 --- a/pageindex/backend/cloud.py +++ b/pageindex/backend/cloud.py @@ -30,17 +30,24 @@ def _as_int(value): class CloudBackend: - def __init__(self, api_key: str, base_url: str | Callable[[], str] | None = None): + def __init__(self, api_key: str | Callable[[], str], + base_url: str | Callable[[], str] | None = None): self._api_key = api_key self._base_url = base_url or API_BASE - self._headers = {"api_key": api_key} self._folder_id_cache: dict[str, str | None] = {} self._folder_warning_shown = False + @property + def api_key(self) -> str: + return self._api_key() if callable(self._api_key) else self._api_key + @property def base_url(self) -> str: return self._base_url() if callable(self._base_url) else self._base_url + def _headers(self) -> dict[str, str]: + return {"api_key": self.api_key} + # ── HTTP helpers ────────────────────────────────────────────────────── # Folder API statuses meaning "folders are not available on this account" @@ -77,7 +84,7 @@ class CloudBackend: if hasattr(fobj, "seek"): fobj.seek(0) try: - resp = requests.request(method, url, headers=self._headers, **kwargs) + resp = requests.request(method, url, headers=self._headers(), **kwargs) if resp.status_code in (429, 500, 502, 503): last_status = resp.status_code if attempt == retries - 1: @@ -452,7 +459,7 @@ class CloudBackend: ) if not doc_id: raise ValueError("collection has no documents to query") - headers = self._headers + headers = self._headers() base_url = self.base_url # Queue carries QueryEvent, an Exception to re-raise, or None (end). queue: asyncio.Queue[QueryEvent | Exception | None] = asyncio.Queue() diff --git a/pageindex/client.py b/pageindex/client.py index 2d0a222..fac9f65 100644 --- a/pageindex/client.py +++ b/pageindex/client.py @@ -74,11 +74,13 @@ class PageIndexClient: def _init_cloud(self, api_key: str): from .backend.cloud import CloudBackend from .cloud_api import LegacyCloudAPI - # Callable: re-read per request so post-construction BASE_URL - # reassignment (a 0.2.x pattern) still applies. + # Callables: re-read per request so post-construction BASE_URL / + # api_key reassignment (0.2.x patterns) still applies. + self.api_key = api_key base_url = lambda: self.BASE_URL - self._backend = CloudBackend(api_key=api_key, base_url=base_url) - self._legacy_cloud_api = LegacyCloudAPI(api_key=api_key, base_url=base_url) + api_key_ref = lambda: self.api_key + self._backend = CloudBackend(api_key=api_key_ref, base_url=base_url) + self._legacy_cloud_api = LegacyCloudAPI(api_key=api_key_ref, base_url=base_url) def _init_local(self, model: str = None, retrieve_model: str = None, storage_path: str = None, storage=None, diff --git a/pageindex/cloud_api.py b/pageindex/cloud_api.py index 07552a7..b8866ac 100644 --- a/pageindex/cloud_api.py +++ b/pageindex/cloud_api.py @@ -19,10 +19,19 @@ class LegacyCloudAPI: BASE_URL = API_BASE - def __init__(self, api_key: str, base_url: str | Callable[[], str] | None = None): - self.api_key = api_key + def __init__(self, api_key: str | Callable[[], str], + base_url: str | Callable[[], str] | None = None): + self._api_key = api_key self._base_url = base_url or self.BASE_URL + @property + def api_key(self) -> str: + return self._api_key() if callable(self._api_key) else self._api_key + + @api_key.setter + def api_key(self, value: str | Callable[[], str]) -> None: + self._api_key = value + @property def base_url(self) -> str: return self._base_url() if callable(self._base_url) else self._base_url