Three-level incremental AST cache. Parameters ---------- cache_dir : Path, optional Directory for the persistent (L2) disk cache. When *None* only the in-memory (L1) cache is active. If the directory cannot be created, a warning is issued and the cache ope
| 230 | |
| 231 | |
| 232 | class IncrementalAstCache: |
| 233 | """ |
| 234 | Three-level incremental AST cache. |
| 235 | |
| 236 | Parameters |
| 237 | ---------- |
| 238 | cache_dir : Path, optional |
| 239 | Directory for the persistent (L2) disk cache. When *None* only the |
| 240 | in-memory (L1) cache is active. If the directory cannot be created, |
| 241 | a warning is issued and the cache operates in L1-only mode. |
| 242 | max_l1_entries : int |
| 243 | Maximum entries kept in the in-memory LRU cache. Oldest entries are |
| 244 | evicted when the limit is exceeded. Default: 512. |
| 245 | |
| 246 | Usage |
| 247 | ----- |
| 248 | :: |
| 249 | |
| 250 | cache = IncrementalAstCache(cache_dir=Path(".pyspector_cache/ast")) |
| 251 | ast_json = cache.get_ast_json(Path("src/foo.py"), content) |
| 252 | """ |
| 253 | |
| 254 | def __init__( |
| 255 | self, |
| 256 | cache_dir: Optional[Path] = None, |
| 257 | max_l1_entries: int = MAX_L1_ENTRIES, |
| 258 | ) -> None: |
| 259 | self._l1: OrderedDict[str, FileCacheEntry] = OrderedDict() |
| 260 | self._max_l1 = max_l1_entries |
| 261 | self._cache_dir: Optional[Path] = None |
| 262 | if cache_dir: |
| 263 | try: |
| 264 | cache_dir.mkdir(parents=True, exist_ok=True) |
| 265 | self._cache_dir = cache_dir |
| 266 | except OSError as e: |
| 267 | warnings.warn( |
| 268 | f"PySpector: cannot create cache directory {cache_dir!r}: {e}. " |
| 269 | "Disk cache disabled for this run.", |
| 270 | stacklevel=2, |
| 271 | ) |
| 272 | |
| 273 | # ── Public API ─────────────────────────────────────────────────────────── |
| 274 | |
| 275 | def get_ast_json(self, file_path: Path, content: str) -> str: |
| 276 | """ |
| 277 | Return the AST JSON string for *file_path*. |
| 278 | |
| 279 | Raises |
| 280 | ------ |
| 281 | SyntaxError |
| 282 | If the file cannot be parsed, so callers can emit user-facing |
| 283 | warnings while keeping cache logic out of the CLI layer. |
| 284 | """ |
| 285 | return zlib.decompress(self._get_entry(file_path, content).full_ast_json_z).decode() |
| 286 | |
| 287 | def invalidate(self, file_path: Path) -> None: |
| 288 | """Remove all cached data for a single file.""" |
| 289 | key = str(file_path.resolve()) |
no outgoing calls