Module

compiler.partial_eval

Compile-time partial evaluation of template AST.

Transforms a Kida AST by evaluating expressions whose values can be determined from a static context (values known at compile time, not at render time). This replaces dynamic lookups with constant data nodes, enabling more aggressive f-string coalescing and producing templates where static regions are literal strings in bytecode.

Example:

Given static_context = {"site": Site(title="My Blog")}:

Before:  Output(expr=Getattr(Name("site"), "title"))
After:   Data(value="My Blog")

The evaluator is conservative: if any sub-expression cannot be resolved, the entire expression is left untouched. This guarantees that partial evaluation never changes observable behavior.

Integration:

Called by ``Environment._compile()`` between parsing and compilation.
The partially-evaluated AST is then compiled normally by the Compiler,
which sees more Data/Const nodes and produces better coalesced output.

Classes

PartialEvaluator 15
Evaluate static expressions in a Kida AST at compile time. Walks the template AST and replaces exp…

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…
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 14
__init__ 4
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) -> None
Parameters
Name Type Description
static_context
escape_func Default:None
pure_filters Default:frozenset()
filter_callables Default:None
_try_eval 1 Any
Try to evaluate an expression against the static context. Returns the computed…
def _try_eval(self, expr: Expr) -> Any

Try to evaluate an expression against the static context.

Returns the computed value on success, or_UNRESOLVEDif the expression depends on runtime values.

Parameters
Name Type Description
expr
Returns
Any
_try_eval_filter 1 Any
Evaluate a Filter node when value and args are resolvable.
def _try_eval_filter(self, expr: Filter) -> Any
Parameters
Name Type Description
expr
Returns
Any
_try_eval_pipeline 1 Any
Evaluate a Pipeline node when value and all steps are resolvable.
def _try_eval_pipeline(self, expr: Pipeline) -> Any
Parameters
Name Type Description
expr
Returns
Any
_eval_binop 3 Any
Evaluate a binary operation with known operands.
staticmethod
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
def _eval_unaryop(op: str, operand: Any) -> Any
Parameters
Name Type Description
op
operand
Returns
Any
_eval_compare 1 Any
Evaluate a comparison chain with known operands.
def _eval_compare(self, expr: Compare) -> Any
Parameters
Name Type Description
expr
Returns
Any
_eval_boolop 1 Any
Evaluate a boolean operation with short-circuit semantics.
def _eval_boolop(self, expr: BoolOp) -> Any
Parameters
Name Type Description
expr
Returns
Any
_transform_body 1 Sequence[Node]
Transform a sequence of nodes, merging adjacent Data nodes.
def _transform_body(self, body: Sequence[Node]) -> Sequence[Node]
Parameters
Name Type Description
body
Returns
Sequence[Node]
_transform_node 1 Node | None
Transform a single AST node. Returns the transformed node, or None to remove i…
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.
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.
def _transform_if(self, node: If) -> Node | None
Parameters
Name Type Description
node
Returns
Node | None
_transform_for 1 Node
Recurse into For loop body.
def _transform_for(self, node: For) -> Node
Parameters
Name Type Description
node
Returns
Node
_transform_expr 1 Expr
Try to partially evaluate an expression. If sub-expressions can be resolved, r…
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
_InlinedBody 1
Temporary node for inlined If branches. Holds multiple nodes that replace a single If node. The p…

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…
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).
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.
def _dce_transform_if(node: If) -> Node | None
Parameters
Name Type Description
node If
Returns
Node | None
_dce_transform_body 1 Sequence[Node]
Transform body, eliminating dead If nodes and flattening _InlinedBody.
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…
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.
def _compare_op(op: str, left: Any, right: Any) -> bool
Parameters
Name Type Description
op str
left Any
right Any
Returns
bool
partial_evaluate 5 Template
Convenience function: partially evaluate a template AST.
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) -> 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
Returns
Template
_flatten_inlined 1 Template
Flatten _InlinedBody nodes from branch elimination.
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.
def _flatten_body(body: Sequence[Node]) -> Sequence[Node]
Parameters
Name Type Description
body Sequence[Node]
Returns
Sequence[Node]