jinja2.utils

  1import enum
  2import json
  3import os
  4import re
  5import typing as t
  6from collections import abc
  7from collections import deque
  8from random import choice
  9from random import randrange
 10from threading import Lock
 11from types import CodeType
 12from urllib.parse import quote_from_bytes
 13
 14import markupsafe
 15
 16if t.TYPE_CHECKING:
 17    import typing_extensions as te
 18
 19F = t.TypeVar("F", bound=t.Callable[..., t.Any])
 20
 21# special singleton representing missing values for the runtime
 22missing: t.Any = type("MissingType", (), {"__repr__": lambda x: "missing"})()
 23
 24internal_code: t.MutableSet[CodeType] = set()
 25
 26concat = "".join
 27
 28
 29def pass_context(f: F) -> F:
 30    """Pass the :class:`~jinja2.runtime.Context` as the first argument
 31    to the decorated function when called while rendering a template.
 32
 33    Can be used on functions, filters, and tests.
 34
 35    If only ``Context.eval_context`` is needed, use
 36    :func:`pass_eval_context`. If only ``Context.environment`` is
 37    needed, use :func:`pass_environment`.
 38
 39    .. versionadded:: 3.0.0
 40        Replaces ``contextfunction`` and ``contextfilter``.
 41    """
 42    f.jinja_pass_arg = _PassArg.context  # type: ignore
 43    return f
 44
 45
 46def pass_eval_context(f: F) -> F:
 47    """Pass the :class:`~jinja2.nodes.EvalContext` as the first argument
 48    to the decorated function when called while rendering a template.
 49    See :ref:`eval-context`.
 50
 51    Can be used on functions, filters, and tests.
 52
 53    If only ``EvalContext.environment`` is needed, use
 54    :func:`pass_environment`.
 55
 56    .. versionadded:: 3.0.0
 57        Replaces ``evalcontextfunction`` and ``evalcontextfilter``.
 58    """
 59    f.jinja_pass_arg = _PassArg.eval_context  # type: ignore
 60    return f
 61
 62
 63def pass_environment(f: F) -> F:
 64    """Pass the :class:`~jinja2.Environment` as the first argument to
 65    the decorated function when called while rendering a template.
 66
 67    Can be used on functions, filters, and tests.
 68
 69    .. versionadded:: 3.0.0
 70        Replaces ``environmentfunction`` and ``environmentfilter``.
 71    """
 72    f.jinja_pass_arg = _PassArg.environment  # type: ignore
 73    return f
 74
 75
 76class _PassArg(enum.Enum):
 77    context = enum.auto()
 78    eval_context = enum.auto()
 79    environment = enum.auto()
 80
 81    @classmethod
 82    def from_obj(cls, obj: F) -> t.Optional["_PassArg"]:
 83        if hasattr(obj, "jinja_pass_arg"):
 84            return obj.jinja_pass_arg  # type: ignore
 85
 86        return None
 87
 88
 89def internalcode(f: F) -> F:
 90    """Marks the function as internally used"""
 91    internal_code.add(f.__code__)
 92    return f
 93
 94
 95def is_undefined(obj: t.Any) -> bool:
 96    """Check if the object passed is undefined.  This does nothing more than
 97    performing an instance check against :class:`Undefined` but looks nicer.
 98    This can be used for custom filters or tests that want to react to
 99    undefined variables.  For example a custom default filter can look like
100    this::
101
102        def default(var, default=''):
103            if is_undefined(var):
104                return default
105            return var
106    """
107    from .runtime import Undefined
108
109    return isinstance(obj, Undefined)
110
111
112def consume(iterable: t.Iterable[t.Any]) -> None:
113    """Consumes an iterable without doing anything with it."""
114    for _ in iterable:
115        pass
116
117
118def clear_caches() -> None:
119    """Jinja keeps internal caches for environments and lexers.  These are
120    used so that Jinja doesn't have to recreate environments and lexers all
121    the time.  Normally you don't have to care about that but if you are
122    measuring memory consumption you may want to clean the caches.
123    """
124    from .environment import get_spontaneous_environment
125    from .lexer import _lexer_cache
126
127    get_spontaneous_environment.cache_clear()
128    _lexer_cache.clear()
129
130
131def import_string(import_name: str, silent: bool = False) -> t.Any:
132    """Imports an object based on a string.  This is useful if you want to
133    use import paths as endpoints or something similar.  An import path can
134    be specified either in dotted notation (``xml.sax.saxutils.escape``)
135    or with a colon as object delimiter (``xml.sax.saxutils:escape``).
136
137    If the `silent` is True the return value will be `None` if the import
138    fails.
139
140    :return: imported object
141    """
142    try:
143        if ":" in import_name:
144            module, obj = import_name.split(":", 1)
145        elif "." in import_name:
146            module, _, obj = import_name.rpartition(".")
147        else:
148            return __import__(import_name)
149        return getattr(__import__(module, None, None, [obj]), obj)
150    except (ImportError, AttributeError):
151        if not silent:
152            raise
153
154
155def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO[t.Any]]:
156    """Returns a file descriptor for the filename if that file exists,
157    otherwise ``None``.
158    """
159    if not os.path.isfile(filename):
160        return None
161
162    return open(filename, mode)
163
164
165def object_type_repr(obj: t.Any) -> str:
166    """Returns the name of the object's type.  For some recognized
167    singletons the name of the object is returned instead. (For
168    example for `None` and `Ellipsis`).
169    """
170    if obj is None:
171        return "None"
172    elif obj is Ellipsis:
173        return "Ellipsis"
174
175    cls = type(obj)
176
177    if cls.__module__ == "builtins":
178        return f"{cls.__name__} object"
179
180    return f"{cls.__module__}.{cls.__name__} object"
181
182
183def pformat(obj: t.Any) -> str:
184    """Format an object using :func:`pprint.pformat`."""
185    from pprint import pformat
186
187    return pformat(obj)
188
189
190_http_re = re.compile(
191    r"""
192    ^
193    (
194        (https?://|www\.)  # scheme or www
195        (([\w%-]+\.)+)?  # subdomain
196        (
197            [a-z]{2,63}  # basic tld
198        |
199            xn--[\w%]{2,59}  # idna tld
200        )
201    |
202        ([\w%-]{2,63}\.)+  # basic domain
203        (com|net|int|edu|gov|org|info|mil)  # basic tld
204    |
205        (https?://)  # scheme
206        (
207            (([\d]{1,3})(\.[\d]{1,3}){3})  # IPv4
208        |
209            (\[([\da-f]{0,4}:){2}([\da-f]{0,4}:?){1,6}])  # IPv6
210        )
211    )
212    (?::[\d]{1,5})?  # port
213    (?:[/?#]\S*)?  # path, query, and fragment
214    $
215    """,
216    re.IGNORECASE | re.VERBOSE,
217)
218_email_re = re.compile(r"^\S+@\w[\w.-]*\.\w+$")
219
220
221def urlize(
222    text: str,
223    trim_url_limit: t.Optional[int] = None,
224    rel: t.Optional[str] = None,
225    target: t.Optional[str] = None,
226    extra_schemes: t.Optional[t.Iterable[str]] = None,
227) -> str:
228    """Convert URLs in text into clickable links.
229
230    This may not recognize links in some situations. Usually, a more
231    comprehensive formatter, such as a Markdown library, is a better
232    choice.
233
234    Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
235    addresses. Links with trailing punctuation (periods, commas, closing
236    parentheses) and leading punctuation (opening parentheses) are
237    recognized excluding the punctuation. Email addresses that include
238    header fields are not recognized (for example,
239    ``mailto:address@example.com?cc=copy@example.com``).
240
241    :param text: Original text containing URLs to link.
242    :param trim_url_limit: Shorten displayed URL values to this length.
243    :param target: Add the ``target`` attribute to links.
244    :param rel: Add the ``rel`` attribute to links.
245    :param extra_schemes: Recognize URLs that start with these schemes
246        in addition to the default behavior.
247
248    .. versionchanged:: 3.0
249        The ``extra_schemes`` parameter was added.
250
251    .. versionchanged:: 3.0
252        Generate ``https://`` links for URLs without a scheme.
253
254    .. versionchanged:: 3.0
255        The parsing rules were updated. Recognize email addresses with
256        or without the ``mailto:`` scheme. Validate IP addresses. Ignore
257        parentheses and brackets in more cases.
258    """
259    if trim_url_limit is not None:
260
261        def trim_url(x: str) -> str:
262            if len(x) > trim_url_limit:
263                return f"{x[:trim_url_limit]}..."
264
265            return x
266
267    else:
268
269        def trim_url(x: str) -> str:
270            return x
271
272    words = re.split(r"(\s+)", str(markupsafe.escape(text)))
273    rel_attr = f' rel="{markupsafe.escape(rel)}"' if rel else ""
274    target_attr = f' target="{markupsafe.escape(target)}"' if target else ""
275
276    for i, word in enumerate(words):
277        head, middle, tail = "", word, ""
278        match = re.match(r"^([(<]|&lt;)+", middle)
279
280        if match:
281            head = match.group()
282            middle = middle[match.end() :]
283
284        # Unlike lead, which is anchored to the start of the string,
285        # need to check that the string ends with any of the characters
286        # before trying to match all of them, to avoid backtracking.
287        if middle.endswith((")", ">", ".", ",", "\n", "&gt;")):
288            match = re.search(r"([)>.,\n]|&gt;)+$", middle)
289
290            if match:
291                tail = match.group()
292                middle = middle[: match.start()]
293
294        # Prefer balancing parentheses in URLs instead of ignoring a
295        # trailing character.
296        for start_char, end_char in ("(", ")"), ("<", ">"), ("&lt;", "&gt;"):
297            start_count = middle.count(start_char)
298
299            if start_count <= middle.count(end_char):
300                # Balanced, or lighter on the left
301                continue
302
303            # Move as many as possible from the tail to balance
304            for _ in range(min(start_count, tail.count(end_char))):
305                end_index = tail.index(end_char) + len(end_char)
306                # Move anything in the tail before the end char too
307                middle += tail[:end_index]
308                tail = tail[end_index:]
309
310        if _http_re.match(middle):
311            if middle.startswith("https://") or middle.startswith("http://"):
312                middle = (
313                    f'<a href="{middle}"{rel_attr}{target_attr}>{trim_url(middle)}</a>'
314                )
315            else:
316                middle = (
317                    f'<a href="https://{middle}"{rel_attr}{target_attr}>'
318                    f"{trim_url(middle)}</a>"
319                )
320
321        elif middle.startswith("mailto:") and _email_re.match(middle[7:]):
322            middle = f'<a href="{middle}">{middle[7:]}</a>'
323
324        elif (
325            "@" in middle
326            and not middle.startswith("www.")
327            and ":" not in middle
328            and _email_re.match(middle)
329        ):
330            middle = f'<a href="mailto:{middle}">{middle}</a>'
331
332        elif extra_schemes is not None:
333            for scheme in extra_schemes:
334                if middle != scheme and middle.startswith(scheme):
335                    middle = f'<a href="{middle}"{rel_attr}{target_attr}>{middle}</a>'
336
337        words[i] = f"{head}{middle}{tail}"
338
339    return "".join(words)
340
341
342def generate_lorem_ipsum(
343    n: int = 5, html: bool = True, min: int = 20, max: int = 100
344) -> str:
345    """Generate some lorem ipsum for the template."""
346    from .constants import LOREM_IPSUM_WORDS
347
348    words = LOREM_IPSUM_WORDS.split()
349    result = []
350
351    for _ in range(n):
352        next_capitalized = True
353        last_comma = last_fullstop = 0
354        word = None
355        last = None
356        p = []
357
358        # each paragraph contains out of 20 to 100 words.
359        for idx, _ in enumerate(range(randrange(min, max))):
360            while True:
361                word = choice(words)
362                if word != last:
363                    last = word
364                    break
365            if next_capitalized:
366                word = word.capitalize()
367                next_capitalized = False
368            # add commas
369            if idx - randrange(3, 8) > last_comma:
370                last_comma = idx
371                last_fullstop += 2
372                word += ","
373            # add end of sentences
374            if idx - randrange(10, 20) > last_fullstop:
375                last_comma = last_fullstop = idx
376                word += "."
377                next_capitalized = True
378            p.append(word)
379
380        # ensure that the paragraph ends with a dot.
381        p_str = " ".join(p)
382
383        if p_str.endswith(","):
384            p_str = p_str[:-1] + "."
385        elif not p_str.endswith("."):
386            p_str += "."
387
388        result.append(p_str)
389
390    if not html:
391        return "\n\n".join(result)
392    return markupsafe.Markup(
393        "\n".join(f"<p>{markupsafe.escape(x)}</p>" for x in result)
394    )
395
396
397def url_quote(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str:
398    """Quote a string for use in a URL using the given charset.
399
400    :param obj: String or bytes to quote. Other types are converted to
401        string then encoded to bytes using the given charset.
402    :param charset: Encode text to bytes using this charset.
403    :param for_qs: Quote "/" and use "+" for spaces.
404    """
405    if not isinstance(obj, bytes):
406        if not isinstance(obj, str):
407            obj = str(obj)
408
409        obj = obj.encode(charset)
410
411    safe = b"" if for_qs else b"/"
412    rv = quote_from_bytes(obj, safe)
413
414    if for_qs:
415        rv = rv.replace("%20", "+")
416
417    return rv
418
419
420@abc.MutableMapping.register
421class LRUCache:
422    """A simple LRU Cache implementation."""
423
424    # this is fast for small capacities (something below 1000) but doesn't
425    # scale.  But as long as it's only used as storage for templates this
426    # won't do any harm.
427
428    def __init__(self, capacity: int) -> None:
429        self.capacity = capacity
430        self._mapping: t.Dict[t.Any, t.Any] = {}
431        self._queue: "te.Deque[t.Any]" = deque()
432        self._postinit()
433
434    def _postinit(self) -> None:
435        # alias all queue methods for faster lookup
436        self._popleft = self._queue.popleft
437        self._pop = self._queue.pop
438        self._remove = self._queue.remove
439        self._wlock = Lock()
440        self._append = self._queue.append
441
442    def __getstate__(self) -> t.Mapping[str, t.Any]:
443        return {
444            "capacity": self.capacity,
445            "_mapping": self._mapping,
446            "_queue": self._queue,
447        }
448
449    def __setstate__(self, d: t.Mapping[str, t.Any]) -> None:
450        self.__dict__.update(d)
451        self._postinit()
452
453    def __getnewargs__(self) -> t.Tuple[t.Any, ...]:
454        return (self.capacity,)
455
456    def copy(self) -> "LRUCache":
457        """Return a shallow copy of the instance."""
458        rv = self.__class__(self.capacity)
459        rv._mapping.update(self._mapping)
460        rv._queue.extend(self._queue)
461        return rv
462
463    def get(self, key: t.Any, default: t.Any = None) -> t.Any:
464        """Return an item from the cache dict or `default`"""
465        try:
466            return self[key]
467        except KeyError:
468            return default
469
470    def setdefault(self, key: t.Any, default: t.Any = None) -> t.Any:
471        """Set `default` if the key is not in the cache otherwise
472        leave unchanged. Return the value of this key.
473        """
474        try:
475            return self[key]
476        except KeyError:
477            self[key] = default
478            return default
479
480    def clear(self) -> None:
481        """Clear the cache."""
482        with self._wlock:
483            self._mapping.clear()
484            self._queue.clear()
485
486    def __contains__(self, key: t.Any) -> bool:
487        """Check if a key exists in this cache."""
488        return key in self._mapping
489
490    def __len__(self) -> int:
491        """Return the current size of the cache."""
492        return len(self._mapping)
493
494    def __repr__(self) -> str:
495        return f"<{type(self).__name__} {self._mapping!r}>"
496
497    def __getitem__(self, key: t.Any) -> t.Any:
498        """Get an item from the cache. Moves the item up so that it has the
499        highest priority then.
500
501        Raise a `KeyError` if it does not exist.
502        """
503        with self._wlock:
504            rv = self._mapping[key]
505
506            if self._queue[-1] != key:
507                try:
508                    self._remove(key)
509                except ValueError:
510                    # if something removed the key from the container
511                    # when we read, ignore the ValueError that we would
512                    # get otherwise.
513                    pass
514
515                self._append(key)
516
517            return rv
518
519    def __setitem__(self, key: t.Any, value: t.Any) -> None:
520        """Sets the value for an item. Moves the item up so that it
521        has the highest priority then.
522        """
523        with self._wlock:
524            if key in self._mapping:
525                self._remove(key)
526            elif len(self._mapping) == self.capacity:
527                del self._mapping[self._popleft()]
528
529            self._append(key)
530            self._mapping[key] = value
531
532    def __delitem__(self, key: t.Any) -> None:
533        """Remove an item from the cache dict.
534        Raise a `KeyError` if it does not exist.
535        """
536        with self._wlock:
537            del self._mapping[key]
538
539            try:
540                self._remove(key)
541            except ValueError:
542                pass
543
544    def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]:
545        """Return a list of items."""
546        result = [(key, self._mapping[key]) for key in list(self._queue)]
547        result.reverse()
548        return result
549
550    def values(self) -> t.Iterable[t.Any]:
551        """Return a list of all values."""
552        return [x[1] for x in self.items()]
553
554    def keys(self) -> t.Iterable[t.Any]:
555        """Return a list of all keys ordered by most recent usage."""
556        return list(self)
557
558    def __iter__(self) -> t.Iterator[t.Any]:
559        return reversed(tuple(self._queue))
560
561    def __reversed__(self) -> t.Iterator[t.Any]:
562        """Iterate over the keys in the cache dict, oldest items
563        coming first.
564        """
565        return iter(tuple(self._queue))
566
567    __copy__ = copy
568
569
570def select_autoescape(
571    enabled_extensions: t.Collection[str] = ("html", "htm", "xml"),
572    disabled_extensions: t.Collection[str] = (),
573    default_for_string: bool = True,
574    default: bool = False,
575) -> t.Callable[[t.Optional[str]], bool]:
576    """Intelligently sets the initial value of autoescaping based on the
577    filename of the template.  This is the recommended way to configure
578    autoescaping if you do not want to write a custom function yourself.
579
580    If you want to enable it for all templates created from strings or
581    for all templates with `.html` and `.xml` extensions::
582
583        from jinja2 import Environment, select_autoescape
584        env = Environment(autoescape=select_autoescape(
585            enabled_extensions=('html', 'xml'),
586            default_for_string=True,
587        ))
588
589    Example configuration to turn it on at all times except if the template
590    ends with `.txt`::
591
592        from jinja2 import Environment, select_autoescape
593        env = Environment(autoescape=select_autoescape(
594            disabled_extensions=('txt',),
595            default_for_string=True,
596            default=True,
597        ))
598
599    The `enabled_extensions` is an iterable of all the extensions that
600    autoescaping should be enabled for.  Likewise `disabled_extensions` is
601    a list of all templates it should be disabled for.  If a template is
602    loaded from a string then the default from `default_for_string` is used.
603    If nothing matches then the initial value of autoescaping is set to the
604    value of `default`.
605
606    For security reasons this function operates case insensitive.
607
608    .. versionadded:: 2.9
609    """
610    enabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in enabled_extensions)
611    disabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in disabled_extensions)
612
613    def autoescape(template_name: t.Optional[str]) -> bool:
614        if template_name is None:
615            return default_for_string
616        template_name = template_name.lower()
617        if template_name.endswith(enabled_patterns):
618            return True
619        if template_name.endswith(disabled_patterns):
620            return False
621        return default
622
623    return autoescape
624
625
626def htmlsafe_json_dumps(
627    obj: t.Any, dumps: t.Optional[t.Callable[..., str]] = None, **kwargs: t.Any
628) -> markupsafe.Markup:
629    """Serialize an object to a string of JSON with :func:`json.dumps`,
630    then replace HTML-unsafe characters with Unicode escapes and mark
631    the result safe with :class:`~markupsafe.Markup`.
632
633    This is available in templates as the ``|tojson`` filter.
634
635    The following characters are escaped: ``<``, ``>``, ``&``, ``'``.
636
637    The returned string is safe to render in HTML documents and
638    ``<script>`` tags. The exception is in HTML attributes that are
639    double quoted; either use single quotes or the ``|forceescape``
640    filter.
641
642    :param obj: The object to serialize to JSON.
643    :param dumps: The ``dumps`` function to use. Defaults to
644        ``env.policies["json.dumps_function"]``, which defaults to
645        :func:`json.dumps`.
646    :param kwargs: Extra arguments to pass to ``dumps``. Merged onto
647        ``env.policies["json.dumps_kwargs"]``.
648
649    .. versionchanged:: 3.0
650        The ``dumper`` parameter is renamed to ``dumps``.
651
652    .. versionadded:: 2.9
653    """
654    if dumps is None:
655        dumps = json.dumps
656
657    return markupsafe.Markup(
658        dumps(obj, **kwargs)
659        .replace("<", "\\u003c")
660        .replace(">", "\\u003e")
661        .replace("&", "\\u0026")
662        .replace("'", "\\u0027")
663    )
664
665
666class Cycler:
667    """Cycle through values by yield them one at a time, then restarting
668    once the end is reached. Available as ``cycler`` in templates.
669
670    Similar to ``loop.cycle``, but can be used outside loops or across
671    multiple loops. For example, render a list of folders and files in a
672    list, alternating giving them "odd" and "even" classes.
673
674    .. code-block:: html+jinja
675
676        {% set row_class = cycler("odd", "even") %}
677        <ul class="browser">
678        {% for folder in folders %}
679          <li class="folder {{ row_class.next() }}">{{ folder }}
680        {% endfor %}
681        {% for file in files %}
682          <li class="file {{ row_class.next() }}">{{ file }}
683        {% endfor %}
684        </ul>
685
686    :param items: Each positional argument will be yielded in the order
687        given for each cycle.
688
689    .. versionadded:: 2.1
690    """
691
692    def __init__(self, *items: t.Any) -> None:
693        if not items:
694            raise RuntimeError("at least one item has to be provided")
695        self.items = items
696        self.pos = 0
697
698    def reset(self) -> None:
699        """Resets the current item to the first item."""
700        self.pos = 0
701
702    @property
703    def current(self) -> t.Any:
704        """Return the current item. Equivalent to the item that will be
705        returned next time :meth:`next` is called.
706        """
707        return self.items[self.pos]
708
709    def next(self) -> t.Any:
710        """Return the current item, then advance :attr:`current` to the
711        next item.
712        """
713        rv = self.current
714        self.pos = (self.pos + 1) % len(self.items)
715        return rv
716
717    __next__ = next
718
719
720class Joiner:
721    """A joining helper for templates."""
722
723    def __init__(self, sep: str = ", ") -> None:
724        self.sep = sep
725        self.used = False
726
727    def __call__(self) -> str:
728        if not self.used:
729            self.used = True
730            return ""
731        return self.sep
732
733
734class Namespace:
735    """A namespace object that can hold arbitrary attributes.  It may be
736    initialized from a dictionary or with keyword arguments."""
737
738    def __init__(*args: t.Any, **kwargs: t.Any) -> None:  # noqa: B902
739        self, args = args[0], args[1:]
740        self.__attrs = dict(*args, **kwargs)
741
742    def __getattribute__(self, name: str) -> t.Any:
743        # __class__ is needed for the awaitable check in async mode
744        if name in {"_Namespace__attrs", "__class__"}:
745            return object.__getattribute__(self, name)
746        try:
747            return self.__attrs[name]
748        except KeyError:
749            raise AttributeError(name) from None
750
751    def __setitem__(self, name: str, value: t.Any) -> None:
752        self.__attrs[name] = value
753
754    def __repr__(self) -> str:
755        return f"<Namespace {self.__attrs!r}>"
missing: Any = missing
internal_code: MutableSet[code] = {<code object __call__ at 0x7fcb783babf0, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/runtime.py", line 571>, <code object load at 0x7fcb7832cff0, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/loaders.py", line 516>, <code object compile at 0x7fcb7842c3b0, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/environment.py", line 728>, <code object _async_call at 0x7fcb7842dc30, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/runtime.py", line 368>, <code object _fail_with_undefined_error at 0x7fcb783fe930, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/runtime.py", line 850>, <code object load at 0x5649a93a9670, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/loaders.py", line 641>, <code object __call__ at 0x7fcb7846da70, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/runtime.py", line 379>, <code object _load_template at 0x5649a92e25a0, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/environment.py", line 953>, <code object select_template at 0x7fcb78697a50, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/environment.py", line 1015>, <code object get_or_select_template at 0x7fcb78600c90, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/environment.py", line 1069>, <code object load at 0x5649a942bde0, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/loaders.py", line 107>, <code object __call__ at 0x5649a936ee30, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/runtime.py", line 692>, <code object __getattr__ at 0x7fcb783c9ac0, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/runtime.py", line 859>, <code object _get_default_module at 0x5649a92a6330, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/environment.py", line 1428>, <code object get_template at 0x7fcb7855bc30, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/environment.py", line 978>, <code object parse at 0x7fcb7860c3c0, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/environment.py", line 595>, <code object call at 0x5649a9356c90, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/runtime.py", line 262>, <code object load at 0x7fcb7832d140, file "/home/docs/.cache/pypoetry/virtualenvs/config-ninja-_T-5VH12-py3.12/lib/python3.12/site-packages/jinja2/loaders.py", line 566>}
def concat(iterable, /):

Concatenate any number of strings.

The string whose method is called is inserted in between each given string. The result is returned as a new string.

Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'

def pass_context(f: ~F) -> ~F:
30def pass_context(f: F) -> F:
31    """Pass the :class:`~jinja2.runtime.Context` as the first argument
32    to the decorated function when called while rendering a template.
33
34    Can be used on functions, filters, and tests.
35
36    If only ``Context.eval_context`` is needed, use
37    :func:`pass_eval_context`. If only ``Context.environment`` is
38    needed, use :func:`pass_environment`.
39
40    .. versionadded:: 3.0.0
41        Replaces ``contextfunction`` and ``contextfilter``.
42    """
43    f.jinja_pass_arg = _PassArg.context  # type: ignore
44    return f

Pass the ~jinja2.runtime.Context as the first argument to the decorated function when called while rendering a template.

Can be used on functions, filters, and tests.

If only Context.eval_context is needed, use pass_eval_context(). If only Context.environment is needed, use pass_environment().

New in version 3.0.0: Replaces contextfunction and contextfilter.

def pass_eval_context(f: ~F) -> ~F:
47def pass_eval_context(f: F) -> F:
48    """Pass the :class:`~jinja2.nodes.EvalContext` as the first argument
49    to the decorated function when called while rendering a template.
50    See :ref:`eval-context`.
51
52    Can be used on functions, filters, and tests.
53
54    If only ``EvalContext.environment`` is needed, use
55    :func:`pass_environment`.
56
57    .. versionadded:: 3.0.0
58        Replaces ``evalcontextfunction`` and ``evalcontextfilter``.
59    """
60    f.jinja_pass_arg = _PassArg.eval_context  # type: ignore
61    return f

Pass the ~jinja2.nodes.EvalContext as the first argument to the decorated function when called while rendering a template. See :ref:eval-context.

Can be used on functions, filters, and tests.

If only EvalContext.environment is needed, use pass_environment().

New in version 3.0.0: Replaces evalcontextfunction and evalcontextfilter.

def pass_environment(f: ~F) -> ~F:
64def pass_environment(f: F) -> F:
65    """Pass the :class:`~jinja2.Environment` as the first argument to
66    the decorated function when called while rendering a template.
67
68    Can be used on functions, filters, and tests.
69
70    .. versionadded:: 3.0.0
71        Replaces ``environmentfunction`` and ``environmentfilter``.
72    """
73    f.jinja_pass_arg = _PassArg.environment  # type: ignore
74    return f

Pass the ~jinja2.Environment as the first argument to the decorated function when called while rendering a template.

Can be used on functions, filters, and tests.

New in version 3.0.0: Replaces environmentfunction and environmentfilter.

def internalcode(f: ~F) -> ~F:
90def internalcode(f: F) -> F:
91    """Marks the function as internally used"""
92    internal_code.add(f.__code__)
93    return f

Marks the function as internally used

def is_undefined(obj: Any) -> bool:
 96def is_undefined(obj: t.Any) -> bool:
 97    """Check if the object passed is undefined.  This does nothing more than
 98    performing an instance check against :class:`Undefined` but looks nicer.
 99    This can be used for custom filters or tests that want to react to
100    undefined variables.  For example a custom default filter can look like
101    this::
102
103        def default(var, default=''):
104            if is_undefined(var):
105                return default
106            return var
107    """
108    from .runtime import Undefined
109
110    return isinstance(obj, Undefined)

Check if the object passed is undefined. This does nothing more than performing an instance check against Undefined but looks nicer. This can be used for custom filters or tests that want to react to undefined variables. For example a custom default filter can look like this::

def default(var, default=''):
    if is_undefined(var):
        return default
    return var
def consume(iterable: Iterable[Any]) -> None:
113def consume(iterable: t.Iterable[t.Any]) -> None:
114    """Consumes an iterable without doing anything with it."""
115    for _ in iterable:
116        pass

Consumes an iterable without doing anything with it.

def clear_caches() -> None:
119def clear_caches() -> None:
120    """Jinja keeps internal caches for environments and lexers.  These are
121    used so that Jinja doesn't have to recreate environments and lexers all
122    the time.  Normally you don't have to care about that but if you are
123    measuring memory consumption you may want to clean the caches.
124    """
125    from .environment import get_spontaneous_environment
126    from .lexer import _lexer_cache
127
128    get_spontaneous_environment.cache_clear()
129    _lexer_cache.clear()

Jinja keeps internal caches for environments and lexers. These are used so that Jinja doesn't have to recreate environments and lexers all the time. Normally you don't have to care about that but if you are measuring memory consumption you may want to clean the caches.

def import_string(import_name: str, silent: bool = False) -> Any:
132def import_string(import_name: str, silent: bool = False) -> t.Any:
133    """Imports an object based on a string.  This is useful if you want to
134    use import paths as endpoints or something similar.  An import path can
135    be specified either in dotted notation (``xml.sax.saxutils.escape``)
136    or with a colon as object delimiter (``xml.sax.saxutils:escape``).
137
138    If the `silent` is True the return value will be `None` if the import
139    fails.
140
141    :return: imported object
142    """
143    try:
144        if ":" in import_name:
145            module, obj = import_name.split(":", 1)
146        elif "." in import_name:
147            module, _, obj = import_name.rpartition(".")
148        else:
149            return __import__(import_name)
150        return getattr(__import__(module, None, None, [obj]), obj)
151    except (ImportError, AttributeError):
152        if not silent:
153            raise

Imports an object based on a string. This is useful if you want to use import paths as endpoints or something similar. An import path can be specified either in dotted notation (xml.sax.saxutils.escape) or with a colon as object delimiter (xml.sax.saxutils:escape).

If the silent is True the return value will be None if the import fails.

Returns

imported object

def open_if_exists(filename: str, mode: str = 'rb') -> Optional[IO[Any]]:
156def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO[t.Any]]:
157    """Returns a file descriptor for the filename if that file exists,
158    otherwise ``None``.
159    """
160    if not os.path.isfile(filename):
161        return None
162
163    return open(filename, mode)

