Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
nodes.py1207 linesDownload Raw Back to jinja2
1"""AST nodes generated by the parser for the compiler. Also provides2some node tree helper functions used by the parser and compiler in order3to normalize nodes.4"""5 6import inspect7import operator8import typing as t9from collections import deque10 11from markupsafe import Markup12 13from .utils import _PassArg14 15if t.TYPE_CHECKING:16    import typing_extensions as te17 18    from .environment import Environment19 20_NodeBound = t.TypeVar("_NodeBound", bound="Node")21 22_binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {23    "*": operator.mul,24    "/": operator.truediv,25    "//": operator.floordiv,26    "**": operator.pow,27    "%": operator.mod,28    "+": operator.add,29    "-": operator.sub,30}31 32_uaop_to_func: t.Dict[str, t.Callable[[t.Any], t.Any]] = {33    "not": operator.not_,34    "+": operator.pos,35    "-": operator.neg,36}37 38_cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {39    "eq": operator.eq,40    "ne": operator.ne,41    "gt": operator.gt,42    "gteq": operator.ge,43    "lt": operator.lt,44    "lteq": operator.le,45    "in": lambda a, b: a in b,46    "notin": lambda a, b: a not in b,47}48 49 50class Impossible(Exception):51    """Raised if the node could not perform a requested action."""52 53 54class NodeType(type):55    """A metaclass for nodes that handles the field and attribute56    inheritance.  fields and attributes from the parent class are57    automatically forwarded to the child."""58 59    def __new__(mcs, name, bases, d):  # type: ignore60        for attr in "fields", "attributes":61            storage: t.List[t.Tuple[str, ...]] = []62            storage.extend(getattr(bases[0] if bases else object, attr, ()))63            storage.extend(d.get(attr, ()))64            assert len(bases) <= 1, "multiple inheritance not allowed"65            assert len(storage) == len(set(storage)), "layout conflict"66            d[attr] = tuple(storage)67        d.setdefault("abstract", False)68        return type.__new__(mcs, name, bases, d)69 70 71class EvalContext:72    """Holds evaluation time information.  Custom attributes can be attached73    to it in extensions.74    """75 76    def __init__(77        self, environment: "Environment", template_name: t.Optional[str] = None78    ) -> None:79        self.environment = environment80        if callable(environment.autoescape):81            self.autoescape = environment.autoescape(template_name)82        else:83            self.autoescape = environment.autoescape84        self.volatile = False85 86    def save(self) -> t.Mapping[str, t.Any]:87        return self.__dict__.copy()88 89    def revert(self, old: t.Mapping[str, t.Any]) -> None:90        self.__dict__.clear()91        self.__dict__.update(old)92 93 94def get_eval_context(node: "Node", ctx: t.Optional[EvalContext]) -> EvalContext:95    if ctx is None:96        if node.environment is None:97            raise RuntimeError(98                "if no eval context is passed, the node must have an"99                " attached environment."100            )101        return EvalContext(node.environment)102    return ctx103 104 105class Node(metaclass=NodeType):106    """Baseclass for all Jinja nodes.  There are a number of nodes available107    of different types.  There are four major types:108 109    -   :class:`Stmt`: statements110    -   :class:`Expr`: expressions111    -   :class:`Helper`: helper nodes112    -   :class:`Template`: the outermost wrapper node113 114    All nodes have fields and attributes.  Fields may be other nodes, lists,115    or arbitrary values.  Fields are passed to the constructor as regular116    positional arguments, attributes as keyword arguments.  Each node has117    two attributes: `lineno` (the line number of the node) and `environment`.118    The `environment` attribute is set at the end of the parsing process for119    all nodes automatically.120    """121 122    fields: t.Tuple[str, ...] = ()123    attributes: t.Tuple[str, ...] = ("lineno", "environment")124    abstract = True125 126    lineno: int127    environment: t.Optional["Environment"]128 129    def __init__(self, *fields: t.Any, **attributes: t.Any) -> None:130        if self.abstract:131            raise TypeError("abstract nodes are not instantiable")132        if fields:133            if len(fields) != len(self.fields):134                if not self.fields:135                    raise TypeError(f"{type(self).__name__!r} takes 0 arguments")136                raise TypeError(137                    f"{type(self).__name__!r} takes 0 or {len(self.fields)}"138                    f" argument{'s' if len(self.fields) != 1 else ''}"139                )140            for name, arg in zip(self.fields, fields):141                setattr(self, name, arg)142        for attr in self.attributes:143            setattr(self, attr, attributes.pop(attr, None))144        if attributes:145            raise TypeError(f"unknown attribute {next(iter(attributes))!r}")146 147    def iter_fields(148        self,149        exclude: t.Optional[t.Container[str]] = None,150        only: t.Optional[t.Container[str]] = None,151    ) -> t.Iterator[t.Tuple[str, t.Any]]:152        """This method iterates over all fields that are defined and yields153        ``(key, value)`` tuples.  Per default all fields are returned, but154        it's possible to limit that to some fields by providing the `only`155        parameter or to exclude some using the `exclude` parameter.  Both156        should be sets or tuples of field names.157        """158        for name in self.fields:159            if (160                (exclude is None and only is None)161                or (exclude is not None and name not in exclude)162                or (only is not None and name in only)163            ):164                try:165                    yield name, getattr(self, name)166                except AttributeError:167                    pass168 169    def iter_child_nodes(170        self,171        exclude: t.Optional[t.Container[str]] = None,172        only: t.Optional[t.Container[str]] = None,173    ) -> t.Iterator["Node"]:174        """Iterates over all direct child nodes of the node.  This iterates175        over all fields and yields the values of they are nodes.  If the value176        of a field is a list all the nodes in that list are returned.177        """178        for _, item in self.iter_fields(exclude, only):179            if isinstance(item, list):180                for n in item:181                    if isinstance(n, Node):182                        yield n183            elif isinstance(item, Node):184                yield item185 186    def find(self, node_type: t.Type[_NodeBound]) -> t.Optional[_NodeBound]:187        """Find the first node of a given type.  If no such node exists the188        return value is `None`.189        """190        for result in self.find_all(node_type):191            return result192 193        return None194 195    def find_all(196        self, node_type: t.Union[t.Type[_NodeBound], t.Tuple[t.Type[_NodeBound], ...]]197    ) -> t.Iterator[_NodeBound]:198        """Find all the nodes of a given type.  If the type is a tuple,199        the check is performed for any of the tuple items.200        """201        for child in self.iter_child_nodes():202            if isinstance(child, node_type):203                yield child  # type: ignore204            yield from child.find_all(node_type)205 206    def set_ctx(self, ctx: str) -> "Node":207        """Reset the context of a node and all child nodes.  Per default the208        parser will all generate nodes that have a 'load' context as it's the209        most common one.  This method is used in the parser to set assignment210        targets and other nodes to a store context.211        """212        todo = deque([self])213        while todo:214            node = todo.popleft()215            if "ctx" in node.fields:216                node.ctx = ctx  # type: ignore217            todo.extend(node.iter_child_nodes())218        return self219 220    def set_lineno(self, lineno: int, override: bool = False) -> "Node":221        """Set the line numbers of the node and children."""222        todo = deque([self])223        while todo:224            node = todo.popleft()225            if "lineno" in node.attributes:226                if node.lineno is None or override:227                    node.lineno = lineno228            todo.extend(node.iter_child_nodes())229        return self230 231    def set_environment(self, environment: "Environment") -> "Node":232        """Set the environment for all nodes."""233        todo = deque([self])234        while todo:235            node = todo.popleft()236            node.environment = environment237            todo.extend(node.iter_child_nodes())238        return self239 240    def __eq__(self, other: t.Any) -> bool:241        if type(self) is not type(other):242            return NotImplemented243 244        return tuple(self.iter_fields()) == tuple(other.iter_fields())245 246    __hash__ = object.__hash__247 248    def __repr__(self) -> str:249        args_str = ", ".join(f"{a}={getattr(self, a, None)!r}" for a in self.fields)250        return f"{type(self).__name__}({args_str})"251 252    def dump(self) -> str:253        def _dump(node: t.Union[Node, t.Any]) -> None:254            if not isinstance(node, Node):255                buf.append(repr(node))256                return257 258            buf.append(f"nodes.{type(node).__name__}(")259            if not node.fields:260                buf.append(")")261                return262            for idx, field in enumerate(node.fields):263                if idx:264                    buf.append(", ")265                value = getattr(node, field)266                if isinstance(value, list):267                    buf.append("[")268                    for idx, item in enumerate(value):269                        if idx:270                            buf.append(", ")271                        _dump(item)272                    buf.append("]")273                else:274                    _dump(value)275            buf.append(")")276 277        buf: t.List[str] = []278        _dump(self)279        return "".join(buf)280 281 282class Stmt(Node):283    """Base node for all statements."""284 285    abstract = True286 287 288class Helper(Node):289    """Nodes that exist in a specific context only."""290 291    abstract = True292 293 294class Template(Node):295    """Node that represents a template.  This must be the outermost node that296    is passed to the compiler.297    """298 299    fields = ("body",)300    body: t.List[Node]301 302 303class Output(Stmt):304    """A node that holds multiple expressions which are then printed out.305    This is used both for the `print` statement and the regular template data.306    """307 308    fields = ("nodes",)309    nodes: t.List["Expr"]310 311 312class Extends(Stmt):313    """Represents an extends statement."""314 315    fields = ("template",)316    template: "Expr"317 318 319class For(Stmt):320    """The for loop.  `target` is the target for the iteration (usually a321    :class:`Name` or :class:`Tuple`), `iter` the iterable.  `body` is a list322    of nodes that are used as loop-body, and `else_` a list of nodes for the323    `else` block.  If no else node exists it has to be an empty list.324 325    For filtered nodes an expression can be stored as `test`, otherwise `None`.326    """327 328    fields = ("target", "iter", "body", "else_", "test", "recursive")329    target: Node330    iter: Node331    body: t.List[Node]332    else_: t.List[Node]333    test: t.Optional[Node]334    recursive: bool335 336 337class If(Stmt):338    """If `test` is true, `body` is rendered, else `else_`."""339 340    fields = ("test", "body", "elif_", "else_")341    test: Node342    body: t.List[Node]343    elif_: t.List["If"]344    else_: t.List[Node]345 346 347class Macro(Stmt):348    """A macro definition.  `name` is the name of the macro, `args` a list of349    arguments and `defaults` a list of defaults if there are any.  `body` is350    a list of nodes for the macro body.351    """352 353    fields = ("name", "args", "defaults", "body")354    name: str355    args: t.List["Name"]356    defaults: t.List["Expr"]357    body: t.List[Node]358 359 360class CallBlock(Stmt):361    """Like a macro without a name but a call instead.  `call` is called with362    the unnamed macro as `caller` argument this node holds.363    """364 365    fields = ("call", "args", "defaults", "body")366    call: "Call"367    args: t.List["Name"]368    defaults: t.List["Expr"]369    body: t.List[Node]370 371 372class FilterBlock(Stmt):373    """Node for filter sections."""374 375    fields = ("body", "filter")376    body: t.List[Node]377    filter: "Filter"378 379 380class With(Stmt):381    """Specific node for with statements.  In older versions of Jinja the382    with statement was implemented on the base of the `Scope` node instead.383 384    .. versionadded:: 2.9.3385    """386 387    fields = ("targets", "values", "body")388    targets: t.List["Expr"]389    values: t.List["Expr"]390    body: t.List[Node]391 392 393class Block(Stmt):394    """A node that represents a block.395 396    .. versionchanged:: 3.0.0397        the `required` field was added.398    """399 400    fields = ("name", "body", "scoped", "required")401    name: str402    body: t.List[Node]403    scoped: bool404    required: bool405 406 407class Include(Stmt):408    """A node that represents the include tag."""409 410    fields = ("template", "with_context", "ignore_missing")411    template: "Expr"412    with_context: bool413    ignore_missing: bool414 415 416class Import(Stmt):417    """A node that represents the import tag."""418 419    fields = ("template", "target", "with_context")420    template: "Expr"421    target: str422    with_context: bool423 424 425class FromImport(Stmt):426    """A node that represents the from import tag.  It's important to not427    pass unsafe names to the name attribute.  The compiler translates the428    attribute lookups directly into getattr calls and does *not* use the429    subscript callback of the interface.  As exported variables may not430    start with double underscores (which the parser asserts) this is not a431    problem for regular Jinja code, but if this node is used in an extension432    extra care must be taken.433 434    The list of names may contain tuples if aliases are wanted.435    """436 437    fields = ("template", "names", "with_context")438    template: "Expr"439    names: t.List[t.Union[str, t.Tuple[str, str]]]440    with_context: bool441 442 443class ExprStmt(Stmt):444    """A statement that evaluates an expression and discards the result."""445 446    fields = ("node",)447    node: Node448 449 450class Assign(Stmt):451    """Assigns an expression to a target."""452 453    fields = ("target", "node")454    target: "Expr"455    node: Node456 457 458class AssignBlock(Stmt):459    """Assigns a block to a target."""460 461    fields = ("target", "filter", "body")462    target: "Expr"463    filter: t.Optional["Filter"]464    body: t.List[Node]465 466 467class Expr(Node):468    """Baseclass for all expressions."""469 470    abstract = True471 472    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:473        """Return the value of the expression as constant or raise474        :exc:`Impossible` if this was not possible.475 476        An :class:`EvalContext` can be provided, if none is given477        a default context is created which requires the nodes to have478        an attached environment.479 480        .. versionchanged:: 2.4481           the `eval_ctx` parameter was added.482        """483        raise Impossible()484 485    def can_assign(self) -> bool:486        """Check if it's possible to assign something to this node."""487        return False488 489 490class BinExpr(Expr):491    """Baseclass for all binary expressions."""492 493    fields = ("left", "right")494    left: Expr495    right: Expr496    operator: str497    abstract = True498 499    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:500        eval_ctx = get_eval_context(self, eval_ctx)501 502        # intercepted operators cannot be folded at compile time503        if (504            eval_ctx.environment.sandboxed505            and self.operator in eval_ctx.environment.intercepted_binops  # type: ignore506        ):507            raise Impossible()508        f = _binop_to_func[self.operator]509        try:510            return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))511        except Exception as e:512            raise Impossible() from e513 514 515class UnaryExpr(Expr):516    """Baseclass for all unary expressions."""517 518    fields = ("node",)519    node: Expr520    operator: str521    abstract = True522 523    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:524        eval_ctx = get_eval_context(self, eval_ctx)525 526        # intercepted operators cannot be folded at compile time527        if (528            eval_ctx.environment.sandboxed529            and self.operator in eval_ctx.environment.intercepted_unops  # type: ignore530        ):531            raise Impossible()532        f = _uaop_to_func[self.operator]533        try:534            return f(self.node.as_const(eval_ctx))535        except Exception as e:536            raise Impossible() from e537 538 539class Name(Expr):540    """Looks up a name or stores a value in a name.541    The `ctx` of the node can be one of the following values:542 543    -   `store`: store a value in the name544    -   `load`: load that name545    -   `param`: like `store` but if the name was defined as function parameter.546    """547 548    fields = ("name", "ctx")549    name: str550    ctx: str551 552    def can_assign(self) -> bool:553        return self.name not in {"true", "false", "none", "True", "False", "None"}554 555 556class NSRef(Expr):557    """Reference to a namespace value assignment"""558 559    fields = ("name", "attr")560    name: str561    attr: str562 563    def can_assign(self) -> bool:564        # We don't need any special checks here; NSRef assignments have a565        # runtime check to ensure the target is a namespace object which will566        # have been checked already as it is created using a normal assignment567        # which goes through a `Name` node.568        return True569 570 571class Literal(Expr):572    """Baseclass for literals."""573 574    abstract = True575 576 577class Const(Literal):578    """All constant values.  The parser will return this node for simple579    constants such as ``42`` or ``"foo"`` but it can be used to store more580    complex values such as lists too.  Only constants with a safe581    representation (objects where ``eval(repr(x)) == x`` is true).582    """583 584    fields = ("value",)585    value: t.Any586 587    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:588        return self.value589 590    @classmethod591    def from_untrusted(592        cls,593        value: t.Any,594        lineno: t.Optional[int] = None,595        environment: "t.Optional[Environment]" = None,596    ) -> "Const":597        """Return a const object if the value is representable as598        constant value in the generated code, otherwise it will raise599        an `Impossible` exception.600        """601        from .compiler import has_safe_repr602 603        if not has_safe_repr(value):604            raise Impossible()605        return cls(value, lineno=lineno, environment=environment)606 607 608class TemplateData(Literal):609    """A constant template string."""610 611    fields = ("data",)612    data: str613 614    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:615        eval_ctx = get_eval_context(self, eval_ctx)616        if eval_ctx.volatile:617            raise Impossible()618        if eval_ctx.autoescape:619            return Markup(self.data)620        return self.data621 622 623class Tuple(Literal):624    """For loop unpacking and some other things like multiple arguments625    for subscripts.  Like for :class:`Name` `ctx` specifies if the tuple626    is used for loading the names or storing.627    """628 629    fields = ("items", "ctx")630    items: t.List[Expr]631    ctx: str632 633    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[t.Any, ...]:634        eval_ctx = get_eval_context(self, eval_ctx)635        return tuple(x.as_const(eval_ctx) for x in self.items)636 637    def can_assign(self) -> bool:638        for item in self.items:639            if not item.can_assign():640                return False641        return True642 643 644class List(Literal):645    """Any list literal such as ``[1, 2, 3]``"""646 647    fields = ("items",)648    items: t.List[Expr]649 650    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.List[t.Any]:651        eval_ctx = get_eval_context(self, eval_ctx)652        return [x.as_const(eval_ctx) for x in self.items]653 654 655class Dict(Literal):656    """Any dict literal such as ``{1: 2, 3: 4}``.  The items must be a list of657    :class:`Pair` nodes.658    """659 660    fields = ("items",)661    items: t.List["Pair"]662 663    def as_const(664        self, eval_ctx: t.Optional[EvalContext] = None665    ) -> t.Dict[t.Any, t.Any]:666        eval_ctx = get_eval_context(self, eval_ctx)667        return dict(x.as_const(eval_ctx) for x in self.items)668 669 670class Pair(Helper):671    """A key, value pair for dicts."""672 673    fields = ("key", "value")674    key: Expr675    value: Expr676 677    def as_const(678        self, eval_ctx: t.Optional[EvalContext] = None679    ) -> t.Tuple[t.Any, t.Any]:680        eval_ctx = get_eval_context(self, eval_ctx)681        return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)682 683 684class Keyword(Helper):685    """A key, value pair for keyword arguments where key is a string."""686 687    fields = ("key", "value")688    key: str689    value: Expr690 691    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[str, t.Any]:692        eval_ctx = get_eval_context(self, eval_ctx)693        return self.key, self.value.as_const(eval_ctx)694 695 696class CondExpr(Expr):697    """A conditional expression (inline if expression).  (``{{698    foo if bar else baz }}``)699    """700 701    fields = ("test", "expr1", "expr2")702    test: Expr703    expr1: Expr704    expr2: t.Optional[Expr]705 706    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:707        eval_ctx = get_eval_context(self, eval_ctx)708        if self.test.as_const(eval_ctx):709            return self.expr1.as_const(eval_ctx)710 711        # if we evaluate to an undefined object, we better do that at runtime712        if self.expr2 is None:713            raise Impossible()714 715        return self.expr2.as_const(eval_ctx)716 717 718def args_as_const(719    node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext]720) -> t.Tuple[t.List[t.Any], t.Dict[t.Any, t.Any]]:721    args = [x.as_const(eval_ctx) for x in node.args]722    kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)723 724    if node.dyn_args is not None:725        try:726            args.extend(node.dyn_args.as_const(eval_ctx))727        except Exception as e:728            raise Impossible() from e729 730    if node.dyn_kwargs is not None:731        try:732            kwargs.update(node.dyn_kwargs.as_const(eval_ctx))733        except Exception as e:734            raise Impossible() from e735 736    return args, kwargs737 738 739class _FilterTestCommon(Expr):740    fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")741    node: Expr742    name: str743    args: t.List[Expr]744    kwargs: t.List[Pair]745    dyn_args: t.Optional[Expr]746    dyn_kwargs: t.Optional[Expr]747    abstract = True748    _is_filter = True749 750    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:751        eval_ctx = get_eval_context(self, eval_ctx)752 753        if eval_ctx.volatile:754            raise Impossible()755 756        if self._is_filter:757            env_map = eval_ctx.environment.filters758        else:759            env_map = eval_ctx.environment.tests760 761        func = env_map.get(self.name)762        pass_arg = _PassArg.from_obj(func)  # type: ignore763 764        if func is None or pass_arg is _PassArg.context:765            raise Impossible()766 767        if eval_ctx.environment.is_async and (768            getattr(func, "jinja_async_variant", False) is True769            or inspect.iscoroutinefunction(func)770        ):771            raise Impossible()772 773        args, kwargs = args_as_const(self, eval_ctx)774        args.insert(0, self.node.as_const(eval_ctx))775 776        if pass_arg is _PassArg.eval_context:777            args.insert(0, eval_ctx)778        elif pass_arg is _PassArg.environment:779            args.insert(0, eval_ctx.environment)780 781        try:782            return func(*args, **kwargs)783        except Exception as e:784            raise Impossible() from e785 786 787class Filter(_FilterTestCommon):788    """Apply a filter to an expression. ``name`` is the name of the789    filter, the other fields are the same as :class:`Call`.790 791    If ``node`` is ``None``, the filter is being used in a filter block792    and is applied to the content of the block.793    """794 795    node: t.Optional[Expr]  # type: ignore796 797    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:798        if self.node is None:799            raise Impossible()800 801        return super().as_const(eval_ctx=eval_ctx)802 803 804class Test(_FilterTestCommon):805    """Apply a test to an expression. ``name`` is the name of the test,806    the other field are the same as :class:`Call`.807 808    .. versionchanged:: 3.0809        ``as_const`` shares the same logic for filters and tests. Tests810        check for volatile, async, and ``@pass_context`` etc.811        decorators.812    """813 814    _is_filter = False815 816 817class Call(Expr):818    """Calls an expression.  `args` is a list of arguments, `kwargs` a list819    of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`820    and `dyn_kwargs` has to be either `None` or a node that is used as821    node for dynamic positional (``*args``) or keyword (``**kwargs``)822    arguments.823    """824 825    fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs")826    node: Expr827    args: t.List[Expr]828    kwargs: t.List[Keyword]829    dyn_args: t.Optional[Expr]830    dyn_kwargs: t.Optional[Expr]831 832 833class Getitem(Expr):834    """Get an attribute or item from an expression and prefer the item."""835 836    fields = ("node", "arg", "ctx")837    node: Expr838    arg: Expr839    ctx: str840 841    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:842        if self.ctx != "load":843            raise Impossible()844 845        eval_ctx = get_eval_context(self, eval_ctx)846 847        try:848            return eval_ctx.environment.getitem(849                self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx)850            )851        except Exception as e:852            raise Impossible() from e853 854 855class Getattr(Expr):856    """Get an attribute or item from an expression that is a ascii-only857    bytestring and prefer the attribute.858    """859 860    fields = ("node", "attr", "ctx")861    node: Expr862    attr: str863    ctx: str864 865    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:866        if self.ctx != "load":867            raise Impossible()868 869        eval_ctx = get_eval_context(self, eval_ctx)870 871        try:872            return eval_ctx.environment.getattr(self.node.as_const(eval_ctx), self.attr)873        except Exception as e:874            raise Impossible() from e875 876 877class Slice(Expr):878    """Represents a slice object.  This must only be used as argument for879    :class:`Subscript`.880    """881 882    fields = ("start", "stop", "step")883    start: t.Optional[Expr]884    stop: t.Optional[Expr]885    step: t.Optional[Expr]886 887    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> slice:888        eval_ctx = get_eval_context(self, eval_ctx)889 890        def const(obj: t.Optional[Expr]) -> t.Optional[t.Any]:891            if obj is None:892                return None893            return obj.as_const(eval_ctx)894 895        return slice(const(self.start), const(self.stop), const(self.step))896 897 898class Concat(Expr):899    """Concatenates the list of expressions provided after converting900    them to strings.901    """902 903    fields = ("nodes",)904    nodes: t.List[Expr]905 906    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:907        eval_ctx = get_eval_context(self, eval_ctx)908        return "".join(str(x.as_const(eval_ctx)) for x in self.nodes)909 910 911class Compare(Expr):912    """Compares an expression with some other expressions.  `ops` must be a913    list of :class:`Operand`\\s.914    """915 916    fields = ("expr", "ops")917    expr: Expr918    ops: t.List["Operand"]919 920    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:921        eval_ctx = get_eval_context(self, eval_ctx)922        result = value = self.expr.as_const(eval_ctx)923 924        try:925            for op in self.ops:926                new_value = op.expr.as_const(eval_ctx)927                result = _cmpop_to_func[op.op](value, new_value)928 929                if not result:930                    return False931 932                value = new_value933        except Exception as e:934            raise Impossible() from e935 936        return result937 938 939class Operand(Helper):940    """Holds an operator and an expression."""941 942    fields = ("op", "expr")943    op: str944    expr: Expr945 946 947class Mul(BinExpr):948    """Multiplies the left with the right node."""949 950    operator = "*"951 952 953class Div(BinExpr):954    """Divides the left by the right node."""955 956    operator = "/"957 958 959class FloorDiv(BinExpr):960    """Divides the left by the right node and converts the961    result into an integer by truncating.962    """963 964    operator = "//"965 966 967class Add(BinExpr):968    """Add the left to the right node."""969 970    operator = "+"971 972 973class Sub(BinExpr):974    """Subtract the right from the left node."""975 976    operator = "-"977 978 979class Mod(BinExpr):980    """Left modulo right."""981 982    operator = "%"983 984 985class Pow(BinExpr):986    """Left to the power of right."""987 988    operator = "**"989 990 991class And(BinExpr):992    """Short circuited AND."""993 994    operator = "and"995 996    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:997        eval_ctx = get_eval_context(self, eval_ctx)998        return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)999 1000 1001class Or(BinExpr):1002    """Short circuited OR."""1003 1004    operator = "or"1005 1006    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:1007        eval_ctx = get_eval_context(self, eval_ctx)1008        return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)1009 1010 1011class Not(UnaryExpr):1012    """Negate the expression."""1013 1014    operator = "not"1015 1016 1017class Neg(UnaryExpr):1018    """Make the expression negative."""1019 1020    operator = "-"1021 1022 1023class Pos(UnaryExpr):1024    """Make the expression positive (noop for most expressions)"""1025 1026    operator = "+"1027 1028 1029# Helpers for extensions1030 1031 1032class EnvironmentAttribute(Expr):1033    """Loads an attribute from the environment object.  This is useful for1034    extensions that want to call a callback stored on the environment.1035    """1036 1037    fields = ("name",)1038    name: str1039 1040 1041class ExtensionAttribute(Expr):1042    """Returns the attribute of an extension bound to the environment.1043    The identifier is the identifier of the :class:`Extension`.1044 1045    This node is usually constructed by calling the1046    :meth:`~jinja2.ext.Extension.attr` method on an extension.1047    """1048 1049    fields = ("identifier", "name")1050    identifier: str1051    name: str1052 1053 1054class ImportedName(Expr):1055    """If created with an import name the import name is returned on node1056    access.  For example ``ImportedName('cgi.escape')`` returns the `escape`1057    function from the cgi module on evaluation.  Imports are optimized by the1058    compiler so there is no need to assign them to local variables.1059    """1060 1061    fields = ("importname",)1062    importname: str1063 1064 1065class InternalName(Expr):1066    """An internal name in the compiler.  You cannot create these nodes1067    yourself but the parser provides a1068    :meth:`~jinja2.parser.Parser.free_identifier` method that creates1069    a new identifier for you.  This identifier is not available from the1070    template and is not treated specially by the compiler.1071    """1072 1073    fields = ("name",)1074    name: str1075 1076    def __init__(self) -> None:1077        raise TypeError(1078            "Can't create internal names.  Use the "1079            "`free_identifier` method on a parser."1080        )1081 1082 1083class MarkSafe(Expr):1084    """Mark the wrapped expression as safe (wrap it as `Markup`)."""1085 1086    fields = ("expr",)1087    expr: Expr1088 1089    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> Markup:1090        eval_ctx = get_eval_context(self, eval_ctx)1091        return Markup(self.expr.as_const(eval_ctx))1092 1093 1094class MarkSafeIfAutoescape(Expr):1095    """Mark the wrapped expression as safe (wrap it as `Markup`) but1096    only if autoescaping is active.1097 1098    .. versionadded:: 2.51099    """1100 1101    fields = ("expr",)1102    expr: Expr1103 1104    def as_const(1105        self, eval_ctx: t.Optional[EvalContext] = None1106    ) -> t.Union[Markup, t.Any]:1107        eval_ctx = get_eval_context(self, eval_ctx)1108        if eval_ctx.volatile:1109            raise Impossible()1110        expr = self.expr.as_const(eval_ctx)1111        if eval_ctx.autoescape:1112            return Markup(expr)1113        return expr1114 1115 1116class ContextReference(Expr):1117    """Returns the current template context.  It can be used like a1118    :class:`Name` node, with a ``'load'`` ctx and will return the1119    current :class:`~jinja2.runtime.Context` object.1120 1121    Here an example that assigns the current template name to a1122    variable named `foo`::1123 1124        Assign(Name('foo', ctx='store'),1125               Getattr(ContextReference(), 'name'))1126 1127    This is basically equivalent to using the1128    :func:`~jinja2.pass_context` decorator when using the high-level1129    API, which causes a reference to the context to be passed as the1130    first argument to a function.1131    """1132 1133 1134class DerivedContextReference(Expr):1135    """Return the current template context including locals. Behaves1136    exactly like :class:`ContextReference`, but includes local1137    variables, such as from a ``for`` loop.1138 1139    .. versionadded:: 2.111140    """1141 1142 1143class Continue(Stmt):1144    """Continue a loop."""1145 1146 1147class Break(Stmt):1148    """Break a loop."""1149 1150 1151class Scope(Stmt):1152    """An artificial scope."""1153 1154    fields = ("body",)1155    body: t.List[Node]1156 1157 1158class OverlayScope(Stmt):1159    """An overlay scope for extensions.  This is a largely unoptimized scope1160    that however can be used to introduce completely arbitrary variables into1161    a sub scope from a dictionary or dictionary like object.  The `context`1162    field has to evaluate to a dictionary object.1163 1164    Example usage::1165 1166        OverlayScope(context=self.call_method('get_context'),1167                     body=[...])1168 1169    .. versionadded:: 2.101170    """1171 1172    fields = ("context", "body")1173    context: Expr1174    body: t.List[Node]1175 1176 1177class EvalContextModifier(Stmt):1178    """Modifies the eval context.  For each option that should be modified,1179    a :class:`Keyword` has to be added to the :attr:`options` list.1180 1181    Example to change the `autoescape` setting::1182 1183        EvalContextModifier(options=[Keyword('autoescape', Const(True))])1184    """1185 1186    fields = ("options",)1187    options: t.List[Keyword]1188 1189 1190class ScopedEvalContextModifier(EvalContextModifier):1191    """Modifies the eval context and reverts it later.  Works exactly like1192    :class:`EvalContextModifier` but will only modify the1193    :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.1194    """1195 1196    fields = ("body",)1197    body: t.List[Node]1198 1199 1200# make sure nobody creates custom nodes

Showing the first 1,200 of 1207 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai