From 12cf076118570eebbff08c6b3090e0d4798447a1 Mon Sep 17 00:00:00 2001 From: cyfraeviolae Date: Wed, 3 Apr 2024 03:17:55 -0400 Subject: no venv --- venv/lib/python3.11/site-packages/jinja2/nodes.py | 1204 --------------------- 1 file changed, 1204 deletions(-) delete mode 100644 venv/lib/python3.11/site-packages/jinja2/nodes.py (limited to 'venv/lib/python3.11/site-packages/jinja2/nodes.py') diff --git a/venv/lib/python3.11/site-packages/jinja2/nodes.py b/venv/lib/python3.11/site-packages/jinja2/nodes.py deleted file mode 100644 index b2f88d9..0000000 --- a/venv/lib/python3.11/site-packages/jinja2/nodes.py +++ /dev/null @@ -1,1204 +0,0 @@ -"""AST nodes generated by the parser for the compiler. Also provides -some node tree helper functions used by the parser and compiler in order -to normalize nodes. -""" -import inspect -import operator -import typing as t -from collections import deque - -from markupsafe import Markup - -from .utils import _PassArg - -if t.TYPE_CHECKING: - import typing_extensions as te - from .environment import Environment - -_NodeBound = t.TypeVar("_NodeBound", bound="Node") - -_binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { - "*": operator.mul, - "/": operator.truediv, - "//": operator.floordiv, - "**": operator.pow, - "%": operator.mod, - "+": operator.add, - "-": operator.sub, -} - -_uaop_to_func: t.Dict[str, t.Callable[[t.Any], t.Any]] = { - "not": operator.not_, - "+": operator.pos, - "-": operator.neg, -} - -_cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { - "eq": operator.eq, - "ne": operator.ne, - "gt": operator.gt, - "gteq": operator.ge, - "lt": operator.lt, - "lteq": operator.le, - "in": lambda a, b: a in b, - "notin": lambda a, b: a not in b, -} - - -class Impossible(Exception): - """Raised if the node could not perform a requested action.""" - - -class NodeType(type): - """A metaclass for nodes that handles the field and attribute - inheritance. fields and attributes from the parent class are - automatically forwarded to the child.""" - - def __new__(mcs, name, bases, d): # type: ignore - for attr in "fields", "attributes": - storage = [] - storage.extend(getattr(bases[0] if bases else object, attr, ())) - storage.extend(d.get(attr, ())) - assert len(bases) <= 1, "multiple inheritance not allowed" - assert len(storage) == len(set(storage)), "layout conflict" - d[attr] = tuple(storage) - d.setdefault("abstract", False) - return type.__new__(mcs, name, bases, d) - - -class EvalContext: - """Holds evaluation time information. Custom attributes can be attached - to it in extensions. - """ - - def __init__( - self, environment: "Environment", template_name: t.Optional[str] = None - ) -> None: - self.environment = environment - if callable(environment.autoescape): - self.autoescape = environment.autoescape(template_name) - else: - self.autoescape = environment.autoescape - self.volatile = False - - def save(self) -> t.Mapping[str, t.Any]: - return self.__dict__.copy() - - def revert(self, old: t.Mapping[str, t.Any]) -> None: - self.__dict__.clear() - self.__dict__.update(old) - - -def get_eval_context(node: "Node", ctx: t.Optional[EvalContext]) -> EvalContext: - if ctx is None: - if node.environment is None: - raise RuntimeError( - "if no eval context is passed, the node must have an" - " attached environment." - ) - return EvalContext(node.environment) - return ctx - - -class Node(metaclass=NodeType): - """Baseclass for all Jinja nodes. There are a number of nodes available - of different types. There are four major types: - - - :class:`Stmt`: statements - - :class:`Expr`: expressions - - :class:`Helper`: helper nodes - - :class:`Template`: the outermost wrapper node - - All nodes have fields and attributes. Fields may be other nodes, lists, - or arbitrary values. Fields are passed to the constructor as regular - positional arguments, attributes as keyword arguments. Each node has - two attributes: `lineno` (the line number of the node) and `environment`. - The `environment` attribute is set at the end of the parsing process for - all nodes automatically. - """ - - fields: t.Tuple[str, ...] = () - attributes: t.Tuple[str, ...] = ("lineno", "environment") - abstract = True - - lineno: int - environment: t.Optional["Environment"] - - def __init__(self, *fields: t.Any, **attributes: t.Any) -> None: - if self.abstract: - raise TypeError("abstract nodes are not instantiable") - if fields: - if len(fields) != len(self.fields): - if not self.fields: - raise TypeError(f"{type(self).__name__!r} takes 0 arguments") - raise TypeError( - f"{type(self).__name__!r} takes 0 or {len(self.fields)}" - f" argument{'s' if len(self.fields) != 1 else ''}" - ) - for name, arg in zip(self.fields, fields): - setattr(self, name, arg) - for attr in self.attributes: - setattr(self, attr, attributes.pop(attr, None)) - if attributes: - raise TypeError(f"unknown attribute {next(iter(attributes))!r}") - - def iter_fields( - self, - exclude: t.Optional[t.Container[str]] = None, - only: t.Optional[t.Container[str]] = None, - ) -> t.Iterator[t.Tuple[str, t.Any]]: - """This method iterates over all fields that are defined and yields - ``(key, value)`` tuples. Per default all fields are returned, but - it's possible to limit that to some fields by providing the `only` - parameter or to exclude some using the `exclude` parameter. Both - should be sets or tuples of field names. - """ - for name in self.fields: - if ( - (exclude is None and only is None) - or (exclude is not None and name not in exclude) - or (only is not None and name in only) - ): - try: - yield name, getattr(self, name) - except AttributeError: - pass - - def iter_child_nodes( - self, - exclude: t.Optional[t.Container[str]] = None, - only: t.Optional[t.Container[str]] = None, - ) -> t.Iterator["Node"]: - """Iterates over all direct child nodes of the node. This iterates - over all fields and yields the values of they are nodes. If the value - of a field is a list all the nodes in that list are returned. - """ - for _, item in self.iter_fields(exclude, only): - if isinstance(item, list): - for n in item: - if isinstance(n, Node): - yield n - elif isinstance(item, Node): - yield item - - def find(self, node_type: t.Type[_NodeBound]) -> t.Optional[_NodeBound]: - """Find the first node of a given type. If no such node exists the - return value is `None`. - """ - for result in self.find_all(node_type): - return result - - return None - - def find_all( - self, node_type: t.Union[t.Type[_NodeBound], t.Tuple[t.Type[_NodeBound], ...]] - ) -> t.Iterator[_NodeBound]: - """Find all the nodes of a given type. If the type is a tuple, - the check is performed for any of the tuple items. - """ - for child in self.iter_child_nodes(): - if isinstance(child, node_type): - yield child # type: ignore - yield from child.find_all(node_type) - - def set_ctx(self, ctx: str) -> "Node": - """Reset the context of a node and all child nodes. Per default the - parser will all generate nodes that have a 'load' context as it's the - most common one. This method is used in the parser to set assignment - targets and other nodes to a store context. - """ - todo = deque([self]) - while todo: - node = todo.popleft() - if "ctx" in node.fields: - node.ctx = ctx # type: ignore - todo.extend(node.iter_child_nodes()) - return self - - def set_lineno(self, lineno: int, override: bool = False) -> "Node": - """Set the line numbers of the node and children.""" - todo = deque([self]) - while todo: - node = todo.popleft() - if "lineno" in node.attributes: - if node.lineno is None or override: - node.lineno = lineno - todo.extend(node.iter_child_nodes()) - return self - - def set_environment(self, environment: "Environment") -> "Node": - """Set the environment for all nodes.""" - todo = deque([self]) - while todo: - node = todo.popleft() - node.environment = environment - todo.extend(node.iter_child_nodes()) - return self - - def __eq__(self, other: t.Any) -> bool: - if type(self) is not type(other): - return NotImplemented - - return tuple(self.iter_fields()) == tuple(other.iter_fields()) - - __hash__ = object.__hash__ - - def __repr__(self) -> str: - args_str = ", ".join(f"{a}={getattr(self, a, None)!r}" for a in self.fields) - return f"{type(self).__name__}({args_str})" - - def dump(self) -> str: - def _dump(node: t.Union[Node, t.Any]) -> None: - if not isinstance(node, Node): - buf.append(repr(node)) - return - - buf.append(f"nodes.{type(node).__name__}(") - if not node.fields: - buf.append(")") - return - for idx, field in enumerate(node.fields): - if idx: - buf.append(", ") - value = getattr(node, field) - if isinstance(value, list): - buf.append("[") - for idx, item in enumerate(value): - if idx: - buf.append(", ") - _dump(item) - buf.append("]") - else: - _dump(value) - buf.append(")") - - buf: t.List[str] = [] - _dump(self) - return "".join(buf) - - -class Stmt(Node): - """Base node for all statements.""" - - abstract = True - - -class Helper(Node): - """Nodes that exist in a specific context only.""" - - abstract = True - - -class Template(Node): - """Node that represents a template. This must be the outermost node that - is passed to the compiler. - """ - - fields = ("body",) - body: t.List[Node] - - -class Output(Stmt): - """A node that holds multiple expressions which are then printed out. - This is used both for the `print` statement and the regular template data. - """ - - fields = ("nodes",) - nodes: t.List["Expr"] - - -class Extends(Stmt): - """Represents an extends statement.""" - - fields = ("template",) - template: "Expr" - - -class For(Stmt): - """The for loop. `target` is the target for the iteration (usually a - :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list - of nodes that are used as loop-body, and `else_` a list of nodes for the - `else` block. If no else node exists it has to be an empty list. - - For filtered nodes an expression can be stored as `test`, otherwise `None`. - """ - - fields = ("target", "iter", "body", "else_", "test", "recursive") - target: Node - iter: Node - body: t.List[Node] - else_: t.List[Node] - test: t.Optional[Node] - recursive: bool - - -class If(Stmt): - """If `test` is true, `body` is rendered, else `else_`.""" - - fields = ("test", "body", "elif_", "else_") - test: Node - body: t.List[Node] - elif_: t.List["If"] - else_: t.List[Node] - - -class Macro(Stmt): - """A macro definition. `name` is the name of the macro, `args` a list of - arguments and `defaults` a list of defaults if there are any. `body` is - a list of nodes for the macro body. - """ - - fields = ("name", "args", "defaults", "body") - name: str - args: t.List["Name"] - defaults: t.List["Expr"] - body: t.List[Node] - - -class CallBlock(Stmt): - """Like a macro without a name but a call instead. `call` is called with - the unnamed macro as `caller` argument this node holds. - """ - - fields = ("call", "args", "defaults", "body") - call: "Call" - args: t.List["Name"] - defaults: t.List["Expr"] - body: t.List[Node] - - -class FilterBlock(Stmt): - """Node for filter sections.""" - - fields = ("body", "filter") - body: t.List[Node] - filter: "Filter" - - -class With(Stmt): - """Specific node for with statements. In older versions of Jinja the - with statement was implemented on the base of the `Scope` node instead. - - .. versionadded:: 2.9.3 - """ - - fields = ("targets", "values", "body") - targets: t.List["Expr"] - values: t.List["Expr"] - body: t.List[Node] - - -class Block(Stmt): - """A node that represents a block. - - .. versionchanged:: 3.0.0 - the `required` field was added. - """ - - fields = ("name", "body", "scoped", "required") - name: str - body: t.List[Node] - scoped: bool - required: bool - - -class Include(Stmt): - """A node that represents the include tag.""" - - fields = ("template", "with_context", "ignore_missing") - template: "Expr" - with_context: bool - ignore_missing: bool - - -class Import(Stmt): - """A node that represents the import tag.""" - - fields = ("template", "target", "with_context") - template: "Expr" - target: str - with_context: bool - - -class FromImport(Stmt): - """A node that represents the from import tag. It's important to not - pass unsafe names to the name attribute. The compiler translates the - attribute lookups directly into getattr calls and does *not* use the - subscript callback of the interface. As exported variables may not - start with double underscores (which the parser asserts) this is not a - problem for regular Jinja code, but if this node is used in an extension - extra care must be taken. - - The list of names may contain tuples if aliases are wanted. - """ - - fields = ("template", "names", "with_context") - template: "Expr" - names: t.List[t.Union[str, t.Tuple[str, str]]] - with_context: bool - - -class ExprStmt(Stmt): - """A statement that evaluates an expression and discards the result.""" - - fields = ("node",) - node: Node - - -class Assign(Stmt): - """Assigns an expression to a target.""" - - fields = ("target", "node") - target: "Expr" - node: Node - - -class AssignBlock(Stmt): - """Assigns a block to a target.""" - - fields = ("target", "filter", "body") - target: "Expr" - filter: t.Optional["Filter"] - body: t.List[Node] - - -class Expr(Node): - """Baseclass for all expressions.""" - - abstract = True - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - """Return the value of the expression as constant or raise - :exc:`Impossible` if this was not possible. - - An :class:`EvalContext` can be provided, if none is given - a default context is created which requires the nodes to have - an attached environment. - - .. versionchanged:: 2.4 - the `eval_ctx` parameter was added. - """ - raise Impossible() - - def can_assign(self) -> bool: - """Check if it's possible to assign something to this node.""" - return False - - -class BinExpr(Expr): - """Baseclass for all binary expressions.""" - - fields = ("left", "right") - left: Expr - right: Expr - operator: str - abstract = True - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - eval_ctx = get_eval_context(self, eval_ctx) - - # intercepted operators cannot be folded at compile time - if ( - eval_ctx.environment.sandboxed - and self.operator in eval_ctx.environment.intercepted_binops # type: ignore - ): - raise Impossible() - f = _binop_to_func[self.operator] - try: - return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx)) - except Exception as e: - raise Impossible() from e - - -class UnaryExpr(Expr): - """Baseclass for all unary expressions.""" - - fields = ("node",) - node: Expr - operator: str - abstract = True - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - eval_ctx = get_eval_context(self, eval_ctx) - - # intercepted operators cannot be folded at compile time - if ( - eval_ctx.environment.sandboxed - and self.operator in eval_ctx.environment.intercepted_unops # type: ignore - ): - raise Impossible() - f = _uaop_to_func[self.operator] - try: - return f(self.node.as_const(eval_ctx)) - except Exception as e: - raise Impossible() from e - - -class Name(Expr): - """Looks up a name or stores a value in a name. - The `ctx` of the node can be one of the following values: - - - `store`: store a value in the name - - `load`: load that name - - `param`: like `store` but if the name was defined as function parameter. - """ - - fields = ("name", "ctx") - name: str - ctx: str - - def can_assign(self) -> bool: - return self.name not in {"true", "false", "none", "True", "False", "None"} - - -class NSRef(Expr): - """Reference to a namespace value assignment""" - - fields = ("name", "attr") - name: str - attr: str - - def can_assign(self) -> bool: - # We don't need any special checks here; NSRef assignments have a - # runtime check to ensure the target is a namespace object which will - # have been checked already as it is created using a normal assignment - # which goes through a `Name` node. - return True - - -class Literal(Expr): - """Baseclass for literals.""" - - abstract = True - - -class Const(Literal): - """All constant values. The parser will return this node for simple - constants such as ``42`` or ``"foo"`` but it can be used to store more - complex values such as lists too. Only constants with a safe - representation (objects where ``eval(repr(x)) == x`` is true). - """ - - fields = ("value",) - value: t.Any - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - return self.value - - @classmethod - def from_untrusted( - cls, - value: t.Any, - lineno: t.Optional[int] = None, - environment: "t.Optional[Environment]" = None, - ) -> "Const": - """Return a const object if the value is representable as - constant value in the generated code, otherwise it will raise - an `Impossible` exception. - """ - from .compiler import has_safe_repr - - if not has_safe_repr(value): - raise Impossible() - return cls(value, lineno=lineno, environment=environment) - - -class TemplateData(Literal): - """A constant template string.""" - - fields = ("data",) - data: str - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str: - eval_ctx = get_eval_context(self, eval_ctx) - if eval_ctx.volatile: - raise Impossible() - if eval_ctx.autoescape: - return Markup(self.data) - return self.data - - -class Tuple(Literal): - """For loop unpacking and some other things like multiple arguments - for subscripts. Like for :class:`Name` `ctx` specifies if the tuple - is used for loading the names or storing. - """ - - fields = ("items", "ctx") - items: t.List[Expr] - ctx: str - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[t.Any, ...]: - eval_ctx = get_eval_context(self, eval_ctx) - return tuple(x.as_const(eval_ctx) for x in self.items) - - def can_assign(self) -> bool: - for item in self.items: - if not item.can_assign(): - return False - return True - - -class List(Literal): - """Any list literal such as ``[1, 2, 3]``""" - - fields = ("items",) - items: t.List[Expr] - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.List[t.Any]: - eval_ctx = get_eval_context(self, eval_ctx) - return [x.as_const(eval_ctx) for x in self.items] - - -class Dict(Literal): - """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of - :class:`Pair` nodes. - """ - - fields = ("items",) - items: t.List["Pair"] - - def as_const( - self, eval_ctx: t.Optional[EvalContext] = None - ) -> t.Dict[t.Any, t.Any]: - eval_ctx = get_eval_context(self, eval_ctx) - return dict(x.as_const(eval_ctx) for x in self.items) - - -class Pair(Helper): - """A key, value pair for dicts.""" - - fields = ("key", "value") - key: Expr - value: Expr - - def as_const( - self, eval_ctx: t.Optional[EvalContext] = None - ) -> t.Tuple[t.Any, t.Any]: - eval_ctx = get_eval_context(self, eval_ctx) - return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx) - - -class Keyword(Helper): - """A key, value pair for keyword arguments where key is a string.""" - - fields = ("key", "value") - key: str - value: Expr - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[str, t.Any]: - eval_ctx = get_eval_context(self, eval_ctx) - return self.key, self.value.as_const(eval_ctx) - - -class CondExpr(Expr): - """A conditional expression (inline if expression). (``{{ - foo if bar else baz }}``) - """ - - fields = ("test", "expr1", "expr2") - test: Expr - expr1: Expr - expr2: t.Optional[Expr] - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - eval_ctx = get_eval_context(self, eval_ctx) - if self.test.as_const(eval_ctx): - return self.expr1.as_const(eval_ctx) - - # if we evaluate to an undefined object, we better do that at runtime - if self.expr2 is None: - raise Impossible() - - return self.expr2.as_const(eval_ctx) - - -def args_as_const( - node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext] -) -> t.Tuple[t.List[t.Any], t.Dict[t.Any, t.Any]]: - args = [x.as_const(eval_ctx) for x in node.args] - kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs) - - if node.dyn_args is not None: - try: - args.extend(node.dyn_args.as_const(eval_ctx)) - except Exception as e: - raise Impossible() from e - - if node.dyn_kwargs is not None: - try: - kwargs.update(node.dyn_kwargs.as_const(eval_ctx)) - except Exception as e: - raise Impossible() from e - - return args, kwargs - - -class _FilterTestCommon(Expr): - fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs") - node: Expr - name: str - args: t.List[Expr] - kwargs: t.List[Pair] - dyn_args: t.Optional[Expr] - dyn_kwargs: t.Optional[Expr] - abstract = True - _is_filter = True - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - eval_ctx = get_eval_context(self, eval_ctx) - - if eval_ctx.volatile: - raise Impossible() - - if self._is_filter: - env_map = eval_ctx.environment.filters - else: - env_map = eval_ctx.environment.tests - - func = env_map.get(self.name) - pass_arg = _PassArg.from_obj(func) # type: ignore - - if func is None or pass_arg is _PassArg.context: - raise Impossible() - - if eval_ctx.environment.is_async and ( - getattr(func, "jinja_async_variant", False) is True - or inspect.iscoroutinefunction(func) - ): - raise Impossible() - - args, kwargs = args_as_const(self, eval_ctx) - args.insert(0, self.node.as_const(eval_ctx)) - - if pass_arg is _PassArg.eval_context: - args.insert(0, eval_ctx) - elif pass_arg is _PassArg.environment: - args.insert(0, eval_ctx.environment) - - try: - return func(*args, **kwargs) - except Exception as e: - raise Impossible() from e - - -class Filter(_FilterTestCommon): - """Apply a filter to an expression. ``name`` is the name of the - filter, the other fields are the same as :class:`Call`. - - If ``node`` is ``None``, the filter is being used in a filter block - and is applied to the content of the block. - """ - - node: t.Optional[Expr] # type: ignore - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - if self.node is None: - raise Impossible() - - return super().as_const(eval_ctx=eval_ctx) - - -class Test(_FilterTestCommon): - """Apply a test to an expression. ``name`` is the name of the test, - the other field are the same as :class:`Call`. - - .. versionchanged:: 3.0 - ``as_const`` shares the same logic for filters and tests. Tests - check for volatile, async, and ``@pass_context`` etc. - decorators. - """ - - _is_filter = False - - -class Call(Expr): - """Calls an expression. `args` is a list of arguments, `kwargs` a list - of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args` - and `dyn_kwargs` has to be either `None` or a node that is used as - node for dynamic positional (``*args``) or keyword (``**kwargs``) - arguments. - """ - - fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs") - node: Expr - args: t.List[Expr] - kwargs: t.List[Keyword] - dyn_args: t.Optional[Expr] - dyn_kwargs: t.Optional[Expr] - - -class Getitem(Expr): - """Get an attribute or item from an expression and prefer the item.""" - - fields = ("node", "arg", "ctx") - node: Expr - arg: Expr - ctx: str - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - if self.ctx != "load": - raise Impossible() - - eval_ctx = get_eval_context(self, eval_ctx) - - try: - return eval_ctx.environment.getitem( - self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx) - ) - except Exception as e: - raise Impossible() from e - - -class Getattr(Expr): - """Get an attribute or item from an expression that is a ascii-only - bytestring and prefer the attribute. - """ - - fields = ("node", "attr", "ctx") - node: Expr - attr: str - ctx: str - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - if self.ctx != "load": - raise Impossible() - - eval_ctx = get_eval_context(self, eval_ctx) - - try: - return eval_ctx.environment.getattr(self.node.as_const(eval_ctx), self.attr) - except Exception as e: - raise Impossible() from e - - -class Slice(Expr): - """Represents a slice object. This must only be used as argument for - :class:`Subscript`. - """ - - fields = ("start", "stop", "step") - start: t.Optional[Expr] - stop: t.Optional[Expr] - step: t.Optional[Expr] - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> slice: - eval_ctx = get_eval_context(self, eval_ctx) - - def const(obj: t.Optional[Expr]) -> t.Optional[t.Any]: - if obj is None: - return None - return obj.as_const(eval_ctx) - - return slice(const(self.start), const(self.stop), const(self.step)) - - -class Concat(Expr): - """Concatenates the list of expressions provided after converting - them to strings. - """ - - fields = ("nodes",) - nodes: t.List[Expr] - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str: - eval_ctx = get_eval_context(self, eval_ctx) - return "".join(str(x.as_const(eval_ctx)) for x in self.nodes) - - -class Compare(Expr): - """Compares an expression with some other expressions. `ops` must be a - list of :class:`Operand`\\s. - """ - - fields = ("expr", "ops") - expr: Expr - ops: t.List["Operand"] - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - eval_ctx = get_eval_context(self, eval_ctx) - result = value = self.expr.as_const(eval_ctx) - - try: - for op in self.ops: - new_value = op.expr.as_const(eval_ctx) - result = _cmpop_to_func[op.op](value, new_value) - - if not result: - return False - - value = new_value - except Exception as e: - raise Impossible() from e - - return result - - -class Operand(Helper): - """Holds an operator and an expression.""" - - fields = ("op", "expr") - op: str - expr: Expr - - -class Mul(BinExpr): - """Multiplies the left with the right node.""" - - operator = "*" - - -class Div(BinExpr): - """Divides the left by the right node.""" - - operator = "/" - - -class FloorDiv(BinExpr): - """Divides the left by the right node and converts the - result into an integer by truncating. - """ - - operator = "//" - - -class Add(BinExpr): - """Add the left to the right node.""" - - operator = "+" - - -class Sub(BinExpr): - """Subtract the right from the left node.""" - - operator = "-" - - -class Mod(BinExpr): - """Left modulo right.""" - - operator = "%" - - -class Pow(BinExpr): - """Left to the power of right.""" - - operator = "**" - - -class And(BinExpr): - """Short circuited AND.""" - - operator = "and" - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - eval_ctx = get_eval_context(self, eval_ctx) - return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx) - - -class Or(BinExpr): - """Short circuited OR.""" - - operator = "or" - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: - eval_ctx = get_eval_context(self, eval_ctx) - return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx) - - -class Not(UnaryExpr): - """Negate the expression.""" - - operator = "not" - - -class Neg(UnaryExpr): - """Make the expression negative.""" - - operator = "-" - - -class Pos(UnaryExpr): - """Make the expression positive (noop for most expressions)""" - - operator = "+" - - -# Helpers for extensions - - -class EnvironmentAttribute(Expr): - """Loads an attribute from the environment object. This is useful for - extensions that want to call a callback stored on the environment. - """ - - fields = ("name",) - name: str - - -class ExtensionAttribute(Expr): - """Returns the attribute of an extension bound to the environment. - The identifier is the identifier of the :class:`Extension`. - - This node is usually constructed by calling the - :meth:`~jinja2.ext.Extension.attr` method on an extension. - """ - - fields = ("identifier", "name") - identifier: str - name: str - - -class ImportedName(Expr): - """If created with an import name the import name is returned on node - access. For example ``ImportedName('cgi.escape')`` returns the `escape` - function from the cgi module on evaluation. Imports are optimized by the - compiler so there is no need to assign them to local variables. - """ - - fields = ("importname",) - importname: str - - -class InternalName(Expr): - """An internal name in the compiler. You cannot create these nodes - yourself but the parser provides a - :meth:`~jinja2.parser.Parser.free_identifier` method that creates - a new identifier for you. This identifier is not available from the - template and is not treated specially by the compiler. - """ - - fields = ("name",) - name: str - - def __init__(self) -> None: - raise TypeError( - "Can't create internal names. Use the " - "`free_identifier` method on a parser." - ) - - -class MarkSafe(Expr): - """Mark the wrapped expression as safe (wrap it as `Markup`).""" - - fields = ("expr",) - expr: Expr - - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> Markup: - eval_ctx = get_eval_context(self, eval_ctx) - return Markup(self.expr.as_const(eval_ctx)) - - -class MarkSafeIfAutoescape(Expr): - """Mark the wrapped expression as safe (wrap it as `Markup`) but - only if autoescaping is active. - - .. versionadded:: 2.5 - """ - - fields = ("expr",) - expr: Expr - - def as_const( - self, eval_ctx: t.Optional[EvalContext] = None - ) -> t.Union[Markup, t.Any]: - eval_ctx = get_eval_context(self, eval_ctx) - if eval_ctx.volatile: - raise Impossible() - expr = self.expr.as_const(eval_ctx) - if eval_ctx.autoescape: - return Markup(expr) - return expr - - -class ContextReference(Expr): - """Returns the current template context. It can be used like a - :class:`Name` node, with a ``'load'`` ctx and will return the - current :class:`~jinja2.runtime.Context` object. - - Here an example that assigns the current template name to a - variable named `foo`:: - - Assign(Name('foo', ctx='store'), - Getattr(ContextReference(), 'name')) - - This is basically equivalent to using the - :func:`~jinja2.pass_context` decorator when using the high-level - API, which causes a reference to the context to be passed as the - first argument to a function. - """ - - -class DerivedContextReference(Expr): - """Return the current template context including locals. Behaves - exactly like :class:`ContextReference`, but includes local - variables, such as from a ``for`` loop. - - .. versionadded:: 2.11 - """ - - -class Continue(Stmt): - """Continue a loop.""" - - -class Break(Stmt): - """Break a loop.""" - - -class Scope(Stmt): - """An artificial scope.""" - - fields = ("body",) - body: t.List[Node] - - -class OverlayScope(Stmt): - """An overlay scope for extensions. This is a largely unoptimized scope - that however can be used to introduce completely arbitrary variables into - a sub scope from a dictionary or dictionary like object. The `context` - field has to evaluate to a dictionary object. - - Example usage:: - - OverlayScope(context=self.call_method('get_context'), - body=[...]) - - .. versionadded:: 2.10 - """ - - fields = ("context", "body") - context: Expr - body: t.List[Node] - - -class EvalContextModifier(Stmt): - """Modifies the eval context. For each option that should be modified, - a :class:`Keyword` has to be added to the :attr:`options` list. - - Example to change the `autoescape` setting:: - - EvalContextModifier(options=[Keyword('autoescape', Const(True))]) - """ - - fields = ("options",) - options: t.List[Keyword] - - -class ScopedEvalContextModifier(EvalContextModifier): - """Modifies the eval context and reverts it later. Works exactly like - :class:`EvalContextModifier` but will only modify the - :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`. - """ - - fields = ("body",) - body: t.List[Node] - - -# make sure nobody creates custom nodes -def _failing_new(*args: t.Any, **kwargs: t.Any) -> "te.NoReturn": - raise TypeError("can't create custom node types") - - -NodeType.__new__ = staticmethod(_failing_new) # type: ignore -del _failing_new -- cgit v1.2.3