Classes
_LoopProperties
7
▼
Compile-time stand-in for LoopContext properties.
Provides the same attribute names as the runtime…
_LoopProperties
7
▼
Compile-time stand-in for LoopContext properties.
Provides the same attribute names as the runtime LoopContext so that
expressions like{{ loop.index }}resolve during partial evaluation.
Attributes
| Name | Type | Description |
|---|---|---|
index0 |
int
|
— |
index |
int
|
— |
first |
bool
|
— |
last |
bool
|
— |
length |
int
|
— |
revindex |
int
|
— |
revindex0 |
int
|
— |
PartialEvaluator
33
▼
Evaluate static expressions in a Kida AST at compile time.
Walks the template AST and replaces exp…
PartialEvaluator
33
▼
Evaluate static expressions in a Kida AST at compile time.
Walks the template AST and replaces expressions that can be fully resolved from the static context with their computed values.
Methods
evaluate
1
Template
▼
Transform a template AST by evaluating static expressions.
Returns a new Templ…
evaluate
1
Template
▼
def evaluate(self, template: Template) -> Template
Transform a template AST by evaluating static expressions.
Returns a new Template node with static parts replaced by constants. The original template is not modified.
Parameters
| Name | Type | Description |
|---|---|---|
template |
— |
Returns
Template
Internal Methods 32 ▼
__init__
6
▼
__init__
6
▼
def __init__(self, static_context: dict[str, Any], *, escape_func: Any | None = None, pure_filters: frozenset[str] = frozenset(), filter_callables: dict[str, Callable[..., Any]] | None = None, max_eval_depth: int = 100, inline_components: bool = False) -> None
Parameters
| Name | Type | Description |
|---|---|---|
static_context |
— |
|
escape_func |
— |
Default:None
|
pure_filters |
— |
Default:frozenset()
|
filter_callables |
— |
Default:None
|
max_eval_depth |
— |
Default:100
|
inline_components |
— |
Default:False
|
_try_eval
2
Any
▼
Try to evaluate an expression against the static context.
Returns the computed…
_try_eval
2
Any
▼
def _try_eval(self, expr: Expr, depth: int = 0) -> Any
Try to evaluate an expression against the static context.
Returns the computed value on success, or_UNRESOLVEDif the
expression depends on runtime values.
Depth limit prevents stack overflow from deeply nested attribute chains (e.g. a.b.c.d.e... with 500+ levels).
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_try_eval_filter
2
Any
▼
Evaluate a Filter node when value and args are resolvable.
OptionalFilter (``?…
_try_eval_filter
2
Any
▼
def _try_eval_filter(self, expr: Filter, depth: int = 0) -> Any
Evaluate a Filter node when value and args are resolvable.
OptionalFilter (?|) returns None when the input value is None.
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_try_eval_pipeline
2
Any
▼
Evaluate a Pipeline node when value and all steps are resolvable.
SafePipeline…
_try_eval_pipeline
2
Any
▼
def _try_eval_pipeline(self, expr: Pipeline, depth: int = 0) -> Any
Evaluate a Pipeline node when value and all steps are resolvable.
SafePipeline (?|>) propagates None through the chain.
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_try_eval_listcomp
2
Any
▼
Evaluate a list comprehension when iterable and all parts resolve.
_try_eval_listcomp
2
Any
▼
def _try_eval_listcomp(self, expr: ListComp, depth: int = 0) -> Any
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_try_eval_funccall
2
Any
▼
Evaluate a FuncCall when it targets a safe builtin and all args resolve.
_try_eval_funccall
2
Any
▼
def _try_eval_funccall(self, expr: FuncCall, depth: int = 0) -> Any
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_try_eval_range
2
Any
▼
Evaluate a Range literal (start..end or start...end).
_try_eval_range
2
Any
▼
def _try_eval_range(self, expr: Range, depth: int = 0) -> Any
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_try_eval_test
2
Any
▼
Evaluate a Test node when the value can be resolved.
Handles ``is defined`` / …
_try_eval_test
2
Any
▼
def _try_eval_test(self, expr: Test, depth: int = 0) -> Any
Evaluate a Test node when the value can be resolved.
Handlesis defined / is undefinedspecially (they check
context membership, not the value itself). All other tests require
a resolved value.
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_eval_binop
3
Any
▼
Evaluate a binary operation with known operands.
staticmethod
_eval_binop
3
Any
▼
def _eval_binop(op: str, left: Any, right: Any) -> Any
Parameters
| Name | Type | Description |
|---|---|---|
op |
— |
|
left |
— |
|
right |
— |
Returns
Any
_eval_unaryop
2
Any
▼
Evaluate a unary operation with a known operand.
staticmethod
_eval_unaryop
2
Any
▼
def _eval_unaryop(op: str, operand: Any) -> Any
Parameters
| Name | Type | Description |
|---|---|---|
op |
— |
|
operand |
— |
Returns
Any
_eval_compare
2
Any
▼
Evaluate a comparison chain with known operands.
_eval_compare
2
Any
▼
def _eval_compare(self, expr: Compare, depth: int = 0) -> Any
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_eval_boolop
2
Any
▼
Evaluate a boolean operation with short-circuit semantics.
_eval_boolop
2
Any
▼
def _eval_boolop(self, expr: BoolOp, depth: int = 0) -> Any
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
|
depth |
— |
Default:0
|
Returns
Any
_transform_body
1
Sequence[Node]
▼
Transform a sequence of nodes, merging adjacent Data nodes.
_transform_body
1
Sequence[Node]
▼
def _transform_body(self, body: Sequence[Node]) -> Sequence[Node]
Parameters
| Name | Type | Description |
|---|---|---|
body |
— |
Returns
Sequence[Node]
_append_and_merge
2
▼
Append a node, merging adjacent Data nodes.
staticmethod
_append_and_merge
2
▼
def _append_and_merge(nodes: list[Node], new_node: Node) -> None
Parameters
| Name | Type | Description |
|---|---|---|
nodes |
— |
|
new_node |
— |
_transform_node
1
Node | None
▼
Transform a single AST node.
Returns the transformed node, or None to remove i…
_transform_node
1
Node | None
▼
def _transform_node(self, node: Node) -> Node | None
Transform a single AST node.
Returns the transformed node, or None to remove it.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node | None
_transform_output
1
Node
▼
Try to evaluate an Output node to a Data node.
_transform_output
1
Node
▼
def _transform_output(self, node: Output) -> Node
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node
_transform_if
1
Node | None
▼
Try to evaluate an If node's test at compile time.
_transform_if
1
Node | None
▼
def _transform_if(self, node: If) -> Node | None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node | None
_transform_for
1
Node | None
▼
Unroll for-loop when iterable is statically known, else recurse.
_transform_for
1
Node | None
▼
def _transform_for(self, node: For) -> Node | None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node | None
_transform_with
1
Node
▼
Propagate static values through {% with %} block bindings.
Evaluates each bind…
_transform_with
1
Node
▼
def _transform_with(self, node: With) -> Node
Propagate static values through {% with %} block bindings.
Evaluates each binding expression against the static context. Resolved bindings are added to a sub-evaluator's context so that the body can fold expressions referencing them.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node
_transform_match
1
Node | None
▼
Eliminate dead match/case branches when subject is compile-time-known.
When th…
_transform_match
1
Node | None
▼
def _transform_match(self, node: Match) -> Node | None
Eliminate dead match/case branches when subject is compile-time-known.
When the subject resolves, iterate cases and match:
- Const patterns: exact equality check
- Name("_") wildcard: always matches
- Other patterns: bail (leave Match intact)
If subject is unresolved, recurse into each case body.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node | None
_try_unroll_for
2
Node | None
▼
Attempt to unroll a for-loop with a known iterable.
Returns an _InlinedBody of…
_try_unroll_for
2
Node | None
▼
def _try_unroll_for(self, node: For, iter_val: Any) -> Node | None
Attempt to unroll a for-loop with a known iterable.
Returns an _InlinedBody of unrolled iterations, or None if unrolling is not possible (too many items, complex target, etc.).
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
|
iter_val |
— |
Returns
Node | None
_build_iter_context
2
dict[str, Any]
▼
Build a sub-context mapping target variable(s) to the current item.
_build_iter_context
2
dict[str, Any]
▼
def _build_iter_context(self, target_names: tuple[str, ...], item: Any) -> dict[str, Any]
Parameters
| Name | Type | Description |
|---|---|---|
target_names |
— |
|
item |
— |
Returns
dict[str, Any]
_make_sub_evaluator
1
PartialEvaluator
▼
Create a sub-evaluator with a merged context.
_make_sub_evaluator
1
PartialEvaluator
▼
def _make_sub_evaluator(self, ctx: dict[str, Any]) -> PartialEvaluator
Parameters
| Name | Type | Description |
|---|---|---|
ctx |
— |
Returns
PartialEvaluator
_transform_assignment
1
Node
▼
Track Set/Let bindings so downstream expressions resolve.
When the assigned va…
_transform_assignment
1
Node
▼
def _transform_assignment(self, node: Set | Let) -> Node
Track Set/Let bindings so downstream expressions resolve.
When the assigned value can be fully evaluated from the static context, add it to self._ctx so subsequent expressions referencing this variable are also foldable. The value expression is also replaced with a Const so the runtime assignment doesn't fail looking up now-unnecessary vars.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node
_transform_export
1
Node
▼
Partially transform Export value expression.
Export has the same structure as …
_transform_export
1
Node
▼
def _transform_export(self, node: Export) -> Node
Partially transform Export value expression.
Export has the same structure as Let (name + value), but with export-from-scope semantics. We need to partially transform the value expression so loop variable references are replaced with constants when the enclosing for-loop is unrolled.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node
_transform_capture
1
Node
▼
Recurse into Capture body so expressions are partially transformed.
Without th…
_transform_capture
1
Node
▼
def _transform_capture(self, node: Capture) -> Node
Recurse into Capture body so expressions are partially transformed.
Without this, a Capture inside an unrolled for-loop would retain references to the (now-removed) loop variable.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node
_try_inline_call
1
Node | None
▼
Try to inline a CallBlock by expanding its Def body.
Returns an _InlinedBody (…
_try_inline_call
1
Node | None
▼
def _try_inline_call(self, node: CallBlock) -> Node | None
Try to inline a CallBlock by expanding its Def body.
Returns an _InlinedBody (or single node) on success, None if inlining is not possible.
Requirements for inlining:
- The call target is a simple FuncCall(Name(def_name))
- The referenced Def has been seen in this template
- The Def body is small (< _MAX_INLINE_NODES)
- The Def has no Slot nodes (no caller injection)
- No slot content in the CallBlock
- All arguments resolve to constants
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
Node | None
_count_nodes
1
int
▼
Count total nodes in a body (shallow — does not recurse into children).
staticmethod
_count_nodes
1
int
▼
def _count_nodes(body: Sequence[Node]) -> int
Parameters
| Name | Type | Description |
|---|---|---|
body |
— |
Returns
int
_has_slot
1
bool
▼
Check if body contains any Slot nodes (recursively).
staticmethod
_has_slot
1
bool
▼
def _has_slot(body: Sequence[Node]) -> bool
Parameters
| Name | Type | Description |
|---|---|---|
body |
— |
Returns
bool
_transform_expr
1
Expr
▼
Try to partially evaluate an expression.
If sub-expressions can be resolved, r…
_transform_expr
1
Expr
▼
def _transform_expr(self, expr: Expr) -> Expr
Try to partially evaluate an expression.
If sub-expressions can be resolved, replace them with Const nodes.
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
Returns
Expr
_transform_boolop
1
Expr
▼
Partially simplify BoolOp when some operands are statically known.
Template ex…
_transform_boolop
1
Expr
▼
def _transform_boolop(self, expr: BoolOp) -> Expr
Partially simplify BoolOp when some operands are statically known.
Template expressions have no side effects, so short-circuiting is always safe:
false and X→Falsetrue or X→True- Mixed: filter out resolved non-terminating operands.
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
Returns
Expr
_transform_condexpr
1
Expr
▼
Collapse CondExpr when the test resolves statically.
_transform_condexpr
1
Expr
▼
def _transform_condexpr(self, expr: CondExpr) -> Expr
Parameters
| Name | Type | Description |
|---|---|---|
expr |
— |
Returns
Expr
_InlinedBody
1
▼
Temporary node for inlined If branches.
Holds multiple nodes that replace a single If node. The p…
_InlinedBody
1
▼
Temporary node for inlined If branches.
Holds multiple nodes that replace a single If node. The parent's
_transform_bodyflattens these into the body sequence.
Attributes
| Name | Type | Description |
|---|---|---|
nodes |
Sequence[Node]
|
— |
Functions
_try_eval_const_only
1
Any
▼
Evaluate expression using only literals and constant expressions.
Resolves Con…
_try_eval_const_only
1
Any
▼
def _try_eval_const_only(expr: Expr) -> Any
Evaluate expression using only literals and constant expressions.
Resolves Const, BinOp, UnaryOp, Compare, BoolOp. No Name/Getattr/Getitem (those require static_context). Used for dead code elimination.
Parameters
| Name | Type | Description |
|---|---|---|
expr |
Expr |
Returns
Any
_body_has_scoping_nodes
1
bool
▼
True if body contains Set, Let, Capture, or Export (block-scoped).
_body_has_scoping_nodes
1
bool
▼
def _body_has_scoping_nodes(nodes: Sequence[Node]) -> bool
Parameters
| Name | Type | Description |
|---|---|---|
nodes |
Sequence[Node] |
Returns
bool
_dce_transform_if
1
Node | None
▼
Eliminate dead branches when test is const-only resolvable.
_dce_transform_if
1
Node | None
▼
def _dce_transform_if(node: If) -> Node | None
Parameters
| Name | Type | Description |
|---|---|---|
node |
If |
Returns
Node | None
_dce_transform_match
1
Node | None
▼
Eliminate dead match/case branches when subject is a const literal.
_dce_transform_match
1
Node | None
▼
def _dce_transform_match(node: Match) -> Node | None
Parameters
| Name | Type | Description |
|---|---|---|
node |
Match |
Returns
Node | None
_dce_transform_body
1
Sequence[Node]
▼
Transform body, eliminating dead If nodes and flattening _InlinedBody.
_dce_transform_body
1
Sequence[Node]
▼
def _dce_transform_body(body: Sequence[Node]) -> Sequence[Node]
Parameters
| Name | Type | Description |
|---|---|---|
body |
Sequence[Node] |
Returns
Sequence[Node]
eliminate_dead_code
1
Template
▼
Remove branches whose conditions are provably constant.
Runs without static_co…
eliminate_dead_code
1
Template
▼
def eliminate_dead_code(template: Template) -> Template
Remove branches whose conditions are provably constant.
Runs without static_context. Eliminates e.g. {% if false %}...{% end %}, {% if true %}x{% else %}y{% end %}, {% if 1+1==2 %}...{% end %}.
Parameters
| Name | Type | Description |
|---|---|---|
template |
Template |
Returns
Template
_compare_op
3
bool
▼
Evaluate a comparison operator.
_compare_op
3
bool
▼
def _compare_op(op: str, left: Any, right: Any) -> bool
Parameters
| Name | Type | Description |
|---|---|---|
op |
str |
|
left |
Any |
|
right |
Any |
Returns
bool
partial_evaluate
6
Template
▼
Convenience function: partially evaluate a template AST.
partial_evaluate
6
Template
▼
def partial_evaluate(template: Template, static_context: dict[str, Any], *, escape_func: Any | None = None, pure_filters: frozenset[str] = frozenset(), filter_callables: dict[str, Callable[..., Any]] | None = None, inline_components: bool = False) -> Template
Parameters
| Name | Type | Description |
|---|---|---|
template |
Template |
Parsed template AST. |
static_context |
dict[str, Any] |
Values known at compile time. |
escape_func |
Any | None |
HTML escape function for static Output nodes. Default:None
|
pure_filters |
frozenset[str] |
Filter names safe for compile-time evaluation. Default:frozenset()
|
filter_callables |
dict[str, Callable[..., Any]] | None |
Filter name to callable for Filter/Pipeline eval. Default:None
|
inline_components |
bool |
When True, small {% def %} calls with all-constant arguments are expanded inline at compile time. Default:False
|
Returns
Template
_flatten_inlined
1
Template
▼
Flatten _InlinedBody nodes from branch elimination.
_flatten_inlined
1
Template
▼
def _flatten_inlined(template: Template) -> Template
Parameters
| Name | Type | Description |
|---|---|---|
template |
Template |
Returns
Template
_flatten_body
1
Sequence[Node]
▼
Flatten any _InlinedBody nodes in a body sequence.
_flatten_body
1
Sequence[Node]
▼
def _flatten_body(body: Sequence[Node]) -> Sequence[Node]
Parameters
| Name | Type | Description |
|---|---|---|
body |
Sequence[Node] |
Returns
Sequence[Node]