Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
runtime.py1057 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 = concat(371            [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 = concat(self._stack[self._depth](self._context))385 386        if self._context.eval_ctx.autoescape:387            return Markup(rv)388 389        return rv390 391 392class LoopContext:393    """A wrapper iterable for dynamic ``for`` loops, with information394    about the loop and iteration.395    """396 397    #: Current iteration of the loop, starting at 0.398    index0 = -1399 400    _length: t.Optional[int] = None401    _after: t.Any = missing402    _current: t.Any = missing403    _before: t.Any = missing404    _last_changed_value: t.Any = missing405 406    def __init__(407        self,408        iterable: t.Iterable[V],409        undefined: t.Type["Undefined"],410        recurse: t.Optional["LoopRenderFunc"] = None,411        depth0: int = 0,412    ) -> None:413        """414        :param iterable: Iterable to wrap.415        :param undefined: :class:`Undefined` class to use for next and416            previous items.417        :param recurse: The function to render the loop body when the418            loop is marked recursive.419        :param depth0: Incremented when looping recursively.420        """421        self._iterable = iterable422        self._iterator = self._to_iterator(iterable)423        self._undefined = undefined424        self._recurse = recurse425        #: How many levels deep a recursive loop currently is, starting at 0.426        self.depth0 = depth0427 428    @staticmethod429    def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]:430        return iter(iterable)431 432    @property433    def length(self) -> int:434        """Length of the iterable.435 436        If the iterable is a generator or otherwise does not have a437        size, it is eagerly evaluated to get a size.438        """439        if self._length is not None:440            return self._length441 442        try:443            self._length = len(self._iterable)  # type: ignore444        except TypeError:445            iterable = list(self._iterator)446            self._iterator = self._to_iterator(iterable)447            self._length = len(iterable) + self.index + (self._after is not missing)448 449        return self._length450 451    def __len__(self) -> int:452        return self.length453 454    @property455    def depth(self) -> int:456        """How many levels deep a recursive loop currently is, starting at 1."""457        return self.depth0 + 1458 459    @property460    def index(self) -> int:461        """Current iteration of the loop, starting at 1."""462        return self.index0 + 1463 464    @property465    def revindex0(self) -> int:466        """Number of iterations from the end of the loop, ending at 0.467 468        Requires calculating :attr:`length`.469        """470        return self.length - self.index471 472    @property473    def revindex(self) -> int:474        """Number of iterations from the end of the loop, ending at 1.475 476        Requires calculating :attr:`length`.477        """478        return self.length - self.index0479 480    @property481    def first(self) -> bool:482        """Whether this is the first iteration of the loop."""483        return self.index0 == 0484 485    def _peek_next(self) -> t.Any:486        """Return the next element in the iterable, or :data:`missing`487        if the iterable is exhausted. Only peeks one item ahead, caching488        the result in :attr:`_last` for use in subsequent checks. The489        cache is reset when :meth:`__next__` is called.490        """491        if self._after is not missing:492            return self._after493 494        self._after = next(self._iterator, missing)495        return self._after496 497    @property498    def last(self) -> bool:499        """Whether this is the last iteration of the loop.500 501        Causes the iterable to advance early. See502        :func:`itertools.groupby` for issues this can cause.503        The :func:`groupby` filter avoids that issue.504        """505        return self._peek_next() is missing506 507    @property508    def previtem(self) -> t.Union[t.Any, "Undefined"]:509        """The item in the previous iteration. Undefined during the510        first iteration.511        """512        if self.first:513            return self._undefined("there is no previous item")514 515        return self._before516 517    @property518    def nextitem(self) -> t.Union[t.Any, "Undefined"]:519        """The item in the next iteration. Undefined during the last520        iteration.521 522        Causes the iterable to advance early. See523        :func:`itertools.groupby` for issues this can cause.524        The :func:`jinja-filters.groupby` filter avoids that issue.525        """526        rv = self._peek_next()527 528        if rv is missing:529            return self._undefined("there is no next item")530 531        return rv532 533    def cycle(self, *args: V) -> V:534        """Return a value from the given args, cycling through based on535        the current :attr:`index0`.536 537        :param args: One or more values to cycle through.538        """539        if not args:540            raise TypeError("no items for cycling given")541 542        return args[self.index0 % len(args)]543 544    def changed(self, *value: t.Any) -> bool:545        """Return ``True`` if previously called with a different value546        (including when called for the first time).547 548        :param value: One or more values to compare to the last call.549        """550        if self._last_changed_value != value:551            self._last_changed_value = value552            return True553 554        return False555 556    def __iter__(self) -> "LoopContext":557        return self558 559    def __next__(self) -> t.Tuple[t.Any, "LoopContext"]:560        if self._after is not missing:561            rv = self._after562            self._after = missing563        else:564            rv = next(self._iterator)565 566        self.index0 += 1567        self._before = self._current568        self._current = rv569        return rv, self570 571    @internalcode572    def __call__(self, iterable: t.Iterable[V]) -> str:573        """When iterating over nested data, render the body of the loop574        recursively with the given inner iterable data.575 576        The loop must have the ``recursive`` marker for this to work.577        """578        if self._recurse is None:579            raise TypeError(580                "The loop must have the 'recursive' marker to be called recursively."581            )582 583        return self._recurse(iterable, self._recurse, depth=self.depth)584 585    def __repr__(self) -> str:586        return f"<{type(self).__name__} {self.index}/{self.length}>"587 588 589class AsyncLoopContext(LoopContext):590    _iterator: t.AsyncIterator[t.Any]  # type: ignore591 592    @staticmethod593    def _to_iterator(  # type: ignore594        iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]],595    ) -> t.AsyncIterator[V]:596        return auto_aiter(iterable)597 598    @property599    async def length(self) -> int:  # type: ignore600        if self._length is not None:601            return self._length602 603        try:604            self._length = len(self._iterable)  # type: ignore605        except TypeError:606            iterable = [x async for x in self._iterator]607            self._iterator = self._to_iterator(iterable)608            self._length = len(iterable) + self.index + (self._after is not missing)609 610        return self._length611 612    @property613    async def revindex0(self) -> int:  # type: ignore614        return await self.length - self.index615 616    @property617    async def revindex(self) -> int:  # type: ignore618        return await self.length - self.index0619 620    async def _peek_next(self) -> t.Any:621        if self._after is not missing:622            return self._after623 624        try:625            self._after = await self._iterator.__anext__()626        except StopAsyncIteration:627            self._after = missing628 629        return self._after630 631    @property632    async def last(self) -> bool:  # type: ignore633        return await self._peek_next() is missing634 635    @property636    async def nextitem(self) -> t.Union[t.Any, "Undefined"]:637        rv = await self._peek_next()638 639        if rv is missing:640            return self._undefined("there is no next item")641 642        return rv643 644    def __aiter__(self) -> "AsyncLoopContext":645        return self646 647    async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]:648        if self._after is not missing:649            rv = self._after650            self._after = missing651        else:652            rv = await self._iterator.__anext__()653 654        self.index0 += 1655        self._before = self._current656        self._current = rv657        return rv, self658 659 660class Macro:661    """Wraps a macro function."""662 663    def __init__(664        self,665        environment: "Environment",666        func: t.Callable[..., str],667        name: str,668        arguments: t.List[str],669        catch_kwargs: bool,670        catch_varargs: bool,671        caller: bool,672        default_autoescape: t.Optional[bool] = None,673    ):674        self._environment = environment675        self._func = func676        self._argument_count = len(arguments)677        self.name = name678        self.arguments = arguments679        self.catch_kwargs = catch_kwargs680        self.catch_varargs = catch_varargs681        self.caller = caller682        self.explicit_caller = "caller" in arguments683 684        if default_autoescape is None:685            if callable(environment.autoescape):686                default_autoescape = environment.autoescape(None)687            else:688                default_autoescape = environment.autoescape689 690        self._default_autoescape = default_autoescape691 692    @internalcode693    @pass_eval_context694    def __call__(self, *args: t.Any, **kwargs: t.Any) -> str:695        # This requires a bit of explanation,  In the past we used to696        # decide largely based on compile-time information if a macro is697        # safe or unsafe.  While there was a volatile mode it was largely698        # unused for deciding on escaping.  This turns out to be699        # problematic for macros because whether a macro is safe depends not700        # on the escape mode when it was defined, but rather when it was used.701        #702        # Because however we export macros from the module system and703        # there are historic callers that do not pass an eval context (and704        # will continue to not pass one), we need to perform an instance705        # check here.706        #707        # This is considered safe because an eval context is not a valid708        # argument to callables otherwise anyway.  Worst case here is709        # that if no eval context is passed we fall back to the compile710        # time autoescape flag.711        if args and isinstance(args[0], EvalContext):712            autoescape = args[0].autoescape713            args = args[1:]714        else:715            autoescape = self._default_autoescape716 717        # try to consume the positional arguments718        arguments = list(args[: self._argument_count])719        off = len(arguments)720 721        # For information why this is necessary refer to the handling722        # of caller in the `macro_body` handler in the compiler.723        found_caller = False724 725        # if the number of arguments consumed is not the number of726        # arguments expected we start filling in keyword arguments727        # and defaults.728        if off != self._argument_count:729            for name in self.arguments[len(arguments) :]:730                try:731                    value = kwargs.pop(name)732                except KeyError:733                    value = missing734                if name == "caller":735                    found_caller = True736                arguments.append(value)737        else:738            found_caller = self.explicit_caller739 740        # it's important that the order of these arguments does not change741        # if not also changed in the compiler's `function_scoping` method.742        # the order is caller, keyword arguments, positional arguments!743        if self.caller and not found_caller:744            caller = kwargs.pop("caller", None)745            if caller is None:746                caller = self._environment.undefined("No caller defined", name="caller")747            arguments.append(caller)748 749        if self.catch_kwargs:750            arguments.append(kwargs)751        elif kwargs:752            if "caller" in kwargs:753                raise TypeError(754                    f"macro {self.name!r} was invoked with two values for the special"755                    " caller argument. This is most likely a bug."756                )757            raise TypeError(758                f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}"759            )760        if self.catch_varargs:761            arguments.append(args[self._argument_count :])762        elif len(args) > self._argument_count:763            raise TypeError(764                f"macro {self.name!r} takes not more than"765                f" {len(self.arguments)} argument(s)"766            )767 768        return self._invoke(arguments, autoescape)769 770    async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:771        rv = await self._func(*arguments)  # type: ignore772 773        if autoescape:774            return Markup(rv)775 776        return rv  # type: ignore777 778    def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:779        if self._environment.is_async:780            return self._async_invoke(arguments, autoescape)  # type: ignore781 782        rv = self._func(*arguments)783 784        if autoescape:785            rv = Markup(rv)786 787        return rv788 789    def __repr__(self) -> str:790        name = "anonymous" if self.name is None else repr(self.name)791        return f"<{type(self).__name__} {name}>"792 793 794class Undefined:795    """The default undefined type.  This undefined type can be printed and796    iterated over, but every other access will raise an :exc:`UndefinedError`:797 798    >>> foo = Undefined(name='foo')799    >>> str(foo)800    ''801    >>> not foo802    True803    >>> foo + 42804    Traceback (most recent call last):805      ...806    jinja2.exceptions.UndefinedError: 'foo' is undefined807    """808 809    __slots__ = (810        "_undefined_hint",811        "_undefined_obj",812        "_undefined_name",813        "_undefined_exception",814    )815 816    def __init__(817        self,818        hint: t.Optional[str] = None,819        obj: t.Any = missing,820        name: t.Optional[str] = None,821        exc: t.Type[TemplateRuntimeError] = UndefinedError,822    ) -> None:823        self._undefined_hint = hint824        self._undefined_obj = obj825        self._undefined_name = name826        self._undefined_exception = exc827 828    @property829    def _undefined_message(self) -> str:830        """Build a message about the undefined value based on how it was831        accessed.832        """833        if self._undefined_hint:834            return self._undefined_hint835 836        if self._undefined_obj is missing:837            return f"{self._undefined_name!r} is undefined"838 839        if not isinstance(self._undefined_name, str):840            return (841                f"{object_type_repr(self._undefined_obj)} has no"842                f" element {self._undefined_name!r}"843            )844 845        return (846            f"{object_type_repr(self._undefined_obj)!r} has no"847            f" attribute {self._undefined_name!r}"848        )849 850    @internalcode851    def _fail_with_undefined_error(852        self, *args: t.Any, **kwargs: t.Any853    ) -> "te.NoReturn":854        """Raise an :exc:`UndefinedError` when operations are performed855        on the undefined value.856        """857        raise self._undefined_exception(self._undefined_message)858 859    @internalcode860    def __getattr__(self, name: str) -> t.Any:861        if name[:2] == "__":862            raise AttributeError(name)863 864        return self._fail_with_undefined_error()865 866    __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error867    __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error868    __truediv__ = __rtruediv__ = _fail_with_undefined_error869    __floordiv__ = __rfloordiv__ = _fail_with_undefined_error870    __mod__ = __rmod__ = _fail_with_undefined_error871    __pos__ = __neg__ = _fail_with_undefined_error872    __call__ = __getitem__ = _fail_with_undefined_error873    __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error874    __int__ = __float__ = __complex__ = _fail_with_undefined_error875    __pow__ = __rpow__ = _fail_with_undefined_error876 877    def __eq__(self, other: t.Any) -> bool:878        return type(self) is type(other)879 880    def __ne__(self, other: t.Any) -> bool:881        return not self.__eq__(other)882 883    def __hash__(self) -> int:884        return id(type(self))885 886    def __str__(self) -> str:887        return ""888 889    def __len__(self) -> int:890        return 0891 892    def __iter__(self) -> t.Iterator[t.Any]:893        yield from ()894 895    async def __aiter__(self) -> t.AsyncIterator[t.Any]:896        for _ in ():897            yield898 899    def __bool__(self) -> bool:900        return False901 902    def __repr__(self) -> str:903        return "Undefined"904 905 906def make_logging_undefined(907    logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined908) -> t.Type[Undefined]:909    """Given a logger object this returns a new undefined class that will910    log certain failures.  It will log iterations and printing.  If no911    logger is given a default logger is created.912 913    Example::914 915        logger = logging.getLogger(__name__)916        LoggingUndefined = make_logging_undefined(917            logger=logger,918            base=Undefined919        )920 921    .. versionadded:: 2.8922 923    :param logger: the logger to use.  If not provided, a default logger924                   is created.925    :param base: the base class to add logging functionality to.  This926                 defaults to :class:`Undefined`.927    """928    if logger is None:929        import logging930 931        logger = logging.getLogger(__name__)932        logger.addHandler(logging.StreamHandler(sys.stderr))933 934    def _log_message(undef: Undefined) -> None:935        logger.warning("Template variable warning: %s", undef._undefined_message)936 937    class LoggingUndefined(base):  # type: ignore938        __slots__ = ()939 940        def _fail_with_undefined_error(  # type: ignore941            self, *args: t.Any, **kwargs: t.Any942        ) -> "te.NoReturn":943            try:944                super()._fail_with_undefined_error(*args, **kwargs)945            except self._undefined_exception as e:946                logger.error("Template variable error: %s", e)  # type: ignore947                raise e948 949        def __str__(self) -> str:950            _log_message(self)951            return super().__str__()  # type: ignore952 953        def __iter__(self) -> t.Iterator[t.Any]:954            _log_message(self)955            return super().__iter__()  # type: ignore956 957        def __bool__(self) -> bool:958            _log_message(self)959            return super().__bool__()  # type: ignore960 961    return LoggingUndefined962 963 964class ChainableUndefined(Undefined):965    """An undefined that is chainable, where both ``__getattr__`` and966    ``__getitem__`` return itself rather than raising an967    :exc:`UndefinedError`.968 969    >>> foo = ChainableUndefined(name='foo')970    >>> str(foo.bar['baz'])971    ''972    >>> foo.bar['baz'] + 42973    Traceback (most recent call last):974      ...975    jinja2.exceptions.UndefinedError: 'foo' is undefined976 977    .. versionadded:: 2.11.0978    """979 980    __slots__ = ()981 982    def __html__(self) -> str:983        return str(self)984 985    def __getattr__(self, _: str) -> "ChainableUndefined":986        return self987 988    __getitem__ = __getattr__  # type: ignore989 990 991class DebugUndefined(Undefined):992    """An undefined that returns the debug info when printed.993 994    >>> foo = DebugUndefined(name='foo')995    >>> str(foo)996    '{{ foo }}'997    >>> not foo998    True999    >>> foo + 421000    Traceback (most recent call last):1001      ...1002    jinja2.exceptions.UndefinedError: 'foo' is undefined1003    """1004 1005    __slots__ = ()1006 1007    def __str__(self) -> str:1008        if self._undefined_hint:1009            message = f"undefined value printed: {self._undefined_hint}"1010 1011        elif self._undefined_obj is missing:1012            message = self._undefined_name  # type: ignore1013 1014        else:1015            message = (1016                f"no such element: {object_type_repr(self._undefined_obj)}"1017                f"[{self._undefined_name!r}]"1018            )1019 1020        return f"{{{{ {message} }}}}"1021 1022 1023class StrictUndefined(Undefined):1024    """An undefined that barks on print and iteration as well as boolean1025    tests and all kinds of comparisons.  In other words: you can do nothing1026    with it except checking if it's defined using the `defined` test.1027 1028    >>> foo = StrictUndefined(name='foo')1029    >>> str(foo)1030    Traceback (most recent call last):1031      ...1032    jinja2.exceptions.UndefinedError: 'foo' is undefined1033    >>> not foo1034    Traceback (most recent call last):1035      ...1036    jinja2.exceptions.UndefinedError: 'foo' is undefined1037    >>> foo + 421038    Traceback (most recent call last):1039      ...1040    jinja2.exceptions.UndefinedError: 'foo' is undefined1041    """1042 1043    __slots__ = ()1044    __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error1045    __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error1046    __contains__ = Undefined._fail_with_undefined_error1047 1048 1049# Remove slots attributes, after the metaclass is applied they are1050# unneeded and contain wrong data for subclasses.1051del (1052    Undefined.__slots__,1053    ChainableUndefined.__slots__,1054    DebugUndefined.__slots__,1055    StrictUndefined.__slots__,1056)1057 
codekingpro/portable-devtools · Team Ai