Classes
DependencyWalker
72
▼
Extract context variable dependencies from AST expressions.
Walks the AST and collects all context…
DependencyWalker
72
▼
Extract context variable dependencies from AST expressions.
Walks the AST and collects all context paths (e.g., "page.title", "site.pages") that an expression or block may access.
Produces a conservative superset: may include paths not actually used at runtime, but never excludes paths that are used.
Thread-safe: Creates new state for each analyze() call.
Scope Handling:
- Loop variables ({% for x in items %}) are excluded
- With bindings ({% with expr as x %}) are excluded
- Function arguments ({% def fn(x) %}) are excluded
- Set/let assignments create local scope
Methods
analyze
1
frozenset[str]
▼
Analyze a node and return all context dependencies.
analyze
1
frozenset[str]
▼
def analyze(self, node: Node) -> frozenset[str]
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
AST node to analyze (Block, Template, expression, etc.) |
Returns
frozenset[str]
Frozen set of context paths (e.g., {"page.title", "site.pages"})
visit_Name
1
▼
Handle variable reference.
visit_Name
1
▼
def visit_Name(self, node: Name) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Getattr
1
▼
Handle attribute access: obj.attr
visit_Getattr
1
▼
def visit_Getattr(self, node: Getattr) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_OptionalGetattr
1
▼
Handle optional attribute access: obj?.attr
visit_OptionalGetattr
1
▼
def visit_OptionalGetattr(self, node: OptionalGetattr) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Getitem
1
▼
Handle subscript access: obj[key]
visit_Getitem
1
▼
def visit_Getitem(self, node: Getitem) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_OptionalGetitem
1
▼
Handle optional subscript access: obj?[key]
visit_OptionalGetitem
1
▼
def visit_OptionalGetitem(self, node: OptionalGetitem) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_For
1
▼
Handle for loop: push loop variable into scope.
visit_For
1
▼
def visit_For(self, node: For | AsyncFor) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_AsyncFor
1
▼
Handle async for loop (same as regular for).
visit_AsyncFor
1
▼
def visit_AsyncFor(self, node: AsyncFor) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_While
1
▼
Handle while loop.
visit_While
1
▼
def visit_While(self, node: While) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_With
1
▼
Handle with block: {% with x = expr %}...{% end %}
visit_With
1
▼
def visit_With(self, node: With) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_WithConditional
1
▼
Handle conditional with: {% with expr as target %}
visit_WithConditional
1
▼
def visit_WithConditional(self, node: WithConditional) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Def
1
▼
Handle function definition: push args into scope.
visit_Def
1
▼
def visit_Def(self, node: Def) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Region
1
▼
Handle region: push params into scope, visit body (same as def).
visit_Region
1
▼
def visit_Region(self, node: Region) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Macro
1
▼
Handle macro definition (same as def).
visit_Macro
1
▼
def visit_Macro(self, node: Node) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Set
1
▼
Handle set statement.
visit_Set
1
▼
def visit_Set(self, node: Set) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Let
1
▼
Handle let statement (template-scoped).
visit_Let
1
▼
def visit_Let(self, node: Let) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Export
1
▼
Handle export statement.
visit_Export
1
▼
def visit_Export(self, node: Export) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Capture
1
▼
Handle capture block: {% capture name %}...{% end %}
visit_Capture
1
▼
def visit_Capture(self, node: Capture) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Filter
1
▼
Handle filter expression.
visit_Filter
1
▼
def visit_Filter(self, node: Filter) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_OptionalFilter
1
▼
Handle optional filter expression (same as regular filter).
visit_OptionalFilter
1
▼
def visit_OptionalFilter(self, node: Filter) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Pipeline
1
▼
Handle pipeline expression: expr |> filter1 |> filter2
visit_Pipeline
1
▼
def visit_Pipeline(self, node: Pipeline) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_SafePipeline
1
▼
Handle safe pipeline expression (same as regular pipeline).
visit_SafePipeline
1
▼
def visit_SafePipeline(self, node: SafePipeline) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_FuncCall
1
▼
Handle function call.
visit_FuncCall
1
▼
def visit_FuncCall(self, node: FuncCall) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_NullCoalesce
1
▼
Handle null coalescing: a ?? b
visit_NullCoalesce
1
▼
def visit_NullCoalesce(self, node: NullCoalesce) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_CondExpr
1
▼
Handle conditional expression: a if cond else b
visit_CondExpr
1
▼
def visit_CondExpr(self, node: CondExpr) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_BoolOp
1
▼
Handle boolean operations: a and b, a or b
visit_BoolOp
1
▼
def visit_BoolOp(self, node: BoolOp) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_BinOp
1
▼
Handle binary operations: a + b, a - b, etc.
visit_BinOp
1
▼
def visit_BinOp(self, node: BinOp) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_UnaryOp
1
▼
Handle unary operations: -a, not a
visit_UnaryOp
1
▼
def visit_UnaryOp(self, node: UnaryOp) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Compare
1
▼
Handle comparisons: a < b < c
visit_Compare
1
▼
def visit_Compare(self, node: Compare) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Range
1
▼
Handle range literal: start..end or start...end
visit_Range
1
▼
def visit_Range(self, node: Range) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Slice
1
▼
Handle slice expression: [start:stop:step]
visit_Slice
1
▼
def visit_Slice(self, node: Slice) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Concat
1
▼
Handle string concatenation: a ~ b ~ c
visit_Concat
1
▼
def visit_Concat(self, node: Concat) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_List
1
▼
Handle list literal: [a, b, c]
visit_List
1
▼
def visit_List(self, node: List) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_ListComp
1
▼
Handle list comprehension: [expr for x in iterable if cond]
The iterable is a …
visit_ListComp
1
▼
def visit_ListComp(self, node: ListComp) -> None
Handle list comprehension: [expr for x in iterable if cond]
The iterable is a context dependency. The target variable is local to the comprehension — elt and ifs must be visited with it in scope.
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Tuple
1
▼
Handle tuple literal: (a, b, c)
visit_Tuple
1
▼
def visit_Tuple(self, node: Tuple) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Dict
1
▼
Handle dict literal: {a: b, c: d}
visit_Dict
1
▼
def visit_Dict(self, node: Dict) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Test
1
▼
Handle test expression: x is defined
visit_Test
1
▼
def visit_Test(self, node: Test) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Match
1
▼
Handle match statement.
visit_Match
1
▼
def visit_Match(self, node: Match) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Trans
1
▼
Handle trans block: walk variable expressions and count_expr.
visit_Trans
1
▼
def visit_Trans(self, node: Trans) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_TransVar
1
▼
Handle trans variable binding: walk the expression.
visit_TransVar
1
▼
def visit_TransVar(self, node: TransVar) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Cache
1
▼
Handle cache block: {% cache key %}...{% end %}
visit_Cache
1
▼
def visit_Cache(self, node: Cache) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Include
1
▼
Handle include statement.
visit_Include
1
▼
def visit_Include(self, node: Include) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Import
1
▼
Handle import statement.
visit_Import
1
▼
def visit_Import(self, node: Import) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_FromImport
1
▼
Handle from...import statement.
visit_FromImport
1
▼
def visit_FromImport(self, node: FromImport) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_If
1
▼
Handle if statement.
visit_If
1
▼
def visit_If(self, node: If) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Output
1
▼
Handle output: {{ expr }}
visit_Output
1
▼
def visit_Output(self, node: Output) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Block
1
▼
Handle block: {% block name %}...{% end %}
visit_Block
1
▼
def visit_Block(self, node: Block) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Extends
1
▼
Handle extends: {% extends 'base.html' %}
visit_Extends
1
▼
def visit_Extends(self, node: Extends) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Template
1
▼
Handle template root node.
visit_Template
1
▼
def visit_Template(self, node: Template) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_FilterBlock
1
▼
Handle filter block: {% filter upper %}...{% end %}
visit_FilterBlock
1
▼
def visit_FilterBlock(self, node: FilterBlock) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_CallBlock
1
▼
Handle call block: {% call name(args) %}body{% end %} with named slots.
visit_CallBlock
1
▼
def visit_CallBlock(self, node: CallBlock) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Spaceless
1
▼
Handle spaceless block.
visit_Spaceless
1
▼
def visit_Spaceless(self, node: Spaceless) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Autoescape
1
▼
Handle autoescape block.
visit_Autoescape
1
▼
def visit_Autoescape(self, node: Autoescape) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Trim
1
▼
Handle trim block.
visit_Trim
1
▼
def visit_Trim(self, node: Trim) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Embed
1
▼
Handle embed: {% embed 'card.html' %}...{% end %}
visit_Embed
1
▼
def visit_Embed(self, node: Embed) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Await
1
▼
Handle await expression.
visit_Await
1
▼
def visit_Await(self, node: Await) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_MarkSafe
1
▼
Handle safe marker.
visit_MarkSafe
1
▼
def visit_MarkSafe(self, node: MarkSafe) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_InlinedFilter
1
▼
Handle inlined filter (optimization).
visit_InlinedFilter
1
▼
def visit_InlinedFilter(self, node: InlinedFilter) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Const
1
▼
Constants have no dependencies.
visit_Const
1
▼
def visit_Const(self, node: Const) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Data
1
▼
Static data has no dependencies.
visit_Data
1
▼
def visit_Data(self, node: Data) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Raw
1
▼
Raw blocks have no dependencies.
visit_Raw
1
▼
def visit_Raw(self, node: Raw) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Slot
1
▼
Slots have no dependencies.
visit_Slot
1
▼
def visit_Slot(self, node: Slot) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Break
1
▼
Break has no dependencies.
visit_Break
1
▼
def visit_Break(self, node: Break) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Continue
1
▼
Continue has no dependencies.
visit_Continue
1
▼
def visit_Continue(self, node: Continue) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_Do
1
▼
Handle do statement.
visit_Do
1
▼
def visit_Do(self, node: Node) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
visit_LoopVar
1
▼
Loop variable access (loop.index, etc.) - no context deps.
visit_LoopVar
1
▼
def visit_LoopVar(self, node: LoopVar) -> None
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Internal Methods 6 ▼
__init__
0
▼
Initialize walker (stateless until analyze() is called).
__init__
0
▼
def __init__(self) -> None
_build_path
1
str | None
▼
Build dotted path from chained attribute/item access.
Returns None if the path…
_build_path
1
str | None
▼
def _build_path(self, node: Node) -> str | None
Build dotted path from chained attribute/item access.
Returns None if the path can't be determined statically (e.g., dynamic keys, local variables).
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
str | None
_extract_targets
1
set[str]
▼
Extract variable names from assignment target.
_extract_targets
1
set[str]
▼
def _extract_targets(self, node: Node) -> set[str]
Parameters
| Name | Type | Description |
|---|---|---|
node |
— |
Returns
set[str]
_push_scope
1
▼
Push a new scope and update the flat locals set.
_push_scope
1
▼
def _push_scope(self, names: set[str]) -> None
Parameters
| Name | Type | Description |
|---|---|---|
names |
— |
_pop_scope
0
▼
Pop the top scope and rebuild the flat locals set.
_pop_scope
0
▼
def _pop_scope(self) -> None
_is_local
1
bool
▼
Check if a name is in local scope (O(1) via flat set).
_is_local
1
bool
▼
def _is_local(self, name: str) -> bool
Parameters
| Name | Type | Description |
|---|---|---|
name |
— |
Returns
bool