2 min read
pyssg.core.incremental.cache
Caches and cache keys.
Two tiers: MemoryCache (one watch session) and FsCache (cross-run,
write-through, to survive cold starts on large wikis). Only expensive pure
results are cached (rendered HTML, parsed AST, optimized bytes).
The cache key MUST cover every non-pure input that affects the output -- source content, the pipeline code version, the plugin set + their config, and the config keys relevant to the phase. Forgetting one would silently serve stale output, so the rule is: prefer a cache miss over a wrong hit. Stdlib only.
input_aspects_of(phase: Phase) -> tuple[Aspect, ...]
class Cache(Protocol)
A pure key/value store of computed phase results.
Cache.get(self, key: Digest) -> object | None
Cache.set(self, key: Digest, value: object) -> None
class MemoryCache
In-process cache for a single watch session.
MemoryCache.__init__(self) -> None
MemoryCache.get(self, key: Digest) -> object | None
MemoryCache.set(self, key: Digest, value: object) -> None
class FsCache
Persistent write-through cache backed by a directory.
A small in-memory layer fronts the disk so repeated hits in one session do
not re-read files. set writes both (write-through), so values survive
across runs to cure cold-start cost on large sites.
FsCache.__init__(self, cache_dir: Path) -> None
FsCache.get(self, key: Digest) -> object | None
FsCache.set(self, key: Digest, value: object) -> None
cache_key(node: Node, phase: Phase, build: Build) -> Digest
Cover every non-pure input affecting node's phase output.
cached(build: Build, key: Digest, compute: Callable[[], T]) -> T
Return a cached result for key or compute, cache and return it.
compute MUST be pure in everything folded into key -- reading an
undeclared input here is the classic way to corrupt incremental builds.
cached_or_compute(build: Build, node: Node, phase: Phase, compute: Callable[[], T]) -> T
Like :func:cached, deriving the key from a node's phase inputs.