Returns a file descriptor for the filename if that file exists, otherwise None.

def object_type_repr(obj: Any) -> str:
166def object_type_repr(obj: t.Any) -> str:
167    """Returns the name of the object's type.  For some recognized
168    singletons the name of the object is returned instead. (For
169    example for `None` and `Ellipsis`).
170    """
171    if obj is None:
172        return "None"
173    elif obj is Ellipsis:
174        return "Ellipsis"
175
176    cls = type(obj)
177
178    if cls.__module__ == "builtins":
179        return f"{cls.__name__} object"
180
181    return f"{cls.__module__}.{cls.__name__} object"

Returns the name of the object's type. For some recognized singletons the name of the object is returned instead. (For example for None and Ellipsis).

def pformat(obj: Any) -> str:
184def pformat(obj: t.Any) -> str:
185    """Format an object using :func:`pprint.pformat`."""
186    from pprint import pformat
187
188    return pformat(obj)

Format an object using pprint.pformat().

def urlize( text: str, trim_url_limit: Optional[int] = None, rel: Optional[str] = None, target: Optional[str] = None, extra_schemes: Optional[Iterable[str]] = None) -> str:
222def urlize(
223    text: str,
224    trim_url_limit: t.Optional[int] = None,
225    rel: t.Optional[str] = None,
226    target: t.Optional[str] = None,
227    extra_schemes: t.Optional[t.Iterable[str]] = None,
228) -> str:
229    """Convert URLs in text into clickable links.
230
231    This may not recognize links in some situations. Usually, a more
232    comprehensive formatter, such as a Markdown library, is a better
233    choice.
234
235    Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
236    addresses. Links with trailing punctuation (periods, commas, closing
237    parentheses) and leading punctuation (opening parentheses) are
238    recognized excluding the punctuation. Email addresses that include
239    header fields are not recognized (for example,
240    ``mailto:address@example.com?cc=copy@example.com``).
241
242    :param text: Original text containing URLs to link.
243    :param trim_url_limit: Shorten displayed URL values to this length.
244    :param target: Add the ``target`` attribute to links.
245    :param rel: Add the ``rel`` attribute to links.
246    :param extra_schemes: Recognize URLs that start with these schemes
247        in addition to the default behavior.
248
249    .. versionchanged:: 3.0
250        The ``extra_schemes`` parameter was added.
251
252    .. versionchanged:: 3.0
253        Generate ``https://`` links for URLs without a scheme.
254
255    .. versionchanged:: 3.0
256        The parsing rules were updated. Recognize email addresses with
257        or without the ``mailto:`` scheme. Validate IP addresses. Ignore
258        parentheses and brackets in more cases.
259    """
260    if trim_url_limit is not None:
261
262        def trim_url(x: str) -> str:
263            if len(x) > trim_url_limit:
264                return f"{x[:trim_url_limit]}..."
265
266            return x
267
268    else:
269
270        def trim_url(x: str) -> str:
271            return x
272
273    words = re.split(r"(\s+)", str(markupsafe.escape(text)))
274    rel_attr = f' rel="{markupsafe.escape(rel)}"' if rel else ""
275    target_attr = f' target="{markupsafe.escape(target)}"' if target else ""
276
277    for i, word in enumerate(words):
278        head, middle, tail = "", word, ""
279        match = re.match(r"^([(<]|&lt;)+", middle)
280
281        if match:
282            head = match.group()
283            middle = middle[match.end() :]
284
285        # Unlike lead, which is anchored to the start of the string,
286        # need to check that the string ends with any of the characters
287        # before trying to match all of them, to avoid backtracking.
288        if middle.endswith((")", ">", ".", ",", "\n", "&gt;")):
289            match = re.search(r"([)>.,\n]|&gt;)+$", middle)
290
291            if match:
292                tail = match.group()
293                middle = middle[: match.start()]
294
295        # Prefer balancing parentheses in URLs instead of ignoring a
296        # trailing character.
297        for start_char, end_char in ("(", ")"), ("<", ">"), ("&lt;", "&gt;"):
298            start_count = middle.count(start_char)
299
300            if start_count <= middle.count(end_char):
301                # Balanced, or lighter on the left
302                continue
303
304            # Move as many as possible from the tail to balance
305            for _ in range(min(start_count, tail.count(end_char))):
306                end_index = tail.index(end_char) + len(end_char)
307                # Move anything in the tail before the end char too
308                middle += tail[:end_index]
309                tail = tail[end_index:]
310
311        if _http_re.match(middle):
312            if middle.startswith("https://") or middle.startswith("http://"):
313                middle = (
314                    f'<a href="{middle}"{rel_attr}{target_attr}>{trim_url(middle)}</a>'
315                )
316            else:
317                middle = (
318                    f'<a href="https://{middle}"{rel_attr}{target_attr}>'
319                    f"{trim_url(middle)}</a>"
320                )
321
322        elif middle.startswith("mailto:") and _email_re.match(middle[7:]):
323            middle = f'<a href="{middle}">{middle[7:]}</a>'
324
325        elif (
326            "@" in middle
327            and not middle.startswith("www.")
328            and ":" not in middle
329            and _email_re.match(middle)
330        ):
331            middle = f'<a href="mailto:{middle}">{middle}</a>'
332
333        elif extra_schemes is not None:
334            for scheme in extra_schemes:
335                if middle != scheme and middle.startswith(scheme):
336                    middle = f'<a href="{middle}"{rel_attr}{target_attr}>{middle}</a>'
337
338        words[i] = f"{head}{middle}{tail}"
339
340    return "".join(words)

Convert URLs in text into clickable links.

This may not recognize links in some situations. Usually, a more comprehensive formatter, such as a Markdown library, is a better choice.

Works on http://, https://, www., mailto:, and email addresses. Links with trailing punctuation (periods, commas, closing parentheses) and leading punctuation (opening parentheses) are recognized excluding the punctuation. Email addresses that include header fields are not recognized (for example, mailto:address@example.com?cc=copy@example.com).

Parameters
  • text: Original text containing URLs to link.
  • trim_url_limit: Shorten displayed URL values to this length.
  • target: Add the target attribute to links.
  • rel: Add the rel attribute to links.
  • extra_schemes: Recognize URLs that start with these schemes in addition to the default behavior.

Changed in version 3.0: The extra_schemes parameter was added.

Changed in version 3.0: Generate https:// links for URLs without a scheme.

Changed in version 3.0: The parsing rules were updated. Recognize email addresses with or without the mailto: scheme. Validate IP addresses. Ignore parentheses and brackets in more cases.

def generate_lorem_ipsum(n: int = 5, html: bool = True, min: int = 20, max: int = 100) -> str:
343def generate_lorem_ipsum(
344    n: int = 5, html: bool = True, min: int = 20, max: int = 100
345) -> str:
346    """Generate some lorem ipsum for the template."""
347    from .constants import LOREM_IPSUM_WORDS
348
349    words = LOREM_IPSUM_WORDS.split()
350    result = []
351
352    for _ in range(n):
353        next_capitalized = True
354        last_comma = last_fullstop = 0
355        word = None
356        last = None
357        p = []
358
359        # each paragraph contains out of 20 to 100 words.
360        for idx, _ in enumerate(range(randrange(min, max))):
361            while True:
362                word = choice(words)
363                if word != last:
364                    last = word
365                    break
366            if next_capitalized:
367                word = word.capitalize()
368                next_capitalized = False
369            # add commas
370            if idx - randrange(3, 8) > last_comma:
371                last_comma = idx
372                last_fullstop += 2
373                word += ","
374            # add end of sentences
375            if idx - randrange(10, 20) > last_fullstop:
376                last_comma = last_fullstop = idx
377                word += "."
378                next_capitalized = True
379            p.append(word)
380
381        # ensure that the paragraph ends with a dot.
382        p_str = " ".join(p)
383
384        if p_str.endswith(","):
385            p_str = p_str[:-1] + "."
386        elif not p_str.endswith("."):
387            p_str += "."
388
389        result.append(p_str)
390
391    if not html:
392        return "\n\n".join(result)
393    return markupsafe.Markup(
394        "\n".join(f"<p>{markupsafe.escape(x)}</p>" for x in result)
395    )

