Source code for pyphi.cache.policy

"""Cache policy Protocol and adapters.

A ``CachePolicy`` is the uniform observability and control surface across all of PyPhi's
cache flavors: it declares only ``name``, ``info()``, and ``clear()``. ``get`` / ``put``
/ ``key`` are not part of it; their signatures differ across cache flavors.
"""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from typing import Protocol
from typing import runtime_checkable

from .cache_utils import _CacheInfo


[docs] @runtime_checkable class CachePolicy(Protocol): """Uniform observability + control surface for caches. A policy may additionally set a true ``persistent`` attribute to mark itself as a durable store; registry-wide ``clear_all()`` skips those. """ name: str def info(self) -> _CacheInfo: ... def clear(self) -> None: ...
@dataclass class _DictCacheAdapter: """Adapter wrapping a backing dict with externally-tracked hit/miss counts. Used by the module-level ``@cache(...)`` decorator and by ``ContentCache`` instances. The ``stats`` callable returns ``(hits, misses)``; the wrapper closure that updates the counts owns them. The optional ``weigh`` callable returns ``(nbytes, evictions)`` for caches that track occupancy in bytes; caches that do not report zero for both. The optional ``reset`` callable clears the owning cache through its own clear path — resetting its tracked byte weight and any latched admission budget along with the entries, since the purpose of clearing is recovering memory. Without it, ``clear()`` falls back to emptying the backing dict, which suits plain unweighted dicts only. """ name: str backing: dict[Any, Any] stats: Callable[[], tuple[int, int]] weigh: Callable[[], tuple[int, int]] | None = None reset: Callable[[], None] | None = None def info(self) -> _CacheInfo: hits, misses = self.stats() nbytes, evictions = self.weigh() if self.weigh else (0, 0) return _CacheInfo(hits, misses, len(self.backing), nbytes, evictions) def clear(self) -> None: if self.reset is not None: self.reset() else: self.backing.clear()