Module

bytecode_cache

Template Bytecode Cache.

Persists compiled template code objects to disk for near-instant cold-start loading. Uses marshal for code object serialization, JSON for compiler-warning facts, and pickle for optional compiler-owned data.

Cache Invalidation:

Uses source hash in filename. When source changes, hash changes, and old cache entry becomes orphan (cleaned up lazily).

Thread-Safety: File writes use atomic rename pattern to prevent corruption. Multiple processes can safely share the cache directory.

Example:

>>> from pathlib import Path
>>> from kida.bytecode_cache import BytecodeCache, hash_source
>>>
>>> cache = BytecodeCache(Path(".kida-cache"))
>>>
>>> # Check cache
>>> code, ast, precomputed = cache.get("base.html", source_hash)
>>> if code is None:
...     code = compile_template(source)
...     cache.set("base.html", source_hash, code)
>>>
>>> # Cache stats
>>> stats = cache.stats()
>>> print(f"Cached: {stats['file_count']} templates")

Classes

_CachedArtifact 4
One validated cache record, including private diagnostic metadata.

One validated cache record, including private diagnostic metadata.

Attributes

Name Type Description
code CodeType
ast Node | None
precomputed list | None
compiler_warnings tuple[TemplateWarning, ...] | None
BytecodeCache 9
Persist compiled template bytecode to disk. Uses marshal for code object serialization (Python std…

Persist compiled template bytecode to disk.

Uses marshal for code object serialization (Python stdlib).

Thread-Safety: File writes use atomic rename pattern to prevent corruption. Multiple processes can safely share the cache directory.

Cache Invalidation: Uses source hash in filename. When source changes, hash changes, and old cache entry becomes orphan (cleaned up lazily).

Methods

get 3 tuple[CodeType, Node | N…
Load cached bytecode, optional AST, and precomputed constants. **The cache fil…
def get(self, name: str, source_hash: str, *, context_hash: str | None = None) -> tuple[CodeType, Node | None, list | None] | tuple[None, None, None]

Load cached bytecode, optional AST, and precomputed constants.

The cache file may contain either:

  • Legacy format: raw marshal-encoded code object only.
  • v2 format:_FRAMED_MAGICsentinel, code length, code, optional AST.
  • v3 format:_FRAMED_MAGIC_V3sentinel, code length, code, precomputed length, precomputed constants, optional AST.
  • v4 format:_FRAMED_MAGIC_V4sentinel plus a length-delimited compiler-warning metadata section before the optional AST.
Parameters
Name Type Description
name

Template name

source_hash

Hash of template source (for invalidation)

context_hash Default:None
Returns
tuple[CodeType, Node | None, list | None] | tuple[None, None, None] ``(code, ast, precomputed)`` on a cache hit — ``ast`` and ``precomputed`` may be ``None``. Returns ``(None, None, None)`` on a cache miss or read error.
set 6
Cache compiled bytecode, optional precomputed constants, and optional AST. The…
def set(self, name: str, source_hash: str, code: CodeType, *, context_hash: str | None = None, ast: Node | None = None, precomputed: list | None = None) -> None

Cache compiled bytecode, optional precomputed constants, and optional AST.

The public method preserves its established signature and stores an empty compiler-warning section. Environment compilation uses the private artifact writer to persist its immutable warning facts.

Parameters
Name Type Description
name

Template name

source_hash

Hash of template source

code

Compiled code object

context_hash Default:None
ast

Optimised AST root node (optional).

Default:None
precomputed

Non-constant-safe values folded by partial eval.

Default:None
clear 1 int
Remove cached bytecode.
def clear(self, current_version_only: bool = False) -> int
Parameters
Name Type Description
current_version_only

If True, only clear current Python version's cache

Default:False
Returns
int Number of files removed
cleanup 1 int
Remove orphaned cache files older than max_age_days. Orphaned files are cache …
def cleanup(self, max_age_days: int = 30) -> int

Remove orphaned cache files older than max_age_days.

Orphaned files are cache entries that are no longer referenced by active templates (e.g., after source changes or template deletion).

Parameters
Name Type Description
max_age_days

Maximum age in days before removal (default: 30)

Default:30
Returns
int Number of files removed
stats 0 dict[str, int]
Get cache statistics.
def stats(self) -> dict[str, int]
Returns
dict[str, int] Dict with file_count, total_bytes
Internal Methods 4
__init__ 2
Initialize bytecode cache.
def __init__(self, directory: Path, pattern: str = '__kida_{version}_{name}_{hash}.pyc')
Parameters
Name Type Description
directory

Cache directory (created if missing)

pattern

Filename pattern with {version}, {name}, {hash} placeholders

Default:'__kida_{version}_{name}_{hash}.pyc'
_make_path 3 Path
Generate cache file path. Includes Python version in filename to prevent cross…
def _make_path(self, name: str, source_hash: str, context_hash: str | None = None) -> Path

Generate cache file path.

Includes Python version in filename to prevent cross-version bytecode incompatibility (marshal format is version-specific).

Parameters
Name Type Description
name
source_hash
context_hash Default:None
Returns
Path
_get_artifact 3 _CachedArtifact | None
Load one cache artifact with private compiler-warning metadata.
def _get_artifact(self, name: str, source_hash: str, *, context_hash: str | None = None) -> _CachedArtifact | None
Parameters
Name Type Description
name
source_hash
context_hash Default:None
Returns
_CachedArtifact | None
_set_artifact 7
Atomically store a v4 artifact and its compiler-warning facts.
def _set_artifact(self, name: str, source_hash: str, code: CodeType, *, context_hash: str | None = None, ast: Node | None = None, precomputed: list | None = None, compiler_warnings: tuple[TemplateWarning, ...]) -> None
Parameters
Name Type Description
name
source_hash
code
context_hash Default:None
ast Default:None
precomputed Default:None
compiler_warnings

Functions

_discard_cache_path 1 None
Best-effort removal for an invalid cache artifact.
def _discard_cache_path(path: Path) -> None
Parameters
Name Type Description
path Path
_load_optional_ast 3 object
Load an optional AST, distinguishing incompatible shapes from absence.
def _load_optional_ast(data: bytes, *, name: str, format_name: str) -> object
Parameters
Name Type Description
data bytes
name str
format_name str
Returns
object
_serialize_compiler_warnings 1 bytes
Serialize immutable warning facts without pickling Python classes.
def _serialize_compiler_warnings(warnings: tuple[TemplateWarning, ...]) -> bytes
Parameters
Name Type Description
warnings tuple[TemplateWarning, ...]
Returns
bytes
_deserialize_compiler_warnings 1 tuple[TemplateWarning, .…
Validate and reconstruct compiler warnings in stored source order.
def _deserialize_compiler_warnings(data: bytes) -> tuple[TemplateWarning, ...]
Parameters
Name Type Description
data bytes
Returns
tuple[TemplateWarning, ...]
hash_source 1 str
Generate hash of template source for cache key.
def hash_source(source: str) -> str
Parameters
Name Type Description
source str
Returns
str
_cached_ast_is_compatible 1 bool
Return True when an unpickled AST matches the current dataclass shape.
def _cached_ast_is_compatible(ast: object) -> bool
Parameters
Name Type Description
ast object
Returns
bool