Generate some lorem ipsum for the template.

def url_quote(obj: Any, charset: str = 'utf-8', for_qs: bool = False) -> str:
398def url_quote(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str:
399    """Quote a string for use in a URL using the given charset.
400
401    :param obj: String or bytes to quote. Other types are converted to
402        string then encoded to bytes using the given charset.
403    :param charset: Encode text to bytes using this charset.
404    :param for_qs: Quote "/" and use "+" for spaces.
405    """
406    if not isinstance(obj, bytes):
407        if not isinstance(obj, str):
408            obj = str(obj)
409
410        obj = obj.encode(charset)
411
412    safe = b"" if for_qs else b"/"
413    rv = quote_from_bytes(obj, safe)
414
415    if for_qs:
416        rv = rv.replace("%20", "+")
417
418    return rv

Quote a string for use in a URL using the given charset.

Parameters
  • obj: String or bytes to quote. Other types are converted to string then encoded to bytes using the given charset.
  • charset: Encode text to bytes using this charset.
  • for_qs: Quote "/" and use "+" for spaces.
@abc.MutableMapping.register
class LRUCache:
421@abc.MutableMapping.register
422class LRUCache:
423    """A simple LRU Cache implementation."""
424
425    # this is fast for small capacities (something below 1000) but doesn't
426    # scale.  But as long as it's only used as storage for templates this
427    # won't do any harm.
428
429    def __init__(self, capacity: int) -> None:
430        self.capacity = capacity
431        self._mapping: t.Dict[t.Any, t.Any] = {}
432        self._queue: "te.Deque[t.Any]" = deque()
433        self._postinit()
434
435    def _postinit(self) -> None:
436        # alias all queue methods for faster lookup
437        self._popleft = self._queue.popleft
438        self._pop = self._queue.pop
439        self._remove = self._queue.remove
440        self._wlock = Lock()
441        self._append = self._queue.append
442
443    def __getstate__(self) -> t.Mapping[str, t.Any]:
444        return {
445            "capacity": self.capacity,
446            "_mapping": self._mapping,
447            "_queue": self._queue,
448        }
449
450    def __setstate__(self, d: t.Mapping[str, t.Any]) -> None:
451        self.__dict__.update(d)
452        self._postinit()
453
454    def __getnewargs__(self) -> t.Tuple[t.Any, ...]:
455        return (self.capacity,)
456
457    def copy(self) -> "LRUCache":
458        """Return a shallow copy of the instance."""
459        rv = self.__class__(self.capacity)
460        rv._mapping.update(self._mapping)
461        rv._queue.extend(self._queue)
462        return rv
463
464    def get(self, key: t.Any, default: t.Any = None) -> t.Any:
465        """Return an item from the cache dict or `default`"""
466        try:
467            return self[key]
468        except KeyError:
469            return default
470
471    def setdefault(self, key: t.Any, default: t.Any = None) -> t.Any:
472        """Set `default` if the key is not in the cache otherwise
473        leave unchanged. Return the value of this key.
474        """
475        try:
476            return self[key]
477        except KeyError:
478            self[key] = default
479            return default
480
481    def clear(self) -> None:
482        """Clear the cache."""
483        with self._wlock:
484            self._mapping.clear()
485            self._queue.clear()
486
487    def __contains__(self, key: t.Any) -> bool:
488        """Check if a key exists in this cache."""
489        return key in self._mapping
490
491    def __len__(self) -> int:
492        """Return the current size of the cache."""
493        return len(self._mapping)
494
495    def __repr__(self) -> str:
496        return f"<{type(self).__name__} {self._mapping!r}>"
497
498    def __getitem__(self, key: t.Any) -> t.Any:
499        """Get an item from the cache. Moves the item up so that it has the
500        highest priority then.
501
502        Raise a `KeyError` if it does not exist.
503        """
504        with self._wlock:
505            rv = self._mapping[key]
506
507            if self._queue[-1] != key:
508                try:
509                    self._remove(key)
510                except ValueError:
511                    # if something removed the key from the container
512                    # when we read, ignore the ValueError that we would
513                    # get otherwise.
514                    pass
515
516                self._append(key)
517
518            return rv
519
520    def __setitem__(self, key: t.Any, value: t.Any) -> None:
521        """Sets the value for an item. Moves the item up so that it
522        has the highest priority then.
523        """
524        with self._wlock:
525            if key in self._mapping:
526                self._remove(key)
527            elif len(self._mapping) == self.capacity:
528                del self._mapping[self._popleft()]
529
530            self._append(key)
531            self._mapping[key] = value
532
533    def __delitem__(self, key: t.Any) -> None:
534        """Remove an item from the cache dict.
535        Raise a `KeyError` if it does not exist.
536        """
537        with self._wlock:
538            del self._mapping[key]
539
540            try:
541                self._remove(key)
542            except ValueError:
543                pass
544
545    def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]:
546        """Return a list of items."""
547        result = [(key, self._mapping[key]) for key in list(self._queue)]
548        result.reverse()
549        return result
550
551    def values(self) -> t.Iterable[t.Any]:
552        """Return a list of all values."""
553        return [x[1] for x in self.items()]
554
555    def keys(self) -> t.Iterable[t.Any]:
556        """Return a list of all keys ordered by most recent usage."""
557        return list(self)
558
559    def __iter__(self) -> t.Iterator[t.Any]:
560        return reversed(tuple(self._queue))
561
562    def __reversed__(self) -> t.Iterator[t.Any]:
563        """Iterate over the keys in the cache dict, oldest items
564        coming first.
565        """
566        return iter(tuple(self._queue))
567
568    __copy__ = copy

