Coverage for jinja2_async_environment / compiler_modules / frame.py: 100%
69 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-26 21:26 -0800
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-26 21:26 -0800
1"""Async frame implementation for template compilation."""
3import typing as t
5from jinja2.compiler import Frame
6from jinja2.nodes import EvalContext
8if t.TYPE_CHECKING:
9 pass
12class AsyncFrame(Frame):
13 """Async-aware frame for template compilation context."""
15 block_frame: bool # Keep consistent with base class
16 block_frame_ref: "AsyncFrame | None" # New attribute for async frame reference
17 require_output_check: bool
18 has_known_extends: bool
19 toplevel: bool
20 rootlevel: bool
21 buffer: str | None
22 block_buffer: list[str]
23 extended_buffer: list[str] | None
24 require_yield: bool
25 buffer_count: int
26 is_async: bool
28 def __init__(self, eval_ctx: EvalContext | None = None) -> None:
29 if eval_ctx is None:
30 from jinja2.environment import Environment
31 from jinja2.nodes import EvalContext
33 eval_ctx = EvalContext(Environment(autoescape=True), "template")
35 super().__init__(eval_ctx)
36 self.buffer = None
37 self.block_buffer = []
38 self.extended_buffer = None
39 self.block_frame = False
40 self.block_frame_ref = None
41 self.require_output_check = False
42 self.has_known_extends = False
43 self.toplevel = False
44 self.rootlevel = False
45 self.require_yield = False
46 self.buffer_count = 0
47 self.is_async = False
48 self.block_counters: dict[str, int] = {}
49 self.block_frame_id = 0
51 def copy(self) -> t.Self:
52 """Create a copy of this frame."""
53 rv = self.__class__(self.eval_ctx)
54 rv.symbols = self.symbols.copy() # noqa: FURB145
55 rv.buffer = self.buffer
56 rv.block_buffer = self.block_buffer
57 rv.extended_buffer = self.extended_buffer
58 rv.eval_ctx = self.eval_ctx
59 rv.parent = self
60 rv.require_output_check = self.require_output_check
61 rv.has_known_extends = self.has_known_extends
62 rv.toplevel = self.toplevel
63 rv.rootlevel = self.rootlevel
64 rv.block_frame = self.block_frame
65 rv.block_frame_ref = self.block_frame_ref
66 rv.require_yield = self.require_yield
67 rv.buffer_count = self.buffer_count
68 rv.is_async = self.is_async
69 rv.block_counters = self.block_counters.copy() # noqa: FURB145
70 rv.block_frame_id = self.block_frame_id
71 return rv
73 def inspect(self, nodes: t.Any | None = None) -> None:
74 """Inspect nodes for symbol analysis."""
75 if nodes:
76 for node in nodes:
77 self.symbols.analyze_node(node)
79 def push_scope(self) -> None:
80 """Push a new scope (no-op for async frame)."""
81 pass
83 def pop_scope(self) -> None:
84 """Pop the current scope (no-op for async frame)."""
85 pass
87 def find_break(self) -> bool:
88 """Check if break statement is valid (always False)."""
89 return False
91 def find_continue(self) -> bool:
92 """Check if continue statement is valid (always False)."""
93 return False
95 def inner(self, isolated: bool = False) -> "AsyncFrame":
96 """Create an inner frame."""
97 return self.copy()