fix: resolve api_key at request time to restore 0.2.x override semantics

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).
This commit is contained in:
Ray 2026-07-22 12:28:54 +08:00
parent 80493ccf62
commit a9bb019d05
3 changed files with 28 additions and 10 deletions

View file

@ -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()

View file

@ -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,

View file

@ -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