A simple LRU Cache implementation.

LRUCache(capacity: int)
429    def __init__(self, capacity: int) -> None:
430        self.capacity = capacity
431        self._mapping: t.Dict[t.Any, t.Any] = {}
432        self._queue: "te.Deque[t.Any]" = deque()
433        self._postinit()
capacity
def copy(self) -> LRUCache:
457    def copy(self) -> "LRUCache":
458        """Return a shallow copy of the instance."""
459        rv = self.__class__(self.capacity)
460        rv._mapping.update(self._mapping)
461        rv._queue.extend(self._queue)
462        return rv

Return a shallow copy of the instance.

def get(self, key: Any, default: Any = None) -> Any:
464    def get(self, key: t.Any, default: t.Any = None) -> t.Any:
465        """Return an item from the cache dict or `default`"""
466        try:
467            return self[key]
468        except KeyError:
469            return default

Return an item from the cache dict or default

def setdefault(self, key: Any, default: Any = None) -> Any:
471    def setdefault(self, key: t.Any, default: t.Any = None) -> t.Any:
472        """Set `default` if the key is not in the cache otherwise
473        leave unchanged. Return the value of this key.
474        """
475        try:
476            return self[key]
477        except KeyError:
478            self[key] = default
479            return default

Set default if the key is not in the cache otherwise leave unchanged. Return the value of this key.

