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 and pickle for optional AST serialization.

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

BytecodeCache 7
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.
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. Fil…
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.

File format (v3, framed): [_FRAMED_MAGIC_V3 (4 B)][code_len (4 B)][marshal(code)] [pc_len (4 B)][pickle(precomputed)?][pickle(ast)?]

Whenprecomputed is None or empty, pc_lenis 0 and the pickle section is omitted. Falls back to v2 format when no precomputed values are present.

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 2
__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

Functions

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