Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/jinja2/nodes.py: 56%
555 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""AST nodes generated by the parser for the compiler. Also provides
2some node tree helper functions used by the parser and compiler in order
3to normalize nodes.
4"""
5import inspect
6import operator
7import typing as t
8from collections import deque
10from markupsafe import Markup
12from .utils import _PassArg
14if t.TYPE_CHECKING: 14 ↛ 15line 14 didn't jump to line 15, because the condition on line 14 was never true
15 import typing_extensions as te
16 from .environment import Environment
18_NodeBound = t.TypeVar("_NodeBound", bound="Node")
20_binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
21 "*": operator.mul,
22 "/": operator.truediv,
23 "//": operator.floordiv,
24 "**": operator.pow,
25 "%": operator.mod,
26 "+": operator.add,
27 "-": operator.sub,
28}
30_uaop_to_func: t.Dict[str, t.Callable[[t.Any], t.Any]] = {
31 "not": operator.not_,
32 "+": operator.pos,
33 "-": operator.neg,
34}
36_cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { 36 ↛ exitline 36 didn't jump to the function exit
37 "eq": operator.eq,
38 "ne": operator.ne,
39 "gt": operator.gt,
40 "gteq": operator.ge,
41 "lt": operator.lt,
42 "lteq": operator.le,
43 "in": lambda a, b: a in b,
44 "notin": lambda a, b: a not in b,
45}
48class Impossible(Exception):
49 """Raised if the node could not perform a requested action."""
52class NodeType(type):
53 """A metaclass for nodes that handles the field and attribute
54 inheritance. fields and attributes from the parent class are
55 automatically forwarded to the child."""
57 def __new__(mcs, name, bases, d): # type: ignore
58 for attr in "fields", "attributes":
59 storage = []
60 storage.extend(getattr(bases[0] if bases else object, attr, ()))
61 storage.extend(d.get(attr, ()))
62 assert len(bases) <= 1, "multiple inheritance not allowed"
63 assert len(storage) == len(set(storage)), "layout conflict"
64 d[attr] = tuple(storage)
65 d.setdefault("abstract", False)
66 return type.__new__(mcs, name, bases, d)
69class EvalContext:
70 """Holds evaluation time information. Custom attributes can be attached
71 to it in extensions.
72 """
74 def __init__(
75 self, environment: "Environment", template_name: t.Optional[str] = None
76 ) -> None:
77 self.environment = environment
78 if callable(environment.autoescape):
79 self.autoescape = environment.autoescape(template_name)
80 else:
81 self.autoescape = environment.autoescape
82 self.volatile = False
84 def save(self) -> t.Mapping[str, t.Any]:
85 return self.__dict__.copy()
87 def revert(self, old: t.Mapping[str, t.Any]) -> None:
88 self.__dict__.clear()
89 self.__dict__.update(old)
92def get_eval_context(node: "Node", ctx: t.Optional[EvalContext]) -> EvalContext:
93 if ctx is None:
94 if node.environment is None:
95 raise RuntimeError(
96 "if no eval context is passed, the node must have an"
97 " attached environment."
98 )
99 return EvalContext(node.environment)
100 return ctx
103class Node(metaclass=NodeType):
104 """Baseclass for all Jinja nodes. There are a number of nodes available
105 of different types. There are four major types:
107 - :class:`Stmt`: statements
108 - :class:`Expr`: expressions
109 - :class:`Helper`: helper nodes
110 - :class:`Template`: the outermost wrapper node
112 All nodes have fields and attributes. Fields may be other nodes, lists,
113 or arbitrary values. Fields are passed to the constructor as regular
114 positional arguments, attributes as keyword arguments. Each node has
115 two attributes: `lineno` (the line number of the node) and `environment`.
116 The `environment` attribute is set at the end of the parsing process for
117 all nodes automatically.
118 """
120 fields: t.Tuple[str, ...] = ()
121 attributes: t.Tuple[str, ...] = ("lineno", "environment")
122 abstract = True
124 lineno: int
125 environment: t.Optional["Environment"]
127 def __init__(self, *fields: t.Any, **attributes: t.Any) -> None:
128 if self.abstract:
129 raise TypeError("abstract nodes are not instantiable")
130 if fields:
131 if len(fields) != len(self.fields):
132 if not self.fields:
133 raise TypeError(f"{type(self).__name__!r} takes 0 arguments")
134 raise TypeError(
135 f"{type(self).__name__!r} takes 0 or {len(self.fields)}"
136 f" argument{'s' if len(self.fields) != 1 else ''}"
137 )
138 for name, arg in zip(self.fields, fields):
139 setattr(self, name, arg)
140 for attr in self.attributes:
141 setattr(self, attr, attributes.pop(attr, None))
142 if attributes:
143 raise TypeError(f"unknown attribute {next(iter(attributes))!r}")
145 def iter_fields(
146 self,
147 exclude: t.Optional[t.Container[str]] = None,
148 only: t.Optional[t.Container[str]] = None,
149 ) -> t.Iterator[t.Tuple[str, t.Any]]:
150 """This method iterates over all fields that are defined and yields
151 ``(key, value)`` tuples. Per default all fields are returned, but
152 it's possible to limit that to some fields by providing the `only`
153 parameter or to exclude some using the `exclude` parameter. Both
154 should be sets or tuples of field names.
155 """
156 for name in self.fields:
157 if (
158 (exclude is None and only is None)
159 or (exclude is not None and name not in exclude)
160 or (only is not None and name in only)
161 ):
162 try:
163 yield name, getattr(self, name)
164 except AttributeError:
165 pass
167 def iter_child_nodes(
168 self,
169 exclude: t.Optional[t.Container[str]] = None,
170 only: t.Optional[t.Container[str]] = None,
171 ) -> t.Iterator["Node"]:
172 """Iterates over all direct child nodes of the node. This iterates
173 over all fields and yields the values of they are nodes. If the value
174 of a field is a list all the nodes in that list are returned.
175 """
176 for _, item in self.iter_fields(exclude, only):
177 if isinstance(item, list):
178 for n in item:
179 if isinstance(n, Node):
180 yield n
181 elif isinstance(item, Node):
182 yield item
184 def find(self, node_type: t.Type[_NodeBound]) -> t.Optional[_NodeBound]:
185 """Find the first node of a given type. If no such node exists the
186 return value is `None`.
187 """
188 for result in self.find_all(node_type):
189 return result
191 return None
193 def find_all(
194 self, node_type: t.Union[t.Type[_NodeBound], t.Tuple[t.Type[_NodeBound], ...]]
195 ) -> t.Iterator[_NodeBound]:
196 """Find all the nodes of a given type. If the type is a tuple,
197 the check is performed for any of the tuple items.
198 """
199 for child in self.iter_child_nodes():
200 if isinstance(child, node_type):
201 yield child # type: ignore
202 yield from child.find_all(node_type)
204 def set_ctx(self, ctx: str) -> "Node":
205 """Reset the context of a node and all child nodes. Per default the
206 parser will all generate nodes that have a 'load' context as it's the
207 most common one. This method is used in the parser to set assignment
208 targets and other nodes to a store context.
209 """
210 todo = deque([self])
211 while todo:
212 node = todo.popleft()
213 if "ctx" in node.fields:
214 node.ctx = ctx # type: ignore
215 todo.extend(node.iter_child_nodes())
216 return self
218 def set_lineno(self, lineno: int, override: bool = False) -> "Node":
219 """Set the line numbers of the node and children."""
220 todo = deque([self])
221 while todo:
222 node = todo.popleft()
223 if "lineno" in node.attributes:
224 if node.lineno is None or override:
225 node.lineno = lineno
226 todo.extend(node.iter_child_nodes())
227 return self
229 def set_environment(self, environment: "Environment") -> "Node":
230 """Set the environment for all nodes."""
231 todo = deque([self])
232 while todo:
233 node = todo.popleft()
234 node.environment = environment
235 todo.extend(node.iter_child_nodes())
236 return self
238 def __eq__(self, other: t.Any) -> bool:
239 if type(self) is not type(other):
240 return NotImplemented
242 return tuple(self.iter_fields()) == tuple(other.iter_fields())
244 __hash__ = object.__hash__
246 def __repr__(self) -> str:
247 args_str = ", ".join(f"{a}={getattr(self, a, None)!r}" for a in self.fields)
248 return f"{type(self).__name__}({args_str})"
250 def dump(self) -> str:
251 def _dump(node: t.Union[Node, t.Any]) -> None:
252 if not isinstance(node, Node):
253 buf.append(repr(node))
254 return
256 buf.append(f"nodes.{type(node).__name__}(")
257 if not node.fields:
258 buf.append(")")
259 return
260 for idx, field in enumerate(node.fields):
261 if idx:
262 buf.append(", ")
263 value = getattr(node, field)
264 if isinstance(value, list):
265 buf.append("[")
266 for idx, item in enumerate(value):
267 if idx:
268 buf.append(", ")
269 _dump(item)
270 buf.append("]")
271 else:
272 _dump(value)
273 buf.append(")")
275 buf: t.List[str] = []
276 _dump(self)
277 return "".join(buf)
280class Stmt(Node):
281 """Base node for all statements."""
283 abstract = True
286class Helper(Node):
287 """Nodes that exist in a specific context only."""
289 abstract = True
292class Template(Node):
293 """Node that represents a template. This must be the outermost node that
294 is passed to the compiler.
295 """
297 fields = ("body",)
298 body: t.List[Node]
301class Output(Stmt):
302 """A node that holds multiple expressions which are then printed out.
303 This is used both for the `print` statement and the regular template data.
304 """
306 fields = ("nodes",)
307 nodes: t.List["Expr"]
310class Extends(Stmt):
311 """Represents an extends statement."""
313 fields = ("template",)
314 template: "Expr"
317class For(Stmt):
318 """The for loop. `target` is the target for the iteration (usually a
319 :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list
320 of nodes that are used as loop-body, and `else_` a list of nodes for the
321 `else` block. If no else node exists it has to be an empty list.
323 For filtered nodes an expression can be stored as `test`, otherwise `None`.
324 """
326 fields = ("target", "iter", "body", "else_", "test", "recursive")
327 target: Node
328 iter: Node
329 body: t.List[Node]
330 else_: t.List[Node]
331 test: t.Optional[Node]
332 recursive: bool
335class If(Stmt):
336 """If `test` is true, `body` is rendered, else `else_`."""
338 fields = ("test", "body", "elif_", "else_")
339 test: Node
340 body: t.List[Node]
341 elif_: t.List["If"]
342 else_: t.List[Node]
345class Macro(Stmt):
346 """A macro definition. `name` is the name of the macro, `args` a list of
347 arguments and `defaults` a list of defaults if there are any. `body` is
348 a list of nodes for the macro body.
349 """
351 fields = ("name", "args", "defaults", "body")
352 name: str
353 args: t.List["Name"]
354 defaults: t.List["Expr"]
355 body: t.List[Node]
358class CallBlock(Stmt):
359 """Like a macro without a name but a call instead. `call` is called with
360 the unnamed macro as `caller` argument this node holds.
361 """
363 fields = ("call", "args", "defaults", "body")
364 call: "Call"
365 args: t.List["Name"]
366 defaults: t.List["Expr"]
367 body: t.List[Node]
370class FilterBlock(Stmt):
371 """Node for filter sections."""
373 fields = ("body", "filter")
374 body: t.List[Node]
375 filter: "Filter"
378class With(Stmt):
379 """Specific node for with statements. In older versions of Jinja the
380 with statement was implemented on the base of the `Scope` node instead.
382 .. versionadded:: 2.9.3
383 """
385 fields = ("targets", "values", "body")
386 targets: t.List["Expr"]
387 values: t.List["Expr"]
388 body: t.List[Node]
391class Block(Stmt):
392 """A node that represents a block.
394 .. versionchanged:: 3.0.0
395 the `required` field was added.
396 """
398 fields = ("name", "body", "scoped", "required")
399 name: str
400 body: t.List[Node]
401 scoped: bool
402 required: bool
405class Include(Stmt):
406 """A node that represents the include tag."""
408 fields = ("template", "with_context", "ignore_missing")
409 template: "Expr"
410 with_context: bool
411 ignore_missing: bool
414class Import(Stmt):
415 """A node that represents the import tag."""
417 fields = ("template", "target", "with_context")
418 template: "Expr"
419 target: str
420 with_context: bool
423class FromImport(Stmt):
424 """A node that represents the from import tag. It's important to not
425 pass unsafe names to the name attribute. The compiler translates the
426 attribute lookups directly into getattr calls and does *not* use the
427 subscript callback of the interface. As exported variables may not
428 start with double underscores (which the parser asserts) this is not a
429 problem for regular Jinja code, but if this node is used in an extension
430 extra care must be taken.
432 The list of names may contain tuples if aliases are wanted.
433 """
435 fields = ("template", "names", "with_context")
436 template: "Expr"
437 names: t.List[t.Union[str, t.Tuple[str, str]]]
438 with_context: bool
441class ExprStmt(Stmt):
442 """A statement that evaluates an expression and discards the result."""
444 fields = ("node",)
445 node: Node
448class Assign(Stmt):
449 """Assigns an expression to a target."""
451 fields = ("target", "node")
452 target: "Expr"
453 node: Node
456class AssignBlock(Stmt):
457 """Assigns a block to a target."""
459 fields = ("target", "filter", "body")
460 target: "Expr"
461 filter: t.Optional["Filter"]
462 body: t.List[Node]
465class Expr(Node):
466 """Baseclass for all expressions."""
468 abstract = True
470 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
471 """Return the value of the expression as constant or raise
472 :exc:`Impossible` if this was not possible.
474 An :class:`EvalContext` can be provided, if none is given
475 a default context is created which requires the nodes to have
476 an attached environment.
478 .. versionchanged:: 2.4
479 the `eval_ctx` parameter was added.
480 """
481 raise Impossible()
483 def can_assign(self) -> bool:
484 """Check if it's possible to assign something to this node."""
485 return False
488class BinExpr(Expr):
489 """Baseclass for all binary expressions."""
491 fields = ("left", "right")
492 left: Expr
493 right: Expr
494 operator: str
495 abstract = True
497 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
498 eval_ctx = get_eval_context(self, eval_ctx)
500 # intercepted operators cannot be folded at compile time
501 if (
502 eval_ctx.environment.sandboxed
503 and self.operator in eval_ctx.environment.intercepted_binops # type: ignore
504 ):
505 raise Impossible()
506 f = _binop_to_func[self.operator]
507 try:
508 return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
509 except Exception as e:
510 raise Impossible() from e
513class UnaryExpr(Expr):
514 """Baseclass for all unary expressions."""
516 fields = ("node",)
517 node: Expr
518 operator: str
519 abstract = True
521 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
522 eval_ctx = get_eval_context(self, eval_ctx)
524 # intercepted operators cannot be folded at compile time
525 if (
526 eval_ctx.environment.sandboxed
527 and self.operator in eval_ctx.environment.intercepted_unops # type: ignore
528 ):
529 raise Impossible()
530 f = _uaop_to_func[self.operator]
531 try:
532 return f(self.node.as_const(eval_ctx))
533 except Exception as e:
534 raise Impossible() from e
537class Name(Expr):
538 """Looks up a name or stores a value in a name.
539 The `ctx` of the node can be one of the following values:
541 - `store`: store a value in the name
542 - `load`: load that name
543 - `param`: like `store` but if the name was defined as function parameter.
544 """
546 fields = ("name", "ctx")
547 name: str
548 ctx: str
550 def can_assign(self) -> bool:
551 return self.name not in {"true", "false", "none", "True", "False", "None"}
554class NSRef(Expr):
555 """Reference to a namespace value assignment"""
557 fields = ("name", "attr")
558 name: str
559 attr: str
561 def can_assign(self) -> bool:
562 # We don't need any special checks here; NSRef assignments have a
563 # runtime check to ensure the target is a namespace object which will
564 # have been checked already as it is created using a normal assignment
565 # which goes through a `Name` node.
566 return True
569class Literal(Expr):
570 """Baseclass for literals."""
572 abstract = True
575class Const(Literal):
576 """All constant values. The parser will return this node for simple
577 constants such as ``42`` or ``"foo"`` but it can be used to store more
578 complex values such as lists too. Only constants with a safe
579 representation (objects where ``eval(repr(x)) == x`` is true).
580 """
582 fields = ("value",)
583 value: t.Any
585 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
586 return self.value
588 @classmethod
589 def from_untrusted(
590 cls,
591 value: t.Any,
592 lineno: t.Optional[int] = None,
593 environment: "t.Optional[Environment]" = None,
594 ) -> "Const":
595 """Return a const object if the value is representable as
596 constant value in the generated code, otherwise it will raise
597 an `Impossible` exception.
598 """
599 from .compiler import has_safe_repr
601 if not has_safe_repr(value):
602 raise Impossible()
603 return cls(value, lineno=lineno, environment=environment)
606class TemplateData(Literal):
607 """A constant template string."""
609 fields = ("data",)
610 data: str
612 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
613 eval_ctx = get_eval_context(self, eval_ctx)
614 if eval_ctx.volatile:
615 raise Impossible()
616 if eval_ctx.autoescape:
617 return Markup(self.data)
618 return self.data
621class Tuple(Literal):
622 """For loop unpacking and some other things like multiple arguments
623 for subscripts. Like for :class:`Name` `ctx` specifies if the tuple
624 is used for loading the names or storing.
625 """
627 fields = ("items", "ctx")
628 items: t.List[Expr]
629 ctx: str
631 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[t.Any, ...]:
632 eval_ctx = get_eval_context(self, eval_ctx)
633 return tuple(x.as_const(eval_ctx) for x in self.items)
635 def can_assign(self) -> bool:
636 for item in self.items:
637 if not item.can_assign():
638 return False
639 return True
642class List(Literal):
643 """Any list literal such as ``[1, 2, 3]``"""
645 fields = ("items",)
646 items: t.List[Expr]
648 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.List[t.Any]:
649 eval_ctx = get_eval_context(self, eval_ctx)
650 return [x.as_const(eval_ctx) for x in self.items]
653class Dict(Literal):
654 """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of
655 :class:`Pair` nodes.
656 """
658 fields = ("items",)
659 items: t.List["Pair"]
661 def as_const(
662 self, eval_ctx: t.Optional[EvalContext] = None
663 ) -> t.Dict[t.Any, t.Any]:
664 eval_ctx = get_eval_context(self, eval_ctx)
665 return dict(x.as_const(eval_ctx) for x in self.items)
668class Pair(Helper):
669 """A key, value pair for dicts."""
671 fields = ("key", "value")
672 key: Expr
673 value: Expr
675 def as_const(
676 self, eval_ctx: t.Optional[EvalContext] = None
677 ) -> t.Tuple[t.Any, t.Any]:
678 eval_ctx = get_eval_context(self, eval_ctx)
679 return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
682class Keyword(Helper):
683 """A key, value pair for keyword arguments where key is a string."""
685 fields = ("key", "value")
686 key: str
687 value: Expr
689 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[str, t.Any]:
690 eval_ctx = get_eval_context(self, eval_ctx)
691 return self.key, self.value.as_const(eval_ctx)
694class CondExpr(Expr):
695 """A conditional expression (inline if expression). (``{{
696 foo if bar else baz }}``)
697 """
699 fields = ("test", "expr1", "expr2")
700 test: Expr
701 expr1: Expr
702 expr2: t.Optional[Expr]
704 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
705 eval_ctx = get_eval_context(self, eval_ctx)
706 if self.test.as_const(eval_ctx):
707 return self.expr1.as_const(eval_ctx)
709 # if we evaluate to an undefined object, we better do that at runtime
710 if self.expr2 is None:
711 raise Impossible()
713 return self.expr2.as_const(eval_ctx)
716def args_as_const(
717 node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext]
718) -> t.Tuple[t.List[t.Any], t.Dict[t.Any, t.Any]]:
719 args = [x.as_const(eval_ctx) for x in node.args]
720 kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
722 if node.dyn_args is not None:
723 try:
724 args.extend(node.dyn_args.as_const(eval_ctx))
725 except Exception as e:
726 raise Impossible() from e
728 if node.dyn_kwargs is not None:
729 try:
730 kwargs.update(node.dyn_kwargs.as_const(eval_ctx))
731 except Exception as e:
732 raise Impossible() from e
734 return args, kwargs
737class _FilterTestCommon(Expr):
738 fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
739 node: Expr
740 name: str
741 args: t.List[Expr]
742 kwargs: t.List[Pair]
743 dyn_args: t.Optional[Expr]
744 dyn_kwargs: t.Optional[Expr]
745 abstract = True
746 _is_filter = True
748 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
749 eval_ctx = get_eval_context(self, eval_ctx)
751 if eval_ctx.volatile:
752 raise Impossible()
754 if self._is_filter:
755 env_map = eval_ctx.environment.filters
756 else:
757 env_map = eval_ctx.environment.tests
759 func = env_map.get(self.name)
760 pass_arg = _PassArg.from_obj(func) # type: ignore
762 if func is None or pass_arg is _PassArg.context:
763 raise Impossible()
765 if eval_ctx.environment.is_async and (
766 getattr(func, "jinja_async_variant", False) is True
767 or inspect.iscoroutinefunction(func)
768 ):
769 raise Impossible()
771 args, kwargs = args_as_const(self, eval_ctx)
772 args.insert(0, self.node.as_const(eval_ctx))
774 if pass_arg is _PassArg.eval_context:
775 args.insert(0, eval_ctx)
776 elif pass_arg is _PassArg.environment:
777 args.insert(0, eval_ctx.environment)
779 try:
780 return func(*args, **kwargs)
781 except Exception as e:
782 raise Impossible() from e
785class Filter(_FilterTestCommon):
786 """Apply a filter to an expression. ``name`` is the name of the
787 filter, the other fields are the same as :class:`Call`.
789 If ``node`` is ``None``, the filter is being used in a filter block
790 and is applied to the content of the block.
791 """
793 node: t.Optional[Expr] # type: ignore
795 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
796 if self.node is None:
797 raise Impossible()
799 return super().as_const(eval_ctx=eval_ctx)
802class Test(_FilterTestCommon):
803 """Apply a test to an expression. ``name`` is the name of the test,
804 the other field are the same as :class:`Call`.
806 .. versionchanged:: 3.0
807 ``as_const`` shares the same logic for filters and tests. Tests
808 check for volatile, async, and ``@pass_context`` etc.
809 decorators.
810 """
812 _is_filter = False
815class Call(Expr):
816 """Calls an expression. `args` is a list of arguments, `kwargs` a list
817 of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`
818 and `dyn_kwargs` has to be either `None` or a node that is used as
819 node for dynamic positional (``*args``) or keyword (``**kwargs``)
820 arguments.
821 """
823 fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs")
824 node: Expr
825 args: t.List[Expr]
826 kwargs: t.List[Keyword]
827 dyn_args: t.Optional[Expr]
828 dyn_kwargs: t.Optional[Expr]
831class Getitem(Expr):
832 """Get an attribute or item from an expression and prefer the item."""
834 fields = ("node", "arg", "ctx")
835 node: Expr
836 arg: Expr
837 ctx: str
839 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
840 if self.ctx != "load":
841 raise Impossible()
843 eval_ctx = get_eval_context(self, eval_ctx)
845 try:
846 return eval_ctx.environment.getitem(
847 self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx)
848 )
849 except Exception as e:
850 raise Impossible() from e
853class Getattr(Expr):
854 """Get an attribute or item from an expression that is a ascii-only
855 bytestring and prefer the attribute.
856 """
858 fields = ("node", "attr", "ctx")
859 node: Expr
860 attr: str
861 ctx: str
863 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
864 if self.ctx != "load":
865 raise Impossible()
867 eval_ctx = get_eval_context(self, eval_ctx)
869 try:
870 return eval_ctx.environment.getattr(self.node.as_const(eval_ctx), self.attr)
871 except Exception as e:
872 raise Impossible() from e
875class Slice(Expr):
876 """Represents a slice object. This must only be used as argument for
877 :class:`Subscript`.
878 """
880 fields = ("start", "stop", "step")
881 start: t.Optional[Expr]
882 stop: t.Optional[Expr]
883 step: t.Optional[Expr]
885 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> slice:
886 eval_ctx = get_eval_context(self, eval_ctx)
888 def const(obj: t.Optional[Expr]) -> t.Optional[t.Any]:
889 if obj is None:
890 return None
891 return obj.as_const(eval_ctx)
893 return slice(const(self.start), const(self.stop), const(self.step))
896class Concat(Expr):
897 """Concatenates the list of expressions provided after converting
898 them to strings.
899 """
901 fields = ("nodes",)
902 nodes: t.List[Expr]
904 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
905 eval_ctx = get_eval_context(self, eval_ctx)
906 return "".join(str(x.as_const(eval_ctx)) for x in self.nodes)
909class Compare(Expr):
910 """Compares an expression with some other expressions. `ops` must be a
911 list of :class:`Operand`\\s.
912 """
914 fields = ("expr", "ops")
915 expr: Expr
916 ops: t.List["Operand"]
918 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
919 eval_ctx = get_eval_context(self, eval_ctx)
920 result = value = self.expr.as_const(eval_ctx)
922 try:
923 for op in self.ops:
924 new_value = op.expr.as_const(eval_ctx)
925 result = _cmpop_to_func[op.op](value, new_value)
927 if not result:
928 return False
930 value = new_value
931 except Exception as e:
932 raise Impossible() from e
934 return result
937class Operand(Helper):
938 """Holds an operator and an expression."""
940 fields = ("op", "expr")
941 op: str
942 expr: Expr
945class Mul(BinExpr):
946 """Multiplies the left with the right node."""
948 operator = "*"
951class Div(BinExpr):
952 """Divides the left by the right node."""
954 operator = "/"
957class FloorDiv(BinExpr):
958 """Divides the left by the right node and converts the
959 result into an integer by truncating.
960 """
962 operator = "//"
965class Add(BinExpr):
966 """Add the left to the right node."""
968 operator = "+"
971class Sub(BinExpr):
972 """Subtract the right from the left node."""
974 operator = "-"
977class Mod(BinExpr):
978 """Left modulo right."""
980 operator = "%"
983class Pow(BinExpr):
984 """Left to the power of right."""
986 operator = "**"
989class And(BinExpr):
990 """Short circuited AND."""
992 operator = "and"
994 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
995 eval_ctx = get_eval_context(self, eval_ctx)
996 return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
999class Or(BinExpr):
1000 """Short circuited OR."""
1002 operator = "or"
1004 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
1005 eval_ctx = get_eval_context(self, eval_ctx)
1006 return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
1009class Not(UnaryExpr):
1010 """Negate the expression."""
1012 operator = "not"
1015class Neg(UnaryExpr):
1016 """Make the expression negative."""
1018 operator = "-"
1021class Pos(UnaryExpr):
1022 """Make the expression positive (noop for most expressions)"""
1024 operator = "+"
1027# Helpers for extensions
1030class EnvironmentAttribute(Expr):
1031 """Loads an attribute from the environment object. This is useful for
1032 extensions that want to call a callback stored on the environment.
1033 """
1035 fields = ("name",)
1036 name: str
1039class ExtensionAttribute(Expr):
1040 """Returns the attribute of an extension bound to the environment.
1041 The identifier is the identifier of the :class:`Extension`.
1043 This node is usually constructed by calling the
1044 :meth:`~jinja2.ext.Extension.attr` method on an extension.
1045 """
1047 fields = ("identifier", "name")
1048 identifier: str
1049 name: str
1052class ImportedName(Expr):
1053 """If created with an import name the import name is returned on node
1054 access. For example ``ImportedName('cgi.escape')`` returns the `escape`
1055 function from the cgi module on evaluation. Imports are optimized by the
1056 compiler so there is no need to assign them to local variables.
1057 """
1059 fields = ("importname",)
1060 importname: str
1063class InternalName(Expr):
1064 """An internal name in the compiler. You cannot create these nodes
1065 yourself but the parser provides a
1066 :meth:`~jinja2.parser.Parser.free_identifier` method that creates
1067 a new identifier for you. This identifier is not available from the
1068 template and is not treated specially by the compiler.
1069 """
1071 fields = ("name",)
1072 name: str
1074 def __init__(self) -> None:
1075 raise TypeError(
1076 "Can't create internal names. Use the "
1077 "`free_identifier` method on a parser."
1078 )
1081class MarkSafe(Expr):
1082 """Mark the wrapped expression as safe (wrap it as `Markup`)."""
1084 fields = ("expr",)
1085 expr: Expr
1087 def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> Markup:
1088 eval_ctx = get_eval_context(self, eval_ctx)
1089 return Markup(self.expr.as_const(eval_ctx))
1092class MarkSafeIfAutoescape(Expr):
1093 """Mark the wrapped expression as safe (wrap it as `Markup`) but
1094 only if autoescaping is active.
1096 .. versionadded:: 2.5
1097 """
1099 fields = ("expr",)
1100 expr: Expr
1102 def as_const(
1103 self, eval_ctx: t.Optional[EvalContext] = None
1104 ) -> t.Union[Markup, t.Any]:
1105 eval_ctx = get_eval_context(self, eval_ctx)
1106 if eval_ctx.volatile:
1107 raise Impossible()
1108 expr = self.expr.as_const(eval_ctx)
1109 if eval_ctx.autoescape:
1110 return Markup(expr)
1111 return expr
1114class ContextReference(Expr):
1115 """Returns the current template context. It can be used like a
1116 :class:`Name` node, with a ``'load'`` ctx and will return the
1117 current :class:`~jinja2.runtime.Context` object.
1119 Here an example that assigns the current template name to a
1120 variable named `foo`::
1122 Assign(Name('foo', ctx='store'),
1123 Getattr(ContextReference(), 'name'))
1125 This is basically equivalent to using the
1126 :func:`~jinja2.pass_context` decorator when using the high-level
1127 API, which causes a reference to the context to be passed as the
1128 first argument to a function.
1129 """
1132class DerivedContextReference(Expr):
1133 """Return the current template context including locals. Behaves
1134 exactly like :class:`ContextReference`, but includes local
1135 variables, such as from a ``for`` loop.
1137 .. versionadded:: 2.11
1138 """
1141class Continue(Stmt):
1142 """Continue a loop."""
1145class Break(Stmt):
1146 """Break a loop."""
1149class Scope(Stmt):
1150 """An artificial scope."""
1152 fields = ("body",)
1153 body: t.List[Node]
1156class OverlayScope(Stmt):
1157 """An overlay scope for extensions. This is a largely unoptimized scope
1158 that however can be used to introduce completely arbitrary variables into
1159 a sub scope from a dictionary or dictionary like object. The `context`
1160 field has to evaluate to a dictionary object.
1162 Example usage::
1164 OverlayScope(context=self.call_method('get_context'),
1165 body=[...])
1167 .. versionadded:: 2.10
1168 """
1170 fields = ("context", "body")
1171 context: Expr
1172 body: t.List[Node]
1175class EvalContextModifier(Stmt):
1176 """Modifies the eval context. For each option that should be modified,
1177 a :class:`Keyword` has to be added to the :attr:`options` list.
1179 Example to change the `autoescape` setting::
1181 EvalContextModifier(options=[Keyword('autoescape', Const(True))])
1182 """
1184 fields = ("options",)
1185 options: t.List[Keyword]
1188class ScopedEvalContextModifier(EvalContextModifier):
1189 """Modifies the eval context and reverts it later. Works exactly like
1190 :class:`EvalContextModifier` but will only modify the
1191 :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
1192 """
1194 fields = ("body",)
1195 body: t.List[Node]
1198# make sure nobody creates custom nodes
1199def _failing_new(*args: t.Any, **kwargs: t.Any) -> "te.NoReturn":
1200 raise TypeError("can't create custom node types")
1203NodeType.__new__ = staticmethod(_failing_new) # type: ignore
1204del _failing_new