def clear(self) -> None:
481    def clear(self) -> None:
482        """Clear the cache."""
483        with self._wlock:
484            self._mapping.clear()
485            self._queue.clear()

Clear the cache.

def items(self) -> Iterable[Tuple[Any, Any]]:
545    def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]:
546        """Return a list of items."""
547        result = [(key, self._mapping[key]) for key in list(self._queue)]
548        result.reverse()
549        return result

Return a list of items.

def values(self) -> Iterable[Any]:
551    def values(self) -> t.Iterable[t.Any]:
552        """Return a list of all values."""
553        return [x[1] for x in self.items()]

Return a list of all values.

def keys(self) -> Iterable[Any]:
555    def keys(self) -> t.Iterable[t.Any]:
556        """Return a list of all keys ordered by most recent usage."""
557        return list(self)

Return a list of all keys ordered by most recent usage.

def select_autoescape( enabled_extensions: Collection[str] = ('html', 'htm', 'xml'), disabled_extensions: Collection[str] = (), default_for_string: bool = True, default: bool = False) -> Callable[[Optional[str]], bool]:
571def select_autoescape(
572    enabled_extensions: t.Collection[str] = ("html", "htm", "xml"),
573    disabled_extensions: t.Collection[str] = (),
574    default_for_string: bool = True,
575    default: bool = False,
576) -> t.Callable[[t.Optional[str]], bool]:
577    """Intelligently sets the initial value of autoescaping based on the
578    filename of the template.  This is the recommended way to configure
579    autoescaping if you do not want to write a custom function yourself.
580
581    If you want to enable it for all templates created from strings or
582    for all templates with `.html` and `.xml` extensions::
583
584        from jinja2 import Environment, select_autoescape
585        env = Environment(autoescape=select_autoescape(
586            enabled_extensions=('html', 'xml'),
587            default_for_string=True,
588        ))
589
590    Example configuration to turn it on at all times except if the template
591    ends with `.txt`::
592
593        from jinja2 import Environment, select_autoescape
594        env = Environment(autoescape=select_autoescape(
595            disabled_extensions=('txt',),
596            default_for_string=True,
597            default=True,
598        ))
599
600    The `enabled_extensions` is an iterable of all the extensions that
601    autoescaping should be enabled for.  Likewise `disabled_extensions` is
602    a list of all templates it should be disabled for.  If a template is
603    loaded from a string then the default from `default_for_string` is used.
604    If nothing matches then the initial value of autoescaping is set to the
605    value of `default`.
606
607    For security reasons this function operates case insensitive.
608
609    .. versionadded:: 2.9
610    """
611    enabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in enabled_extensions)
612    disabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in disabled_extensions)
613
614    def autoescape(template_name: t.Optional[str]) -> bool:
615        if template_name is None:
616            return default_for_string
617        template_name = template_name.lower()
618        if template_name.endswith(enabled_patterns):
619            return True
620        if template_name.endswith(disabled_patterns):
621            return False
622        return default
623
624    return autoescape

