# bytecode_cache

URL: /kida/api/bytecode_cache/
Section: api
Description: 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")

---

> For a complete page index, fetch /kida/llms.txt.

Open LLM text
(/kida/api/bytecode_cache/index.txt)

Share with AI

Ask Claude
(https://claude.ai/new?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fbytecode_cache%2Findex.txt)

Ask ChatGPT
(https://chatgpt.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fbytecode_cache%2Findex.txt)

Ask Gemini
(https://gemini.google.com/app?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fbytecode_cache%2Findex.txt)

Ask Copilot
(https://copilot.microsoft.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fbytecode_cache%2Findex.txt)

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")
```

1Class2Functions

## 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_MAGIC`sentinel, code length, code, optional AST.

- v3 format:`_FRAMED_MAGIC_V3`sentinel, 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)?]`

When`precomputed` is `None` or empty, `pc_len`is 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`

`_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`
