Classes
Compiler
47
▼
Compile Kida AST to Python code objects.
The Compiler transforms a Kida Template AST into an `ast.…
Compiler
47
▼
Compile Kida AST to Python code objects.
The Compiler transforms a Kida Template AST into anast.Module, then
compiles it to a code object ready forexec(). The generated code
defines arender(ctx, _blocks=None)function.
Node Dispatch:
Uses O(1) dict lookup for node type → handler:
python dispatch = { "Data": self._compile_data, "Output": self._compile_output, "If": self._compile_if, ... } handler = dispatch[type(node).__name__]
Line Tracking:
For nodes that can cause runtime errors (Output, For, If, etc.),
generates_get_render_ctx().line = Nbefore the node's code.
This updates the ContextVar-stored RenderContext instead of polluting
the user's ctx dict, enabling rich error messages with source line
numbers while keeping user context clean.
Attributes
| Name | Type | Description |
|---|---|---|
_NODE_DISPATCH_NAMES |
ClassVar[dict[str, str]]
|
— |
_class_dispatch |
ClassVar[dict[str, Callable] | None]
|
— |
_last_block_compiled_stmts |
list[ast.stmt] | None
|
— |
_env |
— |
Parent Environment (for filter/test access) |
_name |
str | None
|
Template name for error messages |
_filename |
str | None
|
Source file path for compile() |
_locals |
set[str]
|
Set of local variable names (loop vars, macro args) |
_blocks |
dict[str, Block | Region]
|
Dict of block_name → Block node (for inheritance) |
_block_counter |
int
|
Counter for unique variable names |
Methods
warnings
0
list
▼
Compile-time warnings accumulated during compilation.
property
warnings
0
list
▼
def warnings(self) -> list
Returns
list
precomputed
0
list[Any]
▼
Values that must be injected into the exec() namespace as ``_pc_N``.
property
precomputed
0
list[Any]
▼
def precomputed(self) -> list[Any]
Returns
list[Any]
compile
3
types.CodeType
▼
Compile template AST to code object.
compile
3
types.CodeType
▼
def compile(self, node: TemplateNode, name: str | None = None, filename: str | None = None) -> types.CodeType
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Root Template node |
name |
— |
Template name for error messages Default:None
|
filename |
— |
Source filename for error messages Default:None
|
Returns
types.CodeType
Compiled code object ready for exec()
Internal Methods 35 ▼
_ensure_dispatch
0
dict[str, Callable]
▼
Build and cache the class-level dispatch table of unbound functions.
classmethod
_ensure_dispatch
0
dict[str, Callable]
▼
def _ensure_dispatch(cls) -> dict[str, Callable]
Returns
dict[str, Callable]
__init_subclass__
1
▼
__init_subclass__
1
▼
def __init_subclass__(cls, **kwargs: Any) -> None
Parameters
| Name | Type | Description |
|---|---|---|
**kwargs |
— |
__init__
1
▼
__init__
1
▼
def __init__(self, env: Environment)
Parameters
| Name | Type | Description |
|---|---|---|
env |
— |
_emit_warning
4
▼
Record a compile-time warning.
_emit_warning
4
▼
def _emit_warning(self, code, message: str, *, lineno: int | None = None, suggestion: str | None = None) -> None
Parameters
| Name | Type | Description |
|---|---|---|
code |
— |
|
message |
— |
|
lineno |
— |
Default:None
|
suggestion |
— |
Default:None
|
_get_literal_extends_target
1
str | None
▼
Return literal extends target if template uses {% extends "literal" %}, else No…
_get_literal_extends_target
1
str | None
▼
def _get_literal_extends_target(self, node: TemplateNode) -> str | None
Return literal extends target if template uses {% extends "literal" %}, else None.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
str | None
_collect_blocks
1
▼
Recursively collect all Block nodes from the AST.
This ensures nested blocks (…
_collect_blocks
1
▼
def _collect_blocks(self, nodes: Sequence[Node]) -> None
Recursively collect all Block nodes from the AST.
This ensures nested blocks (blocks inside blocks, blocks inside conditionals, etc.) are all registered for compilation.
Parameters
| Name | Type | Description |
|---|---|---|
nodes |
— |
_emit_output
1
ast.stmt
▼
Generate output statement: yield (streaming) or _append (StringBuilder).
All o…
_emit_output
1
ast.stmt
▼
def _emit_output(self, value_expr: ast.expr) -> ast.stmt
Generate output statement: yield (streaming) or _append (StringBuilder).
All output generation in compiled templates flows through this method, allowing the compiler to switch between StringBuilder and generator modes.
Parameters
| Name | Type | Description |
|---|---|---|
value_expr |
— |
Returns
ast.stmt
_compile_template
1
ast.Module
▼
Generate Python module from template.
Produces both StringBuilder functions (r…
_compile_template
1
ast.Module
▼
def _compile_template(self, node: TemplateNode) -> ast.Module
Generate Python module from template.
Produces both StringBuilder functions (render, block) and generator functions (render_stream, block_stream) in a single module. The StringBuilder path is used by Template.render() and the generator path by Template.render_stream().
When async constructs are detected (AsyncFor, Await), also generates async generator functions (render_stream_async, block*_stream_async).
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
ast.Module
_make_globals_setup
1
ast.FunctionDef | None
▼
Generate _globals_setup(ctx) from {% globals %}, {% imports %}, and top-level i…
_make_globals_setup
1
ast.FunctionDef | None
▼
def _make_globals_setup(self, node: TemplateNode) -> ast.FunctionDef | None
Generate _globals_setup(ctx) from {% globals %}, {% imports %}, and top-level imports.
Scans the template body for:
- Top-level FromImport and Import nodes (so render_block has macros in scope)
- Globals and Imports nodes (macros/variables for block context)
This function is called by render_block() to inject macros and variables into the block's context. Returns None if neither globals nor top-level imports exist.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
ast.FunctionDef | None
_make_runtime_preamble
9
list[ast.stmt]
▼
Build shared runtime locals preamble for generated functions.
_make_runtime_preamble
9
list[ast.stmt]
▼
def _make_runtime_preamble(self, *, include_blocks_guard: bool = False, include_scope_stack: bool = False, include_escape_str: bool = False, include_getattr: bool = False, include_buf_append: bool = False, include_acc: bool = False, acc_none: bool = False, include_lookup_scope: bool = False, include_render_ctx: bool = False) -> list[ast.stmt]
Parameters
| Name | Type | Description |
|---|---|---|
include_blocks_guard |
— |
Default:False
|
include_scope_stack |
— |
Default:False
|
include_escape_str |
— |
Default:False
|
include_getattr |
— |
Default:False
|
include_buf_append |
— |
Default:False
|
include_acc |
— |
Default:False
|
acc_none |
— |
Default:False
|
include_lookup_scope |
— |
Default:False
|
include_render_ctx |
— |
Default:False
|
Returns
list[ast.stmt]
_make_block_preamble
1
list[ast.stmt]
▼
Common setup stmts for block functions.
Non-streaming adds buf and _append for…
_make_block_preamble
1
list[ast.stmt]
▼
def _make_block_preamble(self, streaming: bool) -> list[ast.stmt]
Common setup stmts for block functions.
Non-streaming adds buf and _append for StringBuilder.
Parameters
| Name | Type | Description |
|---|---|---|
streaming |
— |
Returns
list[ast.stmt]
_build_region_keywords
1
tuple[list[str], list[as…
▼
Build param_names and keywords for region block delegation.
Returns (param_nam…
_build_region_keywords
1
tuple[list[str], list[as…
▼
def _build_region_keywords(self, region_node: Region) -> tuple[list[str], list[ast.keyword]]
Build param_names and keywords for region block delegation.
Returns (param_names, keywords) where keywords includes both the per-param entries and the trailing _outer_ctx / _blocks keywords.
Parameters
| Name | Type | Description |
|---|---|---|
region_node |
— |
Returns
tuple[list[str], list[ast.keyword]]
_make_region_block_function
2
ast.FunctionDef
▼
Generate block wrapper that delegates to region callable with ctx params.
_make_region_block_function
2
ast.FunctionDef
▼
def _make_region_block_function(self, name: str, region_node: Region) -> ast.FunctionDef
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
region_node |
— |
Returns
ast.FunctionDef
_has_unconditional_exprs
1
bool
▼
Fast check: does the body have any nodes that produce unconditional Name refs?
…
staticmethod
_has_unconditional_exprs
1
bool
▼
def _has_unconditional_exprs(body: Sequence) -> bool
Fast check: does the body have any nodes that produce unconditional Name refs?
Returns False when every top-level node is a control-flow node or Data (raw text), meaning CSE analysis would find no unconditional refs and can be skipped entirely.
Parameters
| Name | Type | Description |
|---|---|---|
body |
— |
Returns
bool
_analyze_for_cse
1
set[str]
▼
Combined CSE analysis: returns cacheable variable names.
Performs the fast unc…
_analyze_for_cse
1
set[str]
▼
def _analyze_for_cse(self, body_nodes: Sequence) -> set[str]
Combined CSE analysis: returns cacheable variable names.
Performs the fast unconditional-expression guard check followed by the full variable reference collection in a single call, deduplicating the pattern used across _make_block_function and _make_render_direct_body.
Parameters
| Name | Type | Description |
|---|---|---|
body_nodes |
— |
Returns
set[str]
_collect_var_refs
1
tuple[dict[str, int], se…
▼
Collect variable reference counts and mutated names from Kida AST nodes.
Walks…
staticmethod
_collect_var_refs
1
tuple[dict[str, int], se…
▼
def _collect_var_refs(nodes: Any) -> tuple[dict[str, int], set[str]]
Collect variable reference counts and mutated names from Kida AST nodes.
Walks the AST recursively, collecting mutations from ALL code but only counting Name references in unconditional (non-branching) code paths. This ensures eager cache assignments at function entry won't raise UndefinedError for variables only referenced inside conditional branches.
Does NOT recurse into Block or Def bodies (separate compilation scopes).
Parameters
| Name | Type | Description |
|---|---|---|
nodes |
— |
Returns
tuple[dict[str, int], set[str]]
(ref_counts, mutated) where ref_counts maps var name to usage count
in unconditional code, and mutated is the set of names assigned
anywhere in the body.
_emit_cache_assignments
1
list[ast.stmt]
▼
Emit _cv_name = _ls(ctx, _scope_stack, 'name') for each cached variable.
_emit_cache_assignments
1
list[ast.stmt]
▼
def _emit_cache_assignments(self, names: set[str]) -> list[ast.stmt]
Parameters
| Name | Type | Description |
|---|---|---|
names |
— |
Returns
list[ast.stmt]
_is_append_constant
1
str | None
▼
If *stmt* is ``_append()``, return the string; else None.
staticmethod
_is_append_constant
1
str | None
▼
def _is_append_constant(stmt: ast.stmt) -> str | None
Parameters
| Name | Type | Description |
|---|---|---|
stmt |
— |
Returns
str | None
_is_line_tracking
1
bool
▼
Return True if *stmt* is ``_rc.line = N`` (render-context line tracking).
staticmethod
_is_line_tracking
1
bool
▼
def _is_line_tracking(stmt: ast.stmt) -> bool
Parameters
| Name | Type | Description |
|---|---|---|
stmt |
— |
Returns
bool
_is_single_append_expr
1
ast.expr | None
▼
If *stmt* is ``_append(expr)``, return *expr*; else None.
staticmethod
_is_single_append_expr
1
ast.expr | None
▼
def _is_single_append_expr(stmt: ast.stmt) -> ast.expr | None
Parameters
| Name | Type | Description |
|---|---|---|
stmt |
— |
Returns
ast.expr | None
_make_block_function
2
ast.FunctionDef
▼
Generate a block function: _block_name(ctx, _blocks) -> str.
Also stores the r…
_make_block_function
2
ast.FunctionDef
▼
def _make_block_function(self, name: str, block_node: Block | Region) -> ast.FunctionDef
Generate a block function: _block_name(ctx, _blocks) -> str.
Also stores the raw compiled stmts in_last_block_compiled_stmts
so the stream variant can be derived without recompiling the Kida AST.
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
block_node |
— |
Returns
ast.FunctionDef
_make_render_preamble
0
list[ast.stmt]
▼
Shared init block for render functions: if _blocks, _scope_stack, _acc.
_make_render_preamble
0
list[ast.stmt]
▼
def _make_render_preamble(self) -> list[ast.stmt]
Returns
list[ast.stmt]
_make_render_extends_body
5
list[ast.stmt]
▼
Top-level statements, block registration, and extends return/yield.
_make_render_extends_body
5
list[ast.stmt]
▼
def _make_render_extends_body(self, node: TemplateNode, extends_node: Extends, block_names: dict[str, Block | Region], block_suffix: str, extends_helper: str) -> list[ast.stmt]
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
|
extends_node |
— |
|
block_names |
— |
|
block_suffix |
— |
|
extends_helper |
— |
Returns
list[ast.stmt]
_make_render_direct_body
2
list[ast.stmt]
▼
No-extends path: buf setup (if not streaming), body compile, return vs yield.
_make_render_direct_body
2
list[ast.stmt]
▼
def _make_render_direct_body(self, node: TemplateNode, streaming: bool) -> list[ast.stmt]
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
|
streaming |
— |
Returns
list[ast.stmt]
_make_render_function
1
ast.FunctionDef
▼
Generate the render(ctx, _blocks=None) function.
Optimization: Cache global fu…
_make_render_function
1
ast.FunctionDef
▼
def _make_render_function(self, node: TemplateNode) -> ast.FunctionDef
Generate the render(ctx, _blocks=None) function.
Optimization: Cache global function references as locals for O(1) LOAD_FAST instead of O(1) LOAD_GLOBAL + hash lookup.
For templates with extends:
def render(ctx, _blocks=None):
if _blocks is None: _blocks = {}
# Register child blocks
_blocks.setdefault('name', _block_name)
# Render parent with blocks
return _extends('parent.html', ctx, _blocks)
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
ast.FunctionDef
_make_block_function_stream
2
ast.FunctionDef
▼
Generate a streaming block: _block_name_stream(ctx, _blocks) -> Generator[str].
_make_block_function_stream
2
ast.FunctionDef
▼
def _make_block_function_stream(self, name: str, block_node: Block | Region) -> ast.FunctionDef
Generate a streaming block: _block_name_stream(ctx, _blocks) -> Generator[str].
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
block_node |
— |
Returns
ast.FunctionDef
_make_render_function_stream
2
ast.FunctionDef
▼
Generate render_stream(ctx, _blocks=None) generator function.
For templates wi…
_make_render_function_stream
2
ast.FunctionDef
▼
def _make_render_function_stream(self, node: TemplateNode, blocks: dict[str, Block | Region]) -> ast.FunctionDef
Generate render_stream(ctx, _blocks=None) generator function.
For templates with extends:
yield from _extends_stream('parent.html', ctx, _blocks)
For templates without extends:
yield chunks directly
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
|
blocks |
— |
Returns
ast.FunctionDef
_make_region_block_function_stream
2
ast.FunctionDef
▼
Streaming block wrapper for region — yields callable result.
_make_region_block_function_stream
2
ast.FunctionDef
▼
def _make_region_block_function_stream(self, name: str, region_node: Region) -> ast.FunctionDef
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
region_node |
— |
Returns
ast.FunctionDef
_make_region_block_function_stream_async
2
ast.AsyncFunctionDef
▼
Async streaming block wrapper for region.
_make_region_block_function_stream_async
2
ast.AsyncFunctionDef
▼
def _make_region_block_function_stream_async(self, name: str, region_node: Region) -> ast.AsyncFunctionDef
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
region_node |
— |
Returns
ast.AsyncFunctionDef
_make_block_function_stream_async
2
ast.AsyncFunctionDef
▼
Generate async streaming block: _block_name_stream_async(ctx, _blocks).
Mirror…
_make_block_function_stream_async
2
ast.AsyncFunctionDef
▼
def _make_block_function_stream_async(self, name: str, block_node: Block | Region) -> ast.AsyncFunctionDef
Generate async streaming block: _block_name_stream_async(ctx, _blocks).
Mirrors _make_block_function_stream() but produces an async generator function (async def + yield). Used when the template contains async constructs (AsyncFor, Await).
Part of RFC: rfc-async-rendering.
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
|
block_node |
— |
Returns
ast.AsyncFunctionDef
_make_render_function_stream_async
2
ast.AsyncFunctionDef
▼
Generate async render_stream_async(ctx, _blocks=None) function.
Mirrors _make_…
_make_render_function_stream_async
2
ast.AsyncFunctionDef
▼
def _make_render_function_stream_async(self, node: TemplateNode, blocks: dict[str, Block | Region]) -> ast.AsyncFunctionDef
Generate async render_stream_async(ctx, _blocks=None) function.
Mirrors _make_render_function_stream() but produces an async generator for native async iteration over AsyncFor loops and Await expressions.
For templates with extends:
async for chunk in _extends_stream_async(parent, ctx, _blocks):
yield chunk
For templates without extends:
yield chunks directly via async generator
Part of RFC: rfc-async-rendering.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
|
blocks |
— |
Returns
ast.AsyncFunctionDef
_make_line_marker
1
ast.stmt
▼
Generate RenderContext line update for error tracking.
Generates: _rc.line = l…
_make_line_marker
1
ast.stmt
▼
def _make_line_marker(self, lineno: int) -> ast.stmt
Generate RenderContext line update for error tracking.
Generates: _rc.line = lineno
Uses the cached _rc local (set in preamble) instead of calling _get_render_ctx() per node, avoiding repeated ContextVar.get() calls.
RFC: kida-contextvar-patterns
Parameters
| Name | Type | Description |
|---|---|---|
lineno |
— |
Returns
ast.stmt
_compile_template_context
1
list[ast.stmt]
▼
No-op: TemplateContext is a declaration, not code.
staticmethod
_compile_template_context
1
list[ast.stmt]
▼
def _compile_template_context(_node: Node) -> list[ast.stmt]
Parameters
| Name | Type | Description |
|---|---|---|
_node |
— |
Returns
list[ast.stmt]
_compile_node
1
list[ast.stmt]
▼
Compile a single AST node to Python statements.
Complexity: O(1) type dispatch…
_compile_node
1
list[ast.stmt]
▼
def _compile_node(self, node: Node) -> list[ast.stmt]
Compile a single AST node to Python statements.
Complexity: O(1) type dispatch using class name lookup.
For nodes that can cause runtime errors, injects a line marker statement (ctx['_line'] = N) before the node's code. This enables rich error messages with source line numbers.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
list[ast.stmt]
_get_node_dispatch
0
dict[str, Callable]
▼
Get node type dispatch table.
_get_node_dispatch
0
dict[str, Callable]
▼
def _get_node_dispatch(self) -> dict[str, Callable]
Returns
dict[str, Callable]