Intelligently sets the initial value of autoescaping based on the filename of the template. This is the recommended way to configure autoescaping if you do not want to write a custom function yourself.

If you want to enable it for all templates created from strings or for all templates with .html and .xml extensions::

from jinja2 import Environment, select_autoescape
env = Environment(autoescape=select_autoescape(
    enabled_extensions=('html', 'xml'),
    default_for_string=True,
))

Example configuration to turn it on at all times except if the template ends with .txt::

from jinja2 import Environment, select_autoescape
env = Environment(autoescape=select_autoescape(
    disabled_extensions=('txt',),
    default_for_string=True,
    default=True,
))

The enabled_extensions is an iterable of all the extensions that autoescaping should be enabled for. Likewise disabled_extensions is a list of all templates it should be disabled for. If a template is loaded from a string then the default from default_for_string is used. If nothing matches then the initial value of autoescaping is set to the value of default.

For security reasons this function operates case insensitive.

New in version 2.9.

def htmlsafe_json_dumps( obj: Any, dumps: Optional[Callable[..., str]] = None, **kwargs: Any) -> markupsafe.Markup:
627def htmlsafe_json_dumps(
628    obj: t.Any, dumps: t.Optional[t.Callable[..., str]] = None, **kwargs: t.Any
629) -> markupsafe.Markup:
630    """Serialize an object to a string of JSON with :func:`json.dumps`,
631    then replace HTML-unsafe characters with Unicode escapes and mark
632    the result safe with :class:`~markupsafe.Markup`.
633
634    This is available in templates as the ``|tojson`` filter.
635
636    The following characters are escaped: ``<``, ``>``, ``&``, ``'``.
637
638    The returned string is safe to render in HTML documents and
639    ``<script>`` tags. The exception is in HTML attributes that are
640    double quoted; either use single quotes or the ``|forceescape``
641    filter.
642
643    :param obj: The object to serialize to JSON.
644    :param dumps: The ``dumps`` function to use. Defaults to
645        ``env.policies["json.dumps_function"]``, which defaults to
646        :func:`json.dumps`.
647    :param kwargs: Extra arguments to pass to ``dumps``. Merged onto
648        ``env.policies["json.dumps_kwargs"]``.
649
650    .. versionchanged:: 3.0
651        The ``dumper`` parameter is renamed to ``dumps``.
652
653    .. versionadded:: 2.9
654    """
655    if dumps is None:
656        dumps = json.dumps
657
658    return markupsafe.Markup(
659        dumps(obj, **kwargs)
660        .replace("<", "\\u003c")
661        .replace(">", "\\u003e")
662        .replace("&", "\\u0026")
663        .replace("'", "\\u0027")
664    )

Serialize an object to a string of JSON with json.dumps(), then replace HTML-unsafe characters with Unicode escapes and mark the result safe with ~markupsafe.Markup.

This is available in templates as the |tojson filter.

The following characters are escaped: <, >, &, '.

The returned string is safe to render in HTML documents and <script> tags. The exception is in HTML attributes that are double quoted; either use single quotes or the |forceescape filter.

Parameters
  • obj: The object to serialize to JSON.
  • dumps: The dumps function to use. Defaults to env.policies["json.dumps_function"], which defaults to json.dumps().
  • kwargs: Extra arguments to pass to dumps. Merged onto env.policies["json.dumps_kwargs"].

Changed in version 3.0: The dumper parameter is renamed to dumps.

New in version 2.9.

class Cycler:
667class Cycler:
668    """Cycle through values by yield them one at a time, then restarting
669    once the end is reached. Available as ``cycler`` in templates.
670
671    Similar to ``loop.cycle``, but can be used outside loops or across
672    multiple loops. For example, render a list of folders and files in a
673    list, alternating giving them "odd" and "even" classes.
674
675    .. code-block:: html+jinja
676
677        {% set row_class = cycler("odd", "even") %}
678        <ul class="browser">
679        {% for folder in folders %}
680          <li class="folder {{ row_class.next() }}">{{ folder }}
681        {% endfor %}
682        {% for file in files %}
683          <li class="file {{ row_class.next() }}">{{ file }}
684        {% endfor %}
685        </ul>
686
687    :param items: Each positional argument will be yielded in the order
688        given for each cycle.
689
690    .. versionadded:: 2.1
691    """
692
693    def __init__(self, *items: t.Any) -> None:
694        if not items:
695            raise RuntimeError("at least one item has to be provided")
696        self.items = items
697        self.pos = 0
698
699    def reset(self) -> None:
700        """Resets the current item to the first item."""
701        self.pos = 0
702
703    @property
704    def current(self) -> t.Any:
705        """Return the current item. Equivalent to the item that will be
706        returned next time :meth:`next` is called.
707        """
708        return self.items[self.pos]
709
710    def next(self) -> t.Any:
711        """Return the current item, then advance :attr:`current` to the
712        next item.
713        """
714        rv = self.current
715        self.pos = (self.pos + 1) % len(self.items)
716        return rv
717
718    __next__ = next

Cycle through values by yield them one at a time, then restarting once the end is reached. Available as cycler in templates.

Similar to loop.cycle, but can be used outside loops or across multiple loops. For example, render a list of folders and files in a list, alternating giving them "odd" and "even" classes.

{% set row_class = cycler("odd", "even") %}
<ul class="browser">
{% for folder in folders %}
  <li class="folder {{ row_class.next() }}">{{ folder }}
{% endfor %}
{% for file in files %}
  <li class="file {{ row_class.next() }}">{{ file }}
{% endfor %}
</ul>
Parameters
  • items: Each positional argument will be yielded in the order given for each cycle.

New in version 2.1.

Cycler(*items: Any)
693    def __init__(self, *items: t.Any) -> None:
694        if not items:
695            raise RuntimeError("at least one item has to be provided")
696        self.items = items
697        self.pos = 0
items
pos
def reset(self) -> None:
699    def reset(self) -> None:
700        """Resets the current item to the first item."""
701        self.pos = 0

Resets the current item to the first item.

current: Any
703    @property
704    def current(self) -> t.Any:
705        """Return the current item. Equivalent to the item that will be
706        returned next time :meth:`next` is called.
707        """
708        return self.items[self.pos]

Return the current item. Equivalent to the item that will be returned next time next() is called.

def next(self) -> Any:
710    def next(self) -> t.Any:
711        """Return the current item, then advance :attr:`current` to the
712        next item.
713        """
714        rv = self.current
715        self.pos = (self.pos + 1) % len(self.items)
716        return rv

Return the current item, then advance current to the next item.

class Joiner:
721class Joiner:
722    """A joining helper for templates."""
723
724    def __init__(self, sep: str = ", ") -> None:
725        self.sep = sep
726        self.used = False
727
728    def __call__(self) -> str:
729        if not self.used:
730            self.used = True
731            return ""
732        return self.sep

A joining helper for templates.

Joiner(sep: str = ', ')
724    def __init__(self, sep: str = ", ") -> None:
725        self.sep = sep
726        self.used = False
sep
used
class Namespace:
735class Namespace:
736    """A namespace object that can hold arbitrary attributes.  It may be
737    initialized from a dictionary or with keyword arguments."""
738
739    def __init__(*args: t.Any, **kwargs: t.Any) -> None:  # noqa: B902
740        self, args = args[0], args[1:]
741        self.__attrs = dict(*args, **kwargs)
742
743    def __getattribute__(self, name: str) -> t.Any:
744        # __class__ is needed for the awaitable check in async mode
745        if name in {"_Namespace__attrs", "__class__"}:
746            return object.__getattribute__(self, name)
747        try:
748            return self.__attrs[name]
749        except KeyError:
750            raise AttributeError(name) from None
751
752    def __setitem__(self, name: str, value: t.Any) -> None:
753        self.__attrs[name] = value
754
755    def __repr__(self) -> str:
756        return f"<Namespace {self.__attrs!r}>"

A namespace object that can hold arbitrary attributes. It may be initialized from a dictionary or with keyword arguments.

Namespace(**kwargs: Any)
739    def __init__(*args: t.Any, **kwargs: t.Any) -> None:  # noqa: B902
740        self, args = args[0], args[1:]
741        self.__attrs = dict(*args, **kwargs)