""" cache.py — import this before anything else in a test file to enable file-based caching of fetch_json and fetch_soup calls. Cache is stored in tests/cache/ keyed by a hash of the URL + params. Delete the cache directory to bust it. """ import hashlib import json import pickle from pathlib import Path CACHE_DIR = Path(__file__).parent / "cache" CACHE_DIR.mkdir(exist_ok=True) def _key(url: str, params: dict[str,str] | None) -> str: raw = json.dumps({"url": url, "params": params or {}}, sort_keys=True) return hashlib.sha256(raw.encode()).hexdigest() def _patch(): import adapters.api as api_mod import adapters.ssr as ssr_mod _orig_fetch_json = api_mod.fetch_json _orig_fetch_soup = ssr_mod.fetch_soup def cached_fetch_json(url, *, params: dict[str,str]|None=None, headers=None): path = CACHE_DIR / (_key(url, params) + ".json") if path.exists(): print(f"[cache hit] {url}") return json.loads(path.read_text()) result = _orig_fetch_json(url, params=params, headers=headers) path.write_text(json.dumps(result)) return result def cached_fetch_soup(url, *, params=None): path = CACHE_DIR / (_key(url, params) + ".pickle") if path.exists(): print(f"[cache hit] {url}") return pickle.loads(path.read_bytes()) result = _orig_fetch_soup(url, params=params) path.write_bytes(pickle.dumps(result)) return result api_mod.fetch_json = cached_fetch_json ssr_mod.fetch_soup = cached_fetch_soup print("[cache] fetch_json and fetch_soup patched") _patch()