summaryrefslogtreecommitdiffstats
path: root/contrib/python/Jinja2/py3/jinja2/utils.py
diff options
context:
space:
mode:
authorfloatdrop <[email protected]>2022-02-10 16:47:15 +0300
committerDaniil Cherednik <[email protected]>2022-02-10 16:47:15 +0300
commite63b84f1d39557d9e46ac380b1f388271894293c (patch)
tree338cdaff3fb027e030b847db66df06019a0e3149 /contrib/python/Jinja2/py3/jinja2/utils.py
parentf60febb7ea449535e7b073c386c7ff0539637fc0 (diff)
Restoring authorship annotation for <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/Jinja2/py3/jinja2/utils.py')
-rw-r--r--contrib/python/Jinja2/py3/jinja2/utils.py682
1 files changed, 341 insertions, 341 deletions
diff --git a/contrib/python/Jinja2/py3/jinja2/utils.py b/contrib/python/Jinja2/py3/jinja2/utils.py
index 567185f41fc..261b1185834 100644
--- a/contrib/python/Jinja2/py3/jinja2/utils.py
+++ b/contrib/python/Jinja2/py3/jinja2/utils.py
@@ -1,54 +1,54 @@
import enum
import json
import os
-import re
+import re
import typing as t
import warnings
from collections import abc
-from collections import deque
+from collections import deque
from random import choice
from random import randrange
-from threading import Lock
+from threading import Lock
from types import CodeType
from urllib.parse import quote_from_bytes
-
+
import markupsafe
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
-# special singleton representing missing values for the runtime
+# special singleton representing missing values for the runtime
missing: t.Any = type("MissingType", (), {"__repr__": lambda x: "missing"})()
-
+
internal_code: t.MutableSet[CodeType] = set()
-
+
concat = "".join
-
-
+
+
def pass_context(f: F) -> F:
"""Pass the :class:`~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
:func:`pass_eval_context`. If only ``Context.environment`` is
needed, use :func:`pass_environment`.
.. versionadded:: 3.0.0
Replaces ``contextfunction`` and ``contextfilter``.
- """
+ """
f.jinja_pass_arg = _PassArg.context # type: ignore
- return f
-
-
+ return f
+
+
def pass_eval_context(f: F) -> F:
"""Pass the :class:`~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
@@ -56,11 +56,11 @@ def pass_eval_context(f: F) -> F:
.. versionadded:: 3.0.0
Replaces ``evalcontextfunction`` and ``evalcontextfilter``.
- """
+ """
f.jinja_pass_arg = _PassArg.eval_context # type: ignore
- return f
-
-
+ return f
+
+
def pass_environment(f: F) -> F:
"""Pass the :class:`~jinja2.Environment` as the first argument to
the decorated function when called while rendering a template.
@@ -69,11 +69,11 @@ def pass_environment(f: F) -> F:
.. versionadded:: 3.0.0
Replaces ``environmentfunction`` and ``environmentfilter``.
- """
+ """
f.jinja_pass_arg = _PassArg.environment # type: ignore
- return f
-
-
+ return f
+
+
class _PassArg(enum.Enum):
context = enum.auto()
eval_context = enum.auto()
@@ -153,98 +153,98 @@ def environmentfunction(f: F) -> F:
def internalcode(f: F) -> F:
- """Marks the function as internally used"""
- internal_code.add(f.__code__)
- return f
-
-
+ """Marks the function as internally used"""
+ internal_code.add(f.__code__)
+ return f
+
+
def is_undefined(obj: t.Any) -> bool:
- """Check if the object passed is undefined. This does nothing more than
- performing an instance check against :class:`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
- """
+ """Check if the object passed is undefined. This does nothing more than
+ performing an instance check against :class:`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
+ """
from .runtime import Undefined
- return isinstance(obj, Undefined)
-
-
+ return isinstance(obj, Undefined)
+
+
def consume(iterable: t.Iterable[t.Any]) -> None:
- """Consumes an iterable without doing anything with it."""
+ """Consumes an iterable without doing anything with it."""
for _ in iterable:
- pass
-
-
+ pass
+
+
def clear_caches() -> None:
"""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.
- """
+ 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.
+ """
from .environment import get_spontaneous_environment
from .lexer import _lexer_cache
get_spontaneous_environment.cache_clear()
- _lexer_cache.clear()
-
-
+ _lexer_cache.clear()
+
+
def import_string(import_name: str, silent: bool = False) -> t.Any:
- """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.
-
- :return: imported object
- """
- try:
+ """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.
+
+ :return: imported object
+ """
+ try:
if ":" in import_name:
module, obj = import_name.split(":", 1)
elif "." in import_name:
module, _, obj = import_name.rpartition(".")
- else:
- return __import__(import_name)
- return getattr(__import__(module, None, None, [obj]), obj)
- except (ImportError, AttributeError):
- if not silent:
- raise
-
-
+ else:
+ return __import__(import_name)
+ return getattr(__import__(module, None, None, [obj]), obj)
+ except (ImportError, AttributeError):
+ if not silent:
+ raise
+
+
def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO]:
- """Returns a file descriptor for the filename if that file exists,
+ """Returns a file descriptor for the filename if that file exists,
otherwise ``None``.
- """
+ """
if not os.path.isfile(filename):
return None
-
+
return open(filename, mode)
-
+
def object_type_repr(obj: t.Any) -> str:
- """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`).
- """
- if obj is None:
+ """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`).
+ """
+ if obj is None:
return "None"
- elif obj is Ellipsis:
+ elif obj is Ellipsis:
return "Ellipsis"
cls = type(obj)
if cls.__module__ == "builtins":
return f"{cls.__name__} object"
-
+
return f"{cls.__module__}.{cls.__name__} object"
-
+
def pformat(obj: t.Any) -> str:
"""Format an object using :func:`pprint.pformat`."""
@@ -252,7 +252,7 @@ def pformat(obj: t.Any) -> str:
return pformat(obj)
-
+
_http_re = re.compile(
r"""
^
@@ -282,8 +282,8 @@ _http_re = re.compile(
re.IGNORECASE | re.VERBOSE,
)
_email_re = re.compile(r"^\S+@\w[\w.-]*\.\w+$")
-
-
+
+
def urlize(
text: str,
trim_url_limit: t.Optional[int] = None,
@@ -292,11 +292,11 @@ def urlize(
extra_schemes: t.Optional[t.Iterable[str]] = None,
) -> str:
"""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
@@ -321,9 +321,9 @@ def urlize(
The parsing rules were updated. Recognize email addresses with
or without the ``mailto:`` scheme. Validate IP addresses. Ignore
parentheses and brackets in more cases.
- """
+ """
if trim_url_limit is not None:
-
+
def trim_url(x: str) -> str:
if len(x) > trim_url_limit: # type: ignore
return f"{x[:trim_url_limit]}..."
@@ -339,11 +339,11 @@ def urlize(
rel_attr = f' rel="{markupsafe.escape(rel)}"' if rel else ""
target_attr = f' target="{markupsafe.escape(target)}"' if target else ""
- for i, word in enumerate(words):
+ for i, word in enumerate(words):
head, middle, tail = "", word, ""
match = re.match(r"^([(<]|&lt;)+", middle)
- if match:
+ if match:
head = match.group()
middle = middle[match.end() :]
@@ -401,51 +401,51 @@ def urlize(
middle = f'<a href="{middle}"{rel_attr}{target_attr}>{middle}</a>'
words[i] = f"{head}{middle}{tail}"
-
+
return "".join(words)
-
+
def generate_lorem_ipsum(
n: int = 5, html: bool = True, min: int = 20, max: int = 100
) -> str:
- """Generate some lorem ipsum for the template."""
+ """Generate some lorem ipsum for the template."""
from .constants import LOREM_IPSUM_WORDS
- words = LOREM_IPSUM_WORDS.split()
- result = []
-
- for _ in range(n):
- next_capitalized = True
- last_comma = last_fullstop = 0
- word = None
- last = None
- p = []
-
- # each paragraph contains out of 20 to 100 words.
- for idx, _ in enumerate(range(randrange(min, max))):
- while True:
- word = choice(words)
- if word != last:
- last = word
- break
- if next_capitalized:
- word = word.capitalize()
- next_capitalized = False
- # add commas
- if idx - randrange(3, 8) > last_comma:
- last_comma = idx
- last_fullstop += 2
+ words = LOREM_IPSUM_WORDS.split()
+ result = []
+
+ for _ in range(n):
+ next_capitalized = True
+ last_comma = last_fullstop = 0
+ word = None
+ last = None
+ p = []
+
+ # each paragraph contains out of 20 to 100 words.
+ for idx, _ in enumerate(range(randrange(min, max))):
+ while True:
+ word = choice(words)
+ if word != last:
+ last = word
+ break
+ if next_capitalized:
+ word = word.capitalize()
+ next_capitalized = False
+ # add commas
+ if idx - randrange(3, 8) > last_comma:
+ last_comma = idx
+ last_fullstop += 2
word += ","
- # add end of sentences
- if idx - randrange(10, 20) > last_fullstop:
- last_comma = last_fullstop = idx
+ # add end of sentences
+ if idx - randrange(10, 20) > last_fullstop:
+ last_comma = last_fullstop = idx
word += "."
- next_capitalized = True
- p.append(word)
-
- # ensure that the paragraph ends with a dot.
+ next_capitalized = True
+ p.append(word)
+
+ # ensure that the paragraph ends with a dot.
p_str = " ".join(p)
-
+
if p_str.endswith(","):
p_str = p_str[:-1] + "."
elif not p_str.endswith("."):
@@ -453,36 +453,36 @@ def generate_lorem_ipsum(
result.append(p_str)
- if not html:
+ if not html:
return "\n\n".join(result)
return markupsafe.Markup(
"\n".join(f"<p>{markupsafe.escape(x)}</p>" for x in result)
)
-
-
+
+
def url_quote(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str:
"""Quote a string for use in a URL using the given charset.
-
+
:param obj: String or bytes to quote. Other types are converted to
string then encoded to bytes using the given charset.
:param charset: Encode text to bytes using this charset.
:param for_qs: Quote "/" and use "+" for spaces.
- """
+ """
if not isinstance(obj, bytes):
if not isinstance(obj, str):
obj = str(obj)
- obj = obj.encode(charset)
+ obj = obj.encode(charset)
safe = b"" if for_qs else b"/"
rv = quote_from_bytes(obj, safe)
- if for_qs:
+ if for_qs:
rv = rv.replace("%20", "+")
- return rv
-
-
+ return rv
+
+
def unicode_urlencode(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str:
import warnings
@@ -497,221 +497,221 @@ def unicode_urlencode(obj: t.Any, charset: str = "utf-8", for_qs: bool = False)
@abc.MutableMapping.register
class LRUCache:
- """A simple LRU Cache implementation."""
-
- # this is fast for small capacities (something below 1000) but doesn't
- # scale. But as long as it's only used as storage for templates this
- # won't do any harm.
-
+ """A simple LRU Cache implementation."""
+
+ # this is fast for small capacities (something below 1000) but doesn't
+ # scale. But as long as it's only used as storage for templates this
+ # won't do any harm.
+
def __init__(self, capacity: int) -> None:
- self.capacity = capacity
+ self.capacity = capacity
self._mapping: t.Dict[t.Any, t.Any] = {}
self._queue: "te.Deque[t.Any]" = deque()
- self._postinit()
-
+ self._postinit()
+
def _postinit(self) -> None:
- # alias all queue methods for faster lookup
- self._popleft = self._queue.popleft
- self._pop = self._queue.pop
- self._remove = self._queue.remove
- self._wlock = Lock()
- self._append = self._queue.append
-
+ # alias all queue methods for faster lookup
+ self._popleft = self._queue.popleft
+ self._pop = self._queue.pop
+ self._remove = self._queue.remove
+ self._wlock = Lock()
+ self._append = self._queue.append
+
def __getstate__(self) -> t.Mapping[str, t.Any]:
- return {
+ return {
"capacity": self.capacity,
"_mapping": self._mapping,
"_queue": self._queue,
- }
-
+ }
+
def __setstate__(self, d: t.Mapping[str, t.Any]) -> None:
- self.__dict__.update(d)
- self._postinit()
-
+ self.__dict__.update(d)
+ self._postinit()
+
def __getnewargs__(self) -> t.Tuple:
- return (self.capacity,)
-
+ return (self.capacity,)
+
def copy(self) -> "LRUCache":
- """Return a shallow copy of the instance."""
- rv = self.__class__(self.capacity)
- rv._mapping.update(self._mapping)
+ """Return a shallow copy of the instance."""
+ rv = self.__class__(self.capacity)
+ rv._mapping.update(self._mapping)
rv._queue.extend(self._queue)
- return rv
-
+ return rv
+
def get(self, key: t.Any, default: t.Any = None) -> t.Any:
- """Return an item from the cache dict or `default`"""
- try:
- return self[key]
- except KeyError:
- return default
-
+ """Return an item from the cache dict or `default`"""
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
def setdefault(self, key: t.Any, default: t.Any = None) -> t.Any:
- """Set `default` if the key is not in the cache otherwise
- leave unchanged. Return the value of this key.
- """
- try:
+ """Set `default` if the key is not in the cache otherwise
+ leave unchanged. Return the value of this key.
+ """
+ try:
return self[key]
except KeyError:
self[key] = default
return default
-
+
def clear(self) -> None:
- """Clear the cache."""
+ """Clear the cache."""
with self._wlock:
- self._mapping.clear()
- self._queue.clear()
-
+ self._mapping.clear()
+ self._queue.clear()
+
def __contains__(self, key: t.Any) -> bool:
- """Check if a key exists in this cache."""
- return key in self._mapping
-
+ """Check if a key exists in this cache."""
+ return key in self._mapping
+
def __len__(self) -> int:
- """Return the current size of the cache."""
- return len(self._mapping)
-
+ """Return the current size of the cache."""
+ return len(self._mapping)
+
def __repr__(self) -> str:
return f"<{type(self).__name__} {self._mapping!r}>"
-
+
def __getitem__(self, key: t.Any) -> t.Any:
- """Get an item from the cache. Moves the item up so that it has the
- highest priority then.
-
- Raise a `KeyError` if it does not exist.
- """
+ """Get an item from the cache. Moves the item up so that it has the
+ highest priority then.
+
+ Raise a `KeyError` if it does not exist.
+ """
with self._wlock:
- rv = self._mapping[key]
+ rv = self._mapping[key]
- if self._queue[-1] != key:
- try:
- self._remove(key)
- except ValueError:
- # if something removed the key from the container
- # when we read, ignore the ValueError that we would
- # get otherwise.
- pass
+ if self._queue[-1] != key:
+ try:
+ self._remove(key)
+ except ValueError:
+ # if something removed the key from the container
+ # when we read, ignore the ValueError that we would
+ # get otherwise.
+ pass
- self._append(key)
-
- return rv
+ self._append(key)
+ return rv
+
def __setitem__(self, key: t.Any, value: t.Any) -> None:
- """Sets the value for an item. Moves the item up so that it
- has the highest priority then.
- """
+ """Sets the value for an item. Moves the item up so that it
+ has the highest priority then.
+ """
with self._wlock:
- if key in self._mapping:
- self._remove(key)
- elif len(self._mapping) == self.capacity:
- del self._mapping[self._popleft()]
-
- self._append(key)
- self._mapping[key] = value
-
+ if key in self._mapping:
+ self._remove(key)
+ elif len(self._mapping) == self.capacity:
+ del self._mapping[self._popleft()]
+
+ self._append(key)
+ self._mapping[key] = value
+
def __delitem__(self, key: t.Any) -> None:
- """Remove an item from the cache dict.
- Raise a `KeyError` if it does not exist.
- """
+ """Remove an item from the cache dict.
+ Raise a `KeyError` if it does not exist.
+ """
with self._wlock:
- del self._mapping[key]
-
- try:
- self._remove(key)
- except ValueError:
- pass
+ del self._mapping[key]
+ try:
+ self._remove(key)
+ except ValueError:
+ pass
+
def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]:
- """Return a list of items."""
- result = [(key, self._mapping[key]) for key in list(self._queue)]
- result.reverse()
- return result
-
+ """Return a list of items."""
+ result = [(key, self._mapping[key]) for key in list(self._queue)]
+ result.reverse()
+ return result
+
def values(self) -> t.Iterable[t.Any]:
- """Return a list of all values."""
- return [x[1] for x in self.items()]
-
+ """Return a list of all values."""
+ return [x[1] for x in self.items()]
+
def keys(self) -> t.Iterable[t.Any]:
- """Return a list of all keys ordered by most recent usage."""
- return list(self)
-
+ """Return a list of all keys ordered by most recent usage."""
+ return list(self)
+
def __iter__(self) -> t.Iterator[t.Any]:
- return reversed(tuple(self._queue))
-
+ return reversed(tuple(self._queue))
+
def __reversed__(self) -> t.Iterator[t.Any]:
"""Iterate over the keys in the cache dict, oldest items
- coming first.
- """
- return iter(tuple(self._queue))
-
- __copy__ = copy
-
-
+ coming first.
+ """
+ return iter(tuple(self._queue))
+
+ __copy__ = copy
+
+
def select_autoescape(
enabled_extensions: t.Collection[str] = ("html", "htm", "xml"),
disabled_extensions: t.Collection[str] = (),
default_for_string: bool = True,
default: bool = False,
) -> t.Callable[[t.Optional[str]], bool]:
- """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.
-
- .. versionadded:: 2.9
- """
+ """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.
+
+ .. versionadded:: 2.9
+ """
enabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in enabled_extensions)
disabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in disabled_extensions)
def autoescape(template_name: t.Optional[str]) -> bool:
- if template_name is None:
- return default_for_string
- template_name = template_name.lower()
- if template_name.endswith(enabled_patterns):
- return True
- if template_name.endswith(disabled_patterns):
- return False
- return default
-
- return autoescape
-
-
+ if template_name is None:
+ return default_for_string
+ template_name = template_name.lower()
+ if template_name.endswith(enabled_patterns):
+ return True
+ if template_name.endswith(disabled_patterns):
+ return False
+ return default
+
+ return autoescape
+
+
def htmlsafe_json_dumps(
obj: t.Any, dumps: t.Optional[t.Callable[..., str]] = None, **kwargs: t.Any
) -> markupsafe.Markup:
"""Serialize an object to a string of JSON with :func:`json.dumps`,
then replace HTML-unsafe characters with Unicode escapes and mark
the result safe with :class:`~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``
@@ -728,7 +728,7 @@ def htmlsafe_json_dumps(
The ``dumper`` parameter is renamed to ``dumps``.
.. versionadded:: 2.9
- """
+ """
if dumps is None:
dumps = json.dumps
@@ -739,12 +739,12 @@ def htmlsafe_json_dumps(
.replace("&", "\\u0026")
.replace("'", "\\u0027")
)
-
-
+
+
class Cycler:
"""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.
@@ -768,71 +768,71 @@ class Cycler:
"""
def __init__(self, *items: t.Any) -> None:
- if not items:
+ if not items:
raise RuntimeError("at least one item has to be provided")
- self.items = items
+ self.items = items
self.pos = 0
-
+
def reset(self) -> None:
"""Resets the current item to the first item."""
- self.pos = 0
-
- @property
+ self.pos = 0
+
+ @property
def current(self) -> t.Any:
"""Return the current item. Equivalent to the item that will be
returned next time :meth:`next` is called.
"""
- return self.items[self.pos]
-
+ return self.items[self.pos]
+
def next(self) -> t.Any:
"""Return the current item, then advance :attr:`current` to the
next item.
"""
- rv = self.current
- self.pos = (self.pos + 1) % len(self.items)
- return rv
-
- __next__ = next
-
-
+ rv = self.current
+ self.pos = (self.pos + 1) % len(self.items)
+ return rv
+
+ __next__ = next
+
+
class Joiner:
- """A joining helper for templates."""
-
+ """A joining helper for templates."""
+
def __init__(self, sep: str = ", ") -> None:
- self.sep = sep
- self.used = False
-
+ self.sep = sep
+ self.used = False
+
def __call__(self) -> str:
- if not self.used:
- self.used = True
+ if not self.used:
+ self.used = True
return ""
- return self.sep
-
-
+ return self.sep
+
+
class Namespace:
- """A namespace object that can hold arbitrary attributes. It may be
+ """A namespace object that can hold arbitrary attributes. It may be
initialized from a dictionary or with keyword arguments."""
-
+
def __init__(*args: t.Any, **kwargs: t.Any) -> None: # noqa: B902
- self, args = args[0], args[1:]
- self.__attrs = dict(*args, **kwargs)
-
+ self, args = args[0], args[1:]
+ self.__attrs = dict(*args, **kwargs)
+
def __getattribute__(self, name: str) -> t.Any:
# __class__ is needed for the awaitable check in async mode
if name in {"_Namespace__attrs", "__class__"}:
- return object.__getattribute__(self, name)
- try:
- return self.__attrs[name]
- except KeyError:
+ return object.__getattribute__(self, name)
+ try:
+ return self.__attrs[name]
+ except KeyError:
raise AttributeError(name) from None
-
+
def __setitem__(self, name: str, value: t.Any) -> None:
- self.__attrs[name] = value
-
+ self.__attrs[name] = value
+
def __repr__(self) -> str:
return f"<Namespace {self.__attrs!r}>"
-
-
+
+
class Markup(markupsafe.Markup):
def __new__(cls, base="", encoding=None, errors="strict"): # type: ignore
warnings.warn(
@@ -842,8 +842,8 @@ class Markup(markupsafe.Markup):
stacklevel=2,
)
return super().__new__(cls, base, encoding, errors)
-
-
+
+
def escape(s: t.Any) -> str:
warnings.warn(
"'jinja2.escape' is deprecated and will be removed in Jinja"