Module

compiler.block_recompile

Block-level recompilation for Kida templates.

When a template changes but only some blocks are affected, this module avoids recompiling the entire template by:

  1. Detecting which named blocks changed (via AST comparison).
  2. Compiling only the changed block functions.
  3. Patching the existing Template's namespace with the new functions.

This enables O(changed_blocks) recompilation instead of O(template) for incremental build pipelines.

Thread Safety:

``detect_block_changes`` is a pure function — safe from any thread.
``recompile_blocks`` mutates a Template's namespace; callers must
ensure the template is not being rendered concurrently during
the patch.  In practice, Bengal's build pipeline serializes
compilation and rendering, so this is safe.

Classes

BlockDelta 5
Describes which blocks changed between two template versions.

Describes which blocks changed between two template versions.

Attributes

Name Type Description
changed frozenset[str]

Block names whose AST content changed.

added frozenset[str]

Block names present in new but not old.

removed frozenset[str]

Block names present in old but not new.

Methods

has_changes 0 bool
True if any blocks were changed, added, or removed.
property
def has_changes(self) -> bool
Returns
bool
all_affected 0 frozenset[str]
Union of changed, added, and removed block names.
property
def all_affected(self) -> frozenset[str]
Returns
frozenset[str]

Functions

collect_blocks 1 dict[str, Block]
Recursively collect all named Block nodes from an AST body. Returns a dict map…
def collect_blocks(nodes: Sequence[Node]) -> dict[str, Block]

Recursively collect all named Block nodes from an AST body.

Returns a dict mapping block name to the Block node.

Parameters
Name Type Description
nodes Sequence[Node]
Returns
dict[str, Block]
_walk_for_blocks 2 None
Walk AST nodes, collecting Block nodes into *out*.
def _walk_for_blocks(nodes: Sequence[Node], out: dict[str, Block]) -> None
Parameters
Name Type Description
nodes Sequence[Node]
out dict[str, Block]
detect_block_changes 2 BlockDelta
Compare two template ASTs and identify changed blocks. Uses frozen-dataclass `…
def detect_block_changes(old_ast: TemplateNode, new_ast: TemplateNode) -> BlockDelta

Compare two template ASTs and identify changed blocks.

Uses frozen-dataclass==for O(1) equality on unchanged subtrees.

Parameters
Name Type Description
old_ast TemplateNode

Previous template AST.

new_ast TemplateNode

New template AST.

Returns
BlockDelta
recompile_blocks 4 frozenset[str]
Recompile only the changed/added blocks and patch the template. Compiles each …
def recompile_blocks(env: Environment, template: Template, new_ast: TemplateNode, delta: BlockDelta) -> frozenset[str]

Recompile only the changed/added blocks and patch the template.

Compiles each affected block into three function variants (standard, streaming, async streaming) and replaces them in the template's namespace. Removed blocks are deleted from the namespace.

Parameters
Name Type Description
env Environment

The Environment (needed for compiler construction).

template Template

The live Template object to patch.

new_ast TemplateNode

The new template AST (source of changed block bodies).

delta BlockDelta

The BlockDelta fromdetect_block_changes.

Returns
frozenset[str]