Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
runtime.py1063 linesDownload Raw Back to jinja2
1"""The runtime functions and state used by compiled templates."""2 3import functools4import sys5import typing as t6from collections import abc7from itertools import chain8 9from markupsafe import escape  # noqa: F40110from markupsafe import Markup11from markupsafe import soft_str12 13from .async_utils import auto_aiter14from .async_utils import auto_await  # noqa: F40115from .exceptions import TemplateNotFound  # noqa: F40116from .exceptions import TemplateRuntimeError  # noqa: F40117from .exceptions import UndefinedError18from .nodes import EvalContext19from .utils import _PassArg20from .utils import concat21from .utils import internalcode22from .utils import missing23from .utils import Namespace  # noqa: F40124from .utils import object_type_repr25from .utils import pass_eval_context26 27V = t.TypeVar("V")28F = t.TypeVar("F", bound=t.Callable[..., t.Any])29 30if t.TYPE_CHECKING:31    import logging32 33    import typing_extensions as te34 35    from .environment import Environment36 37    class LoopRenderFunc(te.Protocol):38        def __call__(39            self,40            reciter: t.Iterable[V],41            loop_render_func: "LoopRenderFunc",42            depth: int = 0,43        ) -> str: ...44 45 46# these variables are exported to the template runtime47exported = [48    "LoopContext",49    "TemplateReference",50    "Macro",51    "Markup",52    "TemplateRuntimeError",53    "missing",54    "escape",55    "markup_join",56    "str_join",57    "identity",58    "TemplateNotFound",59    "Namespace",60    "Undefined",61    "internalcode",62]63async_exported = [64    "AsyncLoopContext",65    "auto_aiter",66    "auto_await",67]68 69 70def identity(x: V) -> V:71    """Returns its argument. Useful for certain things in the72    environment.73    """74    return x75 76 77def markup_join(seq: t.Iterable[t.Any]) -> str:78    """Concatenation that escapes if necessary and converts to string."""79    buf = []80    iterator = map(soft_str, seq)81    for arg in iterator:82        buf.append(arg)83        if hasattr(arg, "__html__"):84            return Markup("").join(chain(buf, iterator))85    return concat(buf)86 87 88def str_join(seq: t.Iterable[t.Any]) -> str:89    """Simple args to string conversion and concatenation."""90    return concat(map(str, seq))91 92 93def new_context(94    environment: "Environment",95    template_name: t.Optional[str],96    blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],97    vars: t.Optional[t.Dict[str, t.Any]] = None,98    shared: bool = False,99    globals: t.Optional[t.MutableMapping[str, t.Any]] = None,100    locals: t.Optional[t.Mapping[str, t.Any]] = None,101) -> "Context":102    """Internal helper for context creation."""103    if vars is None:104        vars = {}105    if shared:106        parent = vars107    else:108        parent = dict(globals or (), **vars)109    if locals:110        # if the parent is shared a copy should be created because111        # we don't want to modify the dict passed112        if shared:113            parent = dict(parent)114        for key, value in locals.items():115            if value is not missing:116                parent[key] = value117    return environment.context_class(118        environment, parent, template_name, blocks, globals=globals119    )120 121 122class TemplateReference:123    """The `self` in templates."""124 125    def __init__(self, context: "Context") -> None:126        self.__context = context127 128    def __getitem__(self, name: str) -> t.Any:129        blocks = self.__context.blocks[name]130        return BlockReference(name, self.__context, blocks, 0)131 132    def __repr__(self) -> str:133        return f"<{type(self).__name__} {self.__context.name!r}>"134 135 136def _dict_method_all(dict_method: F) -> F:137    @functools.wraps(dict_method)138    def f_all(self: "Context") -> t.Any:139        return dict_method(self.get_all())140 141    return t.cast(F, f_all)142 143 144@abc.Mapping.register145class Context:146    """The template context holds the variables of a template.  It stores the147    values passed to the template and also the names the template exports.148    Creating instances is neither supported nor useful as it's created149    automatically at various stages of the template evaluation and should not150    be created by hand.151 152    The context is immutable.  Modifications on :attr:`parent` **must not**153    happen and modifications on :attr:`vars` are allowed from generated154    template code only.  Template filters and global functions marked as155    :func:`pass_context` get the active context passed as first argument156    and are allowed to access the context read-only.157 158    The template context supports read only dict operations (`get`,159    `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,160    `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`161    method that doesn't fail with a `KeyError` but returns an162    :class:`Undefined` object for missing variables.163    """164 165    def __init__(166        self,167        environment: "Environment",168        parent: t.Dict[str, t.Any],169        name: t.Optional[str],170        blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],171        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,172    ):173        self.parent = parent174        self.vars: t.Dict[str, t.Any] = {}175        self.environment: Environment = environment176        self.eval_ctx = EvalContext(self.environment, name)177        self.exported_vars: t.Set[str] = set()178        self.name = name179        self.globals_keys = set() if globals is None else set(globals)180 181        # create the initial mapping of blocks.  Whenever template inheritance182        # takes place the runtime will update this mapping with the new blocks183        # from the template.184        self.blocks = {k: [v] for k, v in blocks.items()}185 186    def super(187        self, name: str, current: t.Callable[["Context"], t.Iterator[str]]188    ) -> t.Union["BlockReference", "Undefined"]:189        """Render a parent block."""190        try:191            blocks = self.blocks[name]192            index = blocks.index(current) + 1193            blocks[index]194        except LookupError:195            return self.environment.undefined(196                f"there is no parent block called {name!r}.", name="super"197            )198        return BlockReference(name, self, blocks, index)199 200    def get(self, key: str, default: t.Any = None) -> t.Any:201        """Look up a variable by name, or return a default if the key is202        not found.203 204        :param key: The variable name to look up.205        :param default: The value to return if the key is not found.206        """207        try:208            return self[key]209        except KeyError:210            return default211 212    def resolve(self, key: str) -> t.Union[t.Any, "Undefined"]:213        """Look up a variable by name, or return an :class:`Undefined`214        object if the key is not found.215 216        If you need to add custom behavior, override217        :meth:`resolve_or_missing`, not this method. The various lookup218        functions use that method, not this one.219 220        :param key: The variable name to look up.221        """222        rv = self.resolve_or_missing(key)223 224        if rv is missing:225            return self.environment.undefined(name=key)226 227        return rv228 229    def resolve_or_missing(self, key: str) -> t.Any:230        """Look up a variable by name, or return a ``missing`` sentinel231        if the key is not found.232 233        Override this method to add custom lookup behavior.234        :meth:`resolve`, :meth:`get`, and :meth:`__getitem__` use this235        method. Don't call this method directly.236 237        :param key: The variable name to look up.238        """239        if key in self.vars:240            return self.vars[key]241 242        if key in self.parent:243            return self.parent[key]244 245        return missing246 247    def get_exported(self) -> t.Dict[str, t.Any]:248        """Get a new dict with the exported variables."""249        return {k: self.vars[k] for k in self.exported_vars}250 251    def get_all(self) -> t.Dict[str, t.Any]:252        """Return the complete context as dict including the exported253        variables.  For optimizations reasons this might not return an254        actual copy so be careful with using it.255        """256        if not self.vars:257            return self.parent258        if not self.parent:259            return self.vars260        return dict(self.parent, **self.vars)261 262    @internalcode263    def call(264        __self,265        __obj: t.Callable[..., t.Any],266        *args: t.Any,267        **kwargs: t.Any,  # noqa: B902268    ) -> t.Union[t.Any, "Undefined"]:269        """Call the callable with the arguments and keyword arguments270        provided but inject the active context or environment as first271        argument if the callable has :func:`pass_context` or272        :func:`pass_environment`.273        """274        if __debug__:275            __traceback_hide__ = True  # noqa276 277        # Allow callable classes to take a context278        if (279            hasattr(__obj, "__call__")  # noqa: B004280            and _PassArg.from_obj(__obj.__call__) is not None281        ):282            __obj = __obj.__call__283 284        pass_arg = _PassArg.from_obj(__obj)285 286        if pass_arg is _PassArg.context:287            # the active context should have access to variables set in288            # loops and blocks without mutating the context itself289            if kwargs.get("_loop_vars"):290                __self = __self.derived(kwargs["_loop_vars"])291            if kwargs.get("_block_vars"):292                __self = __self.derived(kwargs["_block_vars"])293            args = (__self,) + args294        elif pass_arg is _PassArg.eval_context:295            args = (__self.eval_ctx,) + args296        elif pass_arg is _PassArg.environment:297            args = (__self.environment,) + args298 299        kwargs.pop("_block_vars", None)300        kwargs.pop("_loop_vars", None)301 302        try:303            return __obj(*args, **kwargs)304        except StopIteration:305            return __self.environment.undefined(306                "value was undefined because a callable raised a"307                " StopIteration exception"308            )309 310    def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context":311        """Internal helper function to create a derived context.  This is312        used in situations where the system needs a new context in the same313        template that is independent.314        """315        context = new_context(316            self.environment, self.name, {}, self.get_all(), True, None, locals317        )318        context.eval_ctx = self.eval_ctx319        context.blocks.update((k, list(v)) for k, v in self.blocks.items())320        return context321 322    keys = _dict_method_all(dict.keys)323    values = _dict_method_all(dict.values)324    items = _dict_method_all(dict.items)325 326    def __contains__(self, name: str) -> bool:327        return name in self.vars or name in self.parent328 329    def __getitem__(self, key: str) -> t.Any:330        """Look up a variable by name with ``[]`` syntax, or raise a331        ``KeyError`` if the key is not found.332        """333        item = self.resolve_or_missing(key)334 335        if item is missing:336            raise KeyError(key)337 338        return item339 340    def __repr__(self) -> str:341        return f"<{type(self).__name__} {self.get_all()!r} of {self.name!r}>"342 343 344class BlockReference:345    """One block on a template reference."""346 347    def __init__(348        self,349        name: str,350        context: "Context",351        stack: t.List[t.Callable[["Context"], t.Iterator[str]]],352        depth: int,353    ) -> None:354        self.name = name355        self._context = context356        self._stack = stack357        self._depth = depth358 359    @property360    def super(self) -> t.Union["BlockReference", "Undefined"]:361        """Super the block."""362        if self._depth + 1 >= len(self._stack):363            return self._context.environment.undefined(364                f"there is no parent block called {self.name!r}.", name="super"365            )366        return BlockReference(self.name, self._context, self._stack, self._depth + 1)367 368    @internalcode369    async def _async_call(self) -> str:370        rv = self._context.environment.concat(  # type: ignore371            [x async for x in self._stack[self._depth](self._context)]  # type: ignore372        )373 374        if self._context.eval_ctx.autoescape:375            return Markup(rv)376 377        return rv378 379    @internalcode380    def __call__(self) -> str:381        if self._context.environment.is_async:382            return self._async_call()  # type: ignore383 384        rv = self._context.environment.concat(  # type: ignore385            self._stack[self._depth](self._context)386        )387 388        if self._context.eval_ctx.autoescape:389            return Markup(rv)390 391        return rv392 393 394class LoopContext:395    """A wrapper iterable for dynamic ``for`` loops, with information396    about the loop and iteration.397    """398 399    #: Current iteration of the loop, starting at 0.400    index0 = -1401 402    _length: t.Optional[int] = None403    _after: t.Any = missing404    _current: t.Any = missing405    _before: t.Any = missing406    _last_changed_value: t.Any = missing407 408    def __init__(409        self,410        iterable: t.Iterable[V],411        undefined: t.Type["Undefined"],412        recurse: t.Optional["LoopRenderFunc"] = None,413        depth0: int = 0,414    ) -> None:415        """416        :param iterable: Iterable to wrap.417        :param undefined: :class:`Undefined` class to use for next and418            previous items.419        :param recurse: The function to render the loop body when the420            loop is marked recursive.421        :param depth0: Incremented when looping recursively.422        """423        self._iterable = iterable424        self._iterator = self._to_iterator(iterable)425        self._undefined = undefined426        self._recurse = recurse427        #: How many levels deep a recursive loop currently is, starting at 0.428        self.depth0 = depth0429 430    @staticmethod431    def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]:432        return iter(iterable)433 434    @property435    def length(self) -> int:436        """Length of the iterable.437 438        If the iterable is a generator or otherwise does not have a439        size, it is eagerly evaluated to get a size.440        """441        if self._length is not None:442            return self._length443 444        try:445            self._length = len(self._iterable)  # type: ignore446        except TypeError:447            iterable = list(self._iterator)448            self._iterator = self._to_iterator(iterable)449            self._length = len(iterable) + self.index + (self._after is not missing)450 451        return self._length452 453    def __len__(self) -> int:454        return self.length455 456    @property457    def depth(self) -> int:458        """How many levels deep a recursive loop currently is, starting at 1."""459        return self.depth0 + 1460 461    @property462    def index(self) -> int:463        """Current iteration of the loop, starting at 1."""464        return self.index0 + 1465 466    @property467    def revindex0(self) -> int:468        """Number of iterations from the end of the loop, ending at 0.469 470        Requires calculating :attr:`length`.471        """472        return self.length - self.index473 474    @property475    def revindex(self) -> int:476        """Number of iterations from the end of the loop, ending at 1.477 478        Requires calculating :attr:`length`.479        """480        return self.length - self.index0481 482    @property483    def first(self) -> bool:484        """Whether this is the first iteration of the loop."""485        return self.index0 == 0486 487    def _peek_next(self) -> t.Any:488        """Return the next element in the iterable, or :data:`missing`489        if the iterable is exhausted. Only peeks one item ahead, caching490        the result in :attr:`_last` for use in subsequent checks. The491        cache is reset when :meth:`__next__` is called.492        """493        if self._after is not missing:494            return self._after495 496        self._after = next(self._iterator, missing)497        return self._after498 499    @property500    def last(self) -> bool:501        """Whether this is the last iteration of the loop.502 503        Causes the iterable to advance early. See504        :func:`itertools.groupby` for issues this can cause.505        The :func:`groupby` filter avoids that issue.506        """507        return self._peek_next() is missing508 509    @property510    def previtem(self) -> t.Union[t.Any, "Undefined"]:511        """The item in the previous iteration. Undefined during the512        first iteration.513        """514        if self.first:515            return self._undefined("there is no previous item")516 517        return self._before518 519    @property520    def nextitem(self) -> t.Union[t.Any, "Undefined"]:521        """The item in the next iteration. Undefined during the last522        iteration.523 524        Causes the iterable to advance early. See525        :func:`itertools.groupby` for issues this can cause.526        The :func:`jinja-filters.groupby` filter avoids that issue.527        """528        rv = self._peek_next()529 530        if rv is missing:531            return self._undefined("there is no next item")532 533        return rv534 535    def cycle(self, *args: V) -> V:536        """Return a value from the given args, cycling through based on537        the current :attr:`index0`.538 539        :param args: One or more values to cycle through.540        """541        if not args:542            raise TypeError("no items for cycling given")543 544        return args[self.index0 % len(args)]545 546    def changed(self, *value: t.Any) -> bool:547        """Return ``True`` if previously called with a different value548        (including when called for the first time).549 550        :param value: One or more values to compare to the last call.551        """552        if self._last_changed_value != value:553            self._last_changed_value = value554            return True555 556        return False557 558    def __iter__(self) -> "LoopContext":559        return self560 561    def __next__(self) -> t.Tuple[t.Any, "LoopContext"]:562        if self._after is not missing:563            rv = self._after564            self._after = missing565        else:566            rv = next(self._iterator)567 568        self.index0 += 1569        self._before = self._current570        self._current = rv571        return rv, self572 573    @internalcode574    def __call__(self, iterable: t.Iterable[V]) -> str:575        """When iterating over nested data, render the body of the loop576        recursively with the given inner iterable data.577 578        The loop must have the ``recursive`` marker for this to work.579        """580        if self._recurse is None:581            raise TypeError(582                "The loop must have the 'recursive' marker to be called recursively."583            )584 585        return self._recurse(iterable, self._recurse, depth=self.depth)586 587    def __repr__(self) -> str:588        return f"<{type(self).__name__} {self.index}/{self.length}>"589 590 591class AsyncLoopContext(LoopContext):592    _iterator: t.AsyncIterator[t.Any]  # type: ignore593 594    @staticmethod595    def _to_iterator(  # type: ignore596        iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]],597    ) -> t.AsyncIterator[V]:598        return auto_aiter(iterable)599 600    @property601    async def length(self) -> int:  # type: ignore602        if self._length is not None:603            return self._length604 605        try:606            self._length = len(self._iterable)  # type: ignore607        except TypeError:608            iterable = [x async for x in self._iterator]609            self._iterator = self._to_iterator(iterable)610            self._length = len(iterable) + self.index + (self._after is not missing)611 612        return self._length613 614    @property615    async def revindex0(self) -> int:  # type: ignore616        return await self.length - self.index617 618    @property619    async def revindex(self) -> int:  # type: ignore620        return await self.length - self.index0621 622    async def _peek_next(self) -> t.Any:623        if self._after is not missing:624            return self._after625 626        try:627            self._after = await self._iterator.__anext__()628        except StopAsyncIteration:629            self._after = missing630 631        return self._after632 633    @property634    async def last(self) -> bool:  # type: ignore635        return await self._peek_next() is missing636 637    @property638    async def nextitem(self) -> t.Union[t.Any, "Undefined"]:639        rv = await self._peek_next()640 641        if rv is missing:642            return self._undefined("there is no next item")643 644        return rv645 646    def __aiter__(self) -> "AsyncLoopContext":647        return self648 649    async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]:650        if self._after is not missing:651            rv = self._after652            self._after = missing653        else:654            rv = await self._iterator.__anext__()655 656        self.index0 += 1657        self._before = self._current658        self._current = rv659        return rv, self660 661 662class Macro:663    """Wraps a macro function."""664 665    def __init__(666        self,667        environment: "Environment",668        func: t.Callable[..., str],669        name: str,670        arguments: t.List[str],671        catch_kwargs: bool,672        catch_varargs: bool,673        caller: bool,674        default_autoescape: t.Optional[bool] = None,675    ):676        self._environment = environment677        self._func = func678        self._argument_count = len(arguments)679        self.name = name680        self.arguments = arguments681        self.catch_kwargs = catch_kwargs682        self.catch_varargs = catch_varargs683        self.caller = caller684        self.explicit_caller = "caller" in arguments685 686        if default_autoescape is None:687            if callable(environment.autoescape):688                default_autoescape = environment.autoescape(None)689            else:690                default_autoescape = environment.autoescape691 692        self._default_autoescape = default_autoescape693 694    @internalcode695    @pass_eval_context696    def __call__(self, *args: t.Any, **kwargs: t.Any) -> str:697        # This requires a bit of explanation,  In the past we used to698        # decide largely based on compile-time information if a macro is699        # safe or unsafe.  While there was a volatile mode it was largely700        # unused for deciding on escaping.  This turns out to be701        # problematic for macros because whether a macro is safe depends not702        # on the escape mode when it was defined, but rather when it was used.703        #704        # Because however we export macros from the module system and705        # there are historic callers that do not pass an eval context (and706        # will continue to not pass one), we need to perform an instance707        # check here.708        #709        # This is considered safe because an eval context is not a valid710        # argument to callables otherwise anyway.  Worst case here is711        # that if no eval context is passed we fall back to the compile712        # time autoescape flag.713        if args and isinstance(args[0], EvalContext):714            autoescape = args[0].autoescape715            args = args[1:]716        else:717            autoescape = self._default_autoescape718 719        # try to consume the positional arguments720        arguments = list(args[: self._argument_count])721        off = len(arguments)722 723        # For information why this is necessary refer to the handling724        # of caller in the `macro_body` handler in the compiler.725        found_caller = False726 727        # if the number of arguments consumed is not the number of728        # arguments expected we start filling in keyword arguments729        # and defaults.730        if off != self._argument_count:731            for name in self.arguments[len(arguments) :]:732                try:733                    value = kwargs.pop(name)734                except KeyError:735                    value = missing736                if name == "caller":737                    found_caller = True738                arguments.append(value)739        else:740            found_caller = self.explicit_caller741 742        # it's important that the order of these arguments does not change743        # if not also changed in the compiler's `function_scoping` method.744        # the order is caller, keyword arguments, positional arguments!745        if self.caller and not found_caller:746            caller = kwargs.pop("caller", None)747            if caller is None:748                caller = self._environment.undefined("No caller defined", name="caller")749            arguments.append(caller)750 751        if self.catch_kwargs:752            arguments.append(kwargs)753        elif kwargs:754            if "caller" in kwargs:755                raise TypeError(756                    f"macro {self.name!r} was invoked with two values for the special"757                    " caller argument. This is most likely a bug."758                )759            raise TypeError(760                f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}"761            )762        if self.catch_varargs:763            arguments.append(args[self._argument_count :])764        elif len(args) > self._argument_count:765            raise TypeError(766                f"macro {self.name!r} takes not more than"767                f" {len(self.arguments)} argument(s)"768            )769 770        return self._invoke(arguments, autoescape)771 772    async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:773        rv = await self._func(*arguments)  # type: ignore774 775        if autoescape:776            return Markup(rv)777 778        return rv  # type: ignore779 780    def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:781        if self._environment.is_async:782            return self._async_invoke(arguments, autoescape)  # type: ignore783 784        rv = self._func(*arguments)785 786        if autoescape:787            rv = Markup(rv)788 789        return rv790 791    def __repr__(self) -> str:792        name = "anonymous" if self.name is None else repr(self.name)793        return f"<{type(self).__name__} {name}>"794 795 796class Undefined:797    """The default undefined type. This can be printed, iterated, and treated as798    a boolean. Any other operation will raise an :exc:`UndefinedError`.799 800    >>> foo = Undefined(name='foo')801    >>> str(foo)802    ''803    >>> not foo804    True805    >>> foo + 42806    Traceback (most recent call last):807      ...808    jinja2.exceptions.UndefinedError: 'foo' is undefined809    """810 811    __slots__ = (812        "_undefined_hint",813        "_undefined_obj",814        "_undefined_name",815        "_undefined_exception",816    )817 818    def __init__(819        self,820        hint: t.Optional[str] = None,821        obj: t.Any = missing,822        name: t.Optional[str] = None,823        exc: t.Type[TemplateRuntimeError] = UndefinedError,824    ) -> None:825        self._undefined_hint = hint826        self._undefined_obj = obj827        self._undefined_name = name828        self._undefined_exception = exc829 830    @property831    def _undefined_message(self) -> str:832        """Build a message about the undefined value based on how it was833        accessed.834        """835        if self._undefined_hint:836            return self._undefined_hint837 838        if self._undefined_obj is missing:839            return f"{self._undefined_name!r} is undefined"840 841        if not isinstance(self._undefined_name, str):842            return (843                f"{object_type_repr(self._undefined_obj)} has no"844                f" element {self._undefined_name!r}"845            )846 847        return (848            f"{object_type_repr(self._undefined_obj)!r} has no"849            f" attribute {self._undefined_name!r}"850        )851 852    @internalcode853    def _fail_with_undefined_error(854        self, *args: t.Any, **kwargs: t.Any855    ) -> "te.NoReturn":856        """Raise an :exc:`UndefinedError` when operations are performed857        on the undefined value.858        """859        raise self._undefined_exception(self._undefined_message)860 861    @internalcode862    def __getattr__(self, name: str) -> t.Any:863        # Raise AttributeError on requests for names that appear to be unimplemented864        # dunder methods to keep Python's internal protocol probing behaviors working865        # properly in cases where another exception type could cause unexpected or866        # difficult-to-diagnose failures.867        if name[:2] == "__" and name[-2:] == "__":868            raise AttributeError(name)869 870        return self._fail_with_undefined_error()871 872    __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error873    __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error874    __truediv__ = __rtruediv__ = _fail_with_undefined_error875    __floordiv__ = __rfloordiv__ = _fail_with_undefined_error876    __mod__ = __rmod__ = _fail_with_undefined_error877    __pos__ = __neg__ = _fail_with_undefined_error878    __call__ = __getitem__ = _fail_with_undefined_error879    __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error880    __int__ = __float__ = __complex__ = _fail_with_undefined_error881    __pow__ = __rpow__ = _fail_with_undefined_error882 883    def __eq__(self, other: t.Any) -> bool:884        return type(self) is type(other)885 886    def __ne__(self, other: t.Any) -> bool:887        return not self.__eq__(other)888 889    def __hash__(self) -> int:890        return id(type(self))891 892    def __str__(self) -> str:893        return ""894 895    def __len__(self) -> int:896        return 0897 898    def __iter__(self) -> t.Iterator[t.Any]:899        yield from ()900 901    async def __aiter__(self) -> t.AsyncIterator[t.Any]:902        for _ in ():903            yield904 905    def __bool__(self) -> bool:906        return False907 908    def __repr__(self) -> str:909        return "Undefined"910 911 912def make_logging_undefined(913    logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined914) -> t.Type[Undefined]:915    """Given a logger object this returns a new undefined class that will916    log certain failures.  It will log iterations and printing.  If no917    logger is given a default logger is created.918 919    Example::920 921        logger = logging.getLogger(__name__)922        LoggingUndefined = make_logging_undefined(923            logger=logger,924            base=Undefined925        )926 927    .. versionadded:: 2.8928 929    :param logger: the logger to use.  If not provided, a default logger930                   is created.931    :param base: the base class to add logging functionality to.  This932                 defaults to :class:`Undefined`.933    """934    if logger is None:935        import logging936 937        logger = logging.getLogger(__name__)938        logger.addHandler(logging.StreamHandler(sys.stderr))939 940    def _log_message(undef: Undefined) -> None:941        logger.warning("Template variable warning: %s", undef._undefined_message)942 943    class LoggingUndefined(base):  # type: ignore944        __slots__ = ()945 946        def _fail_with_undefined_error(  # type: ignore947            self, *args: t.Any, **kwargs: t.Any948        ) -> "te.NoReturn":949            try:950                super()._fail_with_undefined_error(*args, **kwargs)951            except self._undefined_exception as e:952                logger.error("Template variable error: %s", e)  # type: ignore953                raise e954 955        def __str__(self) -> str:956            _log_message(self)957            return super().__str__()  # type: ignore958 959        def __iter__(self) -> t.Iterator[t.Any]:960            _log_message(self)961            return super().__iter__()  # type: ignore962 963        def __bool__(self) -> bool:964            _log_message(self)965            return super().__bool__()  # type: ignore966 967    return LoggingUndefined968 969 970class ChainableUndefined(Undefined):971    """An undefined that is chainable, where both ``__getattr__`` and972    ``__getitem__`` return itself rather than raising an973    :exc:`UndefinedError`.974 975    >>> foo = ChainableUndefined(name='foo')976    >>> str(foo.bar['baz'])977    ''978    >>> foo.bar['baz'] + 42979    Traceback (most recent call last):980      ...981    jinja2.exceptions.UndefinedError: 'foo' is undefined982 983    .. versionadded:: 2.11.0984    """985 986    __slots__ = ()987 988    def __html__(self) -> str:989        return str(self)990 991    def __getattr__(self, name: str) -> "ChainableUndefined":992        # Raise AttributeError on requests for names that appear to be unimplemented993        # dunder methods to avoid confusing Python with truthy non-method objects that994        # do not implement the protocol being probed for. e.g., copy.copy(Undefined())995        # fails spectacularly if getattr(Undefined(), '__setstate__') returns an996        # Undefined object instead of raising AttributeError to signal that it does not997        # support that style of object initialization.998        if name[:2] == "__" and name[-2:] == "__":999            raise AttributeError(name)1000 1001        return self1002 1003    def __getitem__(self, _name: str) -> "ChainableUndefined":  # type: ignore[override]1004        return self1005 1006 1007class DebugUndefined(Undefined):1008    """An undefined that returns the debug info when printed.1009 1010    >>> foo = DebugUndefined(name='foo')1011    >>> str(foo)1012    '{{ foo }}'1013    >>> not foo1014    True1015    >>> foo + 421016    Traceback (most recent call last):1017      ...1018    jinja2.exceptions.UndefinedError: 'foo' is undefined1019    """1020 1021    __slots__ = ()1022 1023    def __str__(self) -> str:1024        if self._undefined_hint:1025            message = f"undefined value printed: {self._undefined_hint}"1026 1027        elif self._undefined_obj is missing:1028            message = self._undefined_name  # type: ignore1029 1030        else:1031            message = (1032                f"no such element: {object_type_repr(self._undefined_obj)}"1033                f"[{self._undefined_name!r}]"1034            )1035 1036        return f"{{{{ {message} }}}}"1037 1038 1039class StrictUndefined(Undefined):1040    """An undefined that barks on print and iteration as well as boolean1041    tests and all kinds of comparisons.  In other words: you can do nothing1042    with it except checking if it's defined using the `defined` test.1043 1044    >>> foo = StrictUndefined(name='foo')1045    >>> str(foo)1046    Traceback (most recent call last):1047      ...1048    jinja2.exceptions.UndefinedError: 'foo' is undefined1049    >>> not foo1050    Traceback (most recent call last):1051      ...1052    jinja2.exceptions.UndefinedError: 'foo' is undefined1053    >>> foo + 421054    Traceback (most recent call last):1055      ...1056    jinja2.exceptions.UndefinedError: 'foo' is undefined1057    """1058 1059    __slots__ = ()1060    __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error1061    __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error1062    __contains__ = Undefined._fail_with_undefined_error1063 
codekingpro/portable-devtools · Team Ai