async def auto_to_list(
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
-) -> t.List["V"]:
+) -> list["V"]:
return [x async for x in auto_aiter(value)]
return False
-def find_undeclared(
- nodes: t.Iterable[nodes.Node], names: t.Iterable[str]
-) -> t.Set[str]:
+def find_undeclared(nodes: t.Iterable[nodes.Node], names: t.Iterable[str]) -> set[str]:
"""Check if the names passed are accessed undeclared. The return value
is a set of all the undeclared names from the sequence of names found.
"""
"""A visitor that collects filter and test calls."""
def __init__(self) -> None:
- self.filters: t.Set[str] = set()
- self.tests: t.Set[str] = set()
+ self.filters: set[str] = set()
+ self.tests: set[str] = set()
def visit_Filter(self, node: nodes.Filter) -> None:
self.generic_visit(node)
def __init__(self, names: t.Iterable[str]) -> None:
self.names = set(names)
- self.undeclared: t.Set[str] = set()
+ self.undeclared: set[str] = set()
def visit_Name(self, node: nodes.Name) -> None:
if node.ctx == "load" and node.name in self.names:
self.optimizer = Optimizer(environment)
# aliases for imports
- self.import_aliases: t.Dict[str, str] = {}
+ self.import_aliases: dict[str, str] = {}
# a registry for all blocks. Because blocks are moved out
# into the global python scope they are registered here
- self.blocks: t.Dict[str, nodes.Block] = {}
+ self.blocks: dict[str, nodes.Block] = {}
# the number of extends statements so far
self.extends_so_far = 0
self.code_lineno = 1
# registry of all filters and tests (global, not block local)
- self.tests: t.Dict[str, str] = {}
- self.filters: t.Dict[str, str] = {}
+ self.tests: dict[str, str] = {}
+ self.filters: dict[str, str] = {}
# the debug information
- self.debug_info: t.List[t.Tuple[int, int]] = []
+ self.debug_info: list[tuple[int, int]] = []
self._write_debug_info: t.Optional[int] = None
# the number of new lines before the next write()
self._indentation = 0
# Tracks toplevel assignments
- self._assign_stack: t.List[t.Set[str]] = []
+ self._assign_stack: list[set[str]] = []
# Tracks parameter definition blocks
- self._param_def_block: t.List[t.Set[str]] = []
+ self._param_def_block: list[set[str]] = []
# Tracks the current context.
self._context_reference_stack = ["context"]
def macro_body(
self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame
- ) -> t.Tuple[Frame, MacroRef]:
+ ) -> tuple[Frame, MacroRef]:
"""Dump the function def of a macro or call block."""
frame = frame.inner()
frame.symbols.analyze_node(node)
self.indent()
finalize = self._make_finalize()
- body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = []
+ body: list[t.Union[list[t.Any], nodes.Expr]] = []
# Evaluate constants at compile time if possible. Each item in
# body will be either a list of static data or a node to be
# it is only valid if it references a Namespace object. Emit a check for
# that for each ref here, before assignment code is emitted. This can't
# be done in visit_NSRef as the ref could be in the middle of a tuple.
- seen_refs: t.Set[str] = set()
+ seen_refs: set[str] = set()
for nsref in node.find_all(nodes.NSRef):
if nsref.name in seen_refs:
return sys.exc_info()[2].tb_next # type: ignore
-def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]:
+def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> dict[str, t.Any]:
"""Based on the runtime locals, get the context that would be
available at that point in the template.
"""
ctx: t.Optional[Context] = real_locals.get("context")
if ctx is not None:
- data: t.Dict[str, t.Any] = ctx.get_all().copy()
+ data: dict[str, t.Any] = ctx.get_all().copy()
else:
data = {}
# rather than pushing a context. Local variables follow the scheme
# l_depth_name. Find the highest-depth local that has a value for
# each name.
- local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {}
+ local_overrides: dict[str, tuple[int, t.Any]] = {}
for name, value in real_locals.items():
if not name.startswith("l_") or value is missing:
}
# default policies
-DEFAULT_POLICIES: t.Dict[str, t.Any] = {
+DEFAULT_POLICIES: dict[str, t.Any] = {
"compiler.ascii_str": True,
"urlize.rel": "noopener",
"urlize.target": None,
# for direct template usage we have up to ten living environments
@lru_cache(maxsize=10)
-def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound:
+def get_spontaneous_environment(cls: type[_env_bound], *args: t.Any) -> _env_bound:
"""Return a new spontaneous environment. A spontaneous environment
is used for templates created directly rather than through an
existing environment.
def create_cache(
size: int,
-) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[BaseLoader]", str], "Template"]]:
+) -> t.Optional[t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]]:
"""Return the cache class for the given size."""
if size == 0:
return None
def copy_cache(
cache: t.Optional[
- t.MutableMapping[t.Tuple["weakref.ref[BaseLoader]", str], "Template"]
+ t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]
],
-) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[BaseLoader]", str], "Template"]]:
+) -> t.Optional[t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]]:
"""Create an empty copy of the given cache."""
if cache is None:
return None
def load_extensions(
environment: "Environment",
- extensions: t.Sequence[t.Union[str, t.Type["Extension"]]],
-) -> t.Dict[str, "Extension"]:
+ extensions: t.Sequence[t.Union[str, type["Extension"]]],
+) -> dict[str, "Extension"]:
"""Load the extensions from the list and bind it to the environment.
Returns a dict of instantiated extensions.
"""
for extension in extensions:
if isinstance(extension, str):
- extension = t.cast(t.Type["Extension"], import_string(extension))
+ extension = t.cast(type["Extension"], import_string(extension))
result[extension.identifier] = extension(environment)
def _environment_config_check(environment: _env_bound) -> _env_bound:
"""Perform a sanity check on the environment."""
- assert issubclass(
- environment.undefined, Undefined
- ), "'undefined' must be a subclass of 'jinja2.Undefined'."
+ assert issubclass(environment.undefined, Undefined), (
+ "'undefined' must be a subclass of 'jinja2.Undefined'."
+ )
assert (
environment.block_start_string
!= environment.variable_start_string
#: the class that is used for code generation. See
#: :class:`~jinja2.compiler.CodeGenerator` for more information.
- code_generator_class: t.Type["CodeGenerator"] = CodeGenerator
+ code_generator_class: type["CodeGenerator"] = CodeGenerator
concat = "".join
#: the context class that is used for templates. See
#: :class:`~jinja2.runtime.Context` for more information.
- context_class: t.Type[Context] = Context
+ context_class: type[Context] = Context
- template_class: t.Type["Template"]
+ template_class: type["Template"]
def __init__(
self,
lstrip_blocks: bool = LSTRIP_BLOCKS,
newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE,
keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE,
- extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (),
+ extensions: t.Sequence[t.Union[str, type["Extension"]]] = (),
optimized: bool = True,
- undefined: t.Type[Undefined] = Undefined,
+ undefined: type[Undefined] = Undefined,
finalize: t.Optional[t.Callable[..., t.Any]] = None,
autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False,
loader: t.Optional["BaseLoader"] = None,
self.keep_trailing_newline = keep_trailing_newline
# runtime information
- self.undefined: t.Type[Undefined] = undefined
+ self.undefined: type[Undefined] = undefined
self.optimized = optimized
self.finalize = finalize
self.autoescape = autoescape
self.is_async = enable_async
_environment_config_check(self)
- def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None:
+ def add_extension(self, extension: t.Union[str, type["Extension"]]) -> None:
"""Adds an extension after the environment was created.
.. versionadded:: 2.5
lstrip_blocks: bool = missing,
newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing,
keep_trailing_newline: bool = missing,
- extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing,
+ extensions: t.Sequence[t.Union[str, type["Extension"]]] = missing,
optimized: bool = missing,
- undefined: t.Type[Undefined] = missing,
+ undefined: type[Undefined] = missing,
finalize: t.Optional[t.Callable[..., t.Any]] = missing,
autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing,
loader: t.Optional["BaseLoader"] = missing,
source: str,
name: t.Optional[str] = None,
filename: t.Optional[str] = None,
- ) -> t.Iterator[t.Tuple[int, str, str]]:
+ ) -> t.Iterator[tuple[int, str, str]]:
"""Lex the given sourcecode and return a generator that yields
tokens as tuples in the form ``(lineno, token_type, value)``.
This can be useful for :ref:`extension development <writing-extensions>`
stream = ext.filter_stream(stream) # type: ignore
if not isinstance(stream, TokenStream):
- stream = TokenStream(stream, name, filename) # type: ignore[unreachable]
+ stream = TokenStream(stream, name, filename)
return stream
self,
extensions: t.Optional[t.Collection[str]] = None,
filter_func: t.Optional[t.Callable[[str], bool]] = None,
- ) -> t.List[str]:
+ ) -> list[str]:
"""Returns a list of templates for this environment. This requires
that the loader supports the loader's
:meth:`~BaseLoader.list_templates` method.
@internalcode
def get_or_select_template(
self,
- template_name_or_list: t.Union[
- str, "Template", t.List[t.Union[str, "Template"]]
- ],
+ template_name_or_list: t.Union[str, "Template", list[t.Union[str, "Template"]]],
parent: t.Optional[str] = None,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
) -> "Template":
self,
source: t.Union[str, nodes.Template],
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
- template_class: t.Optional[t.Type["Template"]] = None,
+ template_class: t.Optional[type["Template"]] = None,
) -> "Template":
"""Load a template from a source string without using
:attr:`loader`.
#: Type of environment to create when creating a template directly
#: rather than through an existing environment.
- environment_class: t.Type[Environment] = Environment
+ environment_class: type[Environment] = Environment
environment: Environment
globals: t.MutableMapping[str, t.Any]
name: t.Optional[str]
filename: t.Optional[str]
- blocks: t.Dict[str, t.Callable[[Context], t.Iterator[str]]]
+ blocks: dict[str, t.Callable[[Context], t.Iterator[str]]]
root_render_func: t.Callable[[Context], t.Iterator[str]]
_module: t.Optional["TemplateModule"]
_debug_info: str
lstrip_blocks: bool = LSTRIP_BLOCKS,
newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE,
keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE,
- extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (),
+ extensions: t.Sequence[t.Union[str, type["Extension"]]] = (),
optimized: bool = True,
- undefined: t.Type[Undefined] = Undefined,
+ undefined: type[Undefined] = Undefined,
finalize: t.Optional[t.Callable[..., t.Any]] = None,
autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False,
enable_async: bool = False,
if self.environment.is_async:
import asyncio
- async def to_list() -> t.List[str]:
+ async def to_list() -> list[str]:
return [x async for x in self.generate_async(*args, **kwargs)]
yield from asyncio.run(to_list())
def new_context(
self,
- vars: t.Optional[t.Dict[str, t.Any]] = None,
+ vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> Context:
def make_module(
self,
- vars: t.Optional[t.Dict[str, t.Any]] = None,
+ vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> "TemplateModule":
async def make_module_async(
self,
- vars: t.Optional[t.Dict[str, t.Any]] = None,
+ vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> "TemplateModule":
return self._uptodate()
@property
- def debug_info(self) -> t.List[t.Tuple[int, int]]:
+ def debug_info(self) -> list[tuple[int, int]]:
"""The debug info mapping."""
if self._debug_info:
return [
self.buffered = False
def _buffered_generator(self, size: int) -> t.Iterator[str]:
- buf: t.List[str] = []
+ buf: list[str] = []
c_size = 0
push = buf.append
# I18N functions available in Jinja templates. If the I18N library
# provides ugettext, it will be assigned to gettext.
-GETTEXT_FUNCTIONS: t.Tuple[str, ...] = (
+GETTEXT_FUNCTIONS: tuple[str, ...] = (
"_",
"gettext",
"ngettext",
cls.identifier = f"{cls.__module__}.{cls.__name__}"
#: if this extension parses this is the list of tags it's listening to.
- tags: t.Set[str] = set()
+ tags: set[str] = set()
#: the priority of that extension. This is especially useful for
#: extensions that preprocess values. A lower value means higher
"""
return stream
- def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]:
+ def parse(self, parser: "Parser") -> t.Union[nodes.Node, list[nodes.Node]]:
"""If any of the :attr:`tags` matched this method is called with the
parser as first argument. The token the parser stream is pointing at
is the name token that matched. This method has to return one or a
def call_method(
self,
name: str,
- args: t.Optional[t.List[nodes.Expr]] = None,
- kwargs: t.Optional[t.List[nodes.Keyword]] = None,
+ args: t.Optional[list[nodes.Expr]] = None,
+ kwargs: t.Optional[list[nodes.Keyword]] = None,
dyn_args: t.Optional[nodes.Expr] = None,
dyn_kwargs: t.Optional[nodes.Expr] = None,
lineno: t.Optional[int] = None,
source: t.Union[str, nodes.Template],
gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS,
) -> t.Iterator[
- t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]]
+ tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]]]
]:
if isinstance(source, str):
source = self.environment.parse(source)
return extract_from_ast(source, gettext_functions)
- def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]:
+ def parse(self, parser: "Parser") -> t.Union[nodes.Node, list[nodes.Node]]:
"""Parse a translatable tag."""
lineno = next(parser.stream).lineno
plural_expr: t.Optional[nodes.Expr] = None
plural_expr_assignment: t.Optional[nodes.Assign] = None
num_called_num = False
- variables: t.Dict[str, nodes.Expr] = {}
+ variables: dict[str, nodes.Expr] = {}
trimmed = None
while parser.stream.current.type != "block_end":
if variables:
def _parse_block(
self, parser: "Parser", allow_pluralize: bool
- ) -> t.Tuple[t.List[str], str]:
+ ) -> tuple[list[str], str]:
"""Parse until the next block tag with a given name."""
referenced = []
buf = []
singular: str,
plural: t.Optional[str],
context: t.Optional[str],
- variables: t.Dict[str, nodes.Expr],
+ variables: dict[str, nodes.Expr],
plural_expr: t.Optional[nodes.Expr],
vars_referenced: bool,
num_called_num: bool,
plural = plural.replace("%%", "%")
func_name = "gettext"
- func_args: t.List[nodes.Expr] = [nodes.Const(singular)]
+ func_args: list[nodes.Expr] = [nodes.Const(singular)]
if context is not None:
func_args.insert(0, nodes.Const(context))
ast: nodes.Template,
gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS,
babel_style: bool = True,
-) -> t.Iterator[
- t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]]
-]:
+) -> t.Iterator[tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]]]]:
"""Extract localizable strings from the given template node. Per
default this function returns matches in babel style that means non string
parameters as well as keyword arguments are returned as `None`. This
to extract any comments. For comment support you have to use the babel
extraction interface or extract comments yourself.
"""
- out: t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]
+ out: t.Union[t.Optional[str], tuple[t.Optional[str], ...]]
for node in ast.find_all(nodes.Call):
if (
):
continue
- strings: t.List[t.Optional[str]] = []
+ strings: list[t.Optional[str]] = []
for arg in node.args:
if isinstance(arg, nodes.Const) and isinstance(arg.value, str):
"""
def __init__(
- self, tokens: t.Sequence[t.Tuple[int, str, str]], comment_tags: t.Sequence[str]
+ self, tokens: t.Sequence[tuple[int, str, str]], comment_tags: t.Sequence[str]
) -> None:
self.tokens = tokens
self.comment_tags = comment_tags
self.offset = 0
self.last_lineno = 0
- def find_backwards(self, offset: int) -> t.List[str]:
+ def find_backwards(self, offset: int) -> list[str]:
try:
for _, token_type, token_value in reversed(
self.tokens[self.offset : offset]
finally:
self.offset = offset
- def find_comments(self, lineno: int) -> t.List[str]:
+ def find_comments(self, lineno: int) -> list[str]:
if not self.comment_tags or self.last_lineno > lineno:
return []
for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]):
fileobj: t.BinaryIO,
keywords: t.Sequence[str],
comment_tags: t.Sequence[str],
- options: t.Dict[str, t.Any],
+ options: dict[str, t.Any],
) -> t.Iterator[
- t.Tuple[
- int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]], t.List[str]
- ]
+ tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]], list[str]]
]:
"""Babel extraction method for Jinja templates.
:return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
(comments will be empty currently)
"""
- extensions: t.Dict[t.Type[Extension], None] = {}
+ extensions: dict[type[Extension], None] = {}
for extension_name in options.get("extensions", "").split(","):
extension_name = extension_name.strip()
environment: "Environment",
attribute: t.Optional[t.Union[str, int]],
postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None,
-) -> t.Callable[[t.Any], t.List[t.Any]]:
+) -> t.Callable[[t.Any], list[t.Any]]:
"""Returns a callable that looks up the given comma separated
attributes from a passed object with the rules of the environment.
Dots are allowed to access attributes of each attribute. Integer
parts = [_prepare_attribute_parts(item) for item in split]
- def attrgetter(item: t.Any) -> t.List[t.Any]:
+ def attrgetter(item: t.Any) -> list[t.Any]:
items = [None] * len(parts)
for i, attribute_part in enumerate(parts):
def _prepare_attribute_parts(
attr: t.Optional[t.Union[str, int]],
-) -> t.List[t.Union[str, int]]:
+) -> list[t.Union[str, int]]:
if attr is None:
return []
def do_urlencode(
- value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[t.Tuple[str, t.Any]]],
+ value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[tuple[str, t.Any]]],
) -> str:
"""Quote data for use in a URL path or query using UTF-8.
return url_quote(value)
if isinstance(value, dict):
- items: t.Iterable[t.Tuple[str, t.Any]] = value.items()
+ items: t.Iterable[tuple[str, t.Any]] = value.items()
else:
items = value # type: ignore
return soft_str(s).lower()
-def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]:
+def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[tuple[K, V]]:
"""Return an iterator over the ``(key, value)`` items of a mapping.
``x|items`` is the same as ``x.items()``, except if ``x`` is
case_sensitive: bool = False,
by: 'te.Literal["key", "value"]' = "key",
reverse: bool = False,
-) -> t.List[t.Tuple[K, V]]:
+) -> list[tuple[K, V]]:
"""Sort a dict and yield (key, value) pairs. Python dicts may not
be in the order you want to display them in, so sort them first.
else:
raise FilterArgumentError('You can only sort by either "key" or "value"')
- def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any:
+ def sort_func(item: tuple[t.Any, t.Any]) -> t.Any:
value = item[pos]
if not case_sensitive:
reverse: bool = False,
case_sensitive: bool = False,
attribute: t.Optional[t.Union[str, int]] = None,
-) -> "t.List[V]":
+) -> "list[V]":
"""Sort an iterable using Python's :func:`sorted`.
.. sourcecode:: jinja
def sync_do_slice(
value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None
-) -> "t.Iterator[t.List[V]]":
+) -> "t.Iterator[list[V]]":
"""Slice an iterator and return a list of lists containing
those items. Useful if you want to create a div containing
three ul tags that represent columns:
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
slices: int,
fill_with: t.Optional[t.Any] = None,
-) -> "t.Iterator[t.List[V]]":
+) -> "t.Iterator[list[V]]":
return sync_do_slice(await auto_to_list(value), slices, fill_with)
def do_batch(
value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None
-) -> "t.Iterator[t.List[V]]":
+) -> "t.Iterator[list[V]]":
"""
A filter that batches items. It works pretty much like `slice`
just the other way round. It returns a list of lists with the
{%- endfor %}
</table>
"""
- tmp: t.List[V] = []
+ tmp: list[V] = []
for item in value:
if len(tmp) == linecount:
class _GroupTuple(t.NamedTuple):
grouper: t.Any
- list: t.List[t.Any]
+ list: list[t.Any]
# Use the regular tuple repr to hide this subclass if users print
# out the value during debugging.
attribute: t.Union[str, int],
default: t.Optional[t.Any] = None,
case_sensitive: bool = False,
-) -> "t.List[_GroupTuple]":
+) -> "list[_GroupTuple]":
"""Group a sequence of objects by an attribute using Python's
:func:`itertools.groupby`. The attribute can use dot notation for
nested access, like ``"address.city"``. Unlike Python's ``groupby``,
attribute: t.Union[str, int],
default: t.Optional[t.Any] = None,
case_sensitive: bool = False,
-) -> "t.List[_GroupTuple]":
+) -> "list[_GroupTuple]":
expr = make_attrgetter(
environment,
attribute,
return rv
-def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
+def sync_do_list(value: "t.Iterable[V]") -> "list[V]":
"""Convert the value into a list. If it was a string the returned list
will be a list of characters.
"""
@async_variant(sync_do_list) # type: ignore
-async def do_list(value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "t.List[V]":
+async def do_list(value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "list[V]":
return await auto_to_list(value)
def prepare_map(
- context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any]
+ context: "Context", args: tuple[t.Any, ...], kwargs: dict[str, t.Any]
) -> t.Callable[[t.Any], t.Any]:
if not args and "attribute" in kwargs:
attribute = kwargs.pop("attribute")
def prepare_select_or_reject(
context: "Context",
- args: t.Tuple[t.Any, ...],
- kwargs: t.Dict[str, t.Any],
+ args: tuple[t.Any, ...],
+ kwargs: dict[str, t.Any],
modfunc: t.Callable[[t.Any], t.Any],
lookup_attr: bool,
) -> t.Callable[[t.Any], t.Any]:
def select_or_reject(
context: "Context",
value: "t.Iterable[V]",
- args: t.Tuple[t.Any, ...],
- kwargs: t.Dict[str, t.Any],
+ args: tuple[t.Any, ...],
+ kwargs: dict[str, t.Any],
modfunc: t.Callable[[t.Any], t.Any],
lookup_attr: bool,
) -> "t.Iterator[V]":
async def async_select_or_reject(
context: "Context",
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
- args: t.Tuple[t.Any, ...],
- kwargs: t.Dict[str, t.Any],
+ args: tuple[t.Any, ...],
+ kwargs: dict[str, t.Any],
modfunc: t.Callable[[t.Any], t.Any],
lookup_attr: bool,
) -> "t.AsyncIterator[V]":
self.level: int = level
self.parent = parent
- self.refs: t.Dict[str, str] = {}
- self.loads: t.Dict[str, t.Any] = {}
- self.stores: t.Set[str] = set()
+ self.refs: dict[str, str] = {}
+ self.loads: dict[str, t.Any] = {}
+ self.stores: set[str] = set()
def analyze_node(self, node: nodes.Node, **kwargs: t.Any) -> None:
visitor = RootVisitor(self)
visitor.visit(node, **kwargs)
def _define_ref(
- self, name: str, load: t.Optional[t.Tuple[str, t.Optional[str]]] = None
+ self, name: str, load: t.Optional[tuple[str, t.Optional[str]]] = None
) -> str:
ident = f"l_{self.level}_{name}"
self.refs[name] = ident
self._define_ref(name, load=(VAR_LOAD_RESOLVE, name))
def branch_update(self, branch_symbols: t.Sequence["Symbols"]) -> None:
- stores: t.Set[str] = set()
+ stores: set[str] = set()
for branch in branch_symbols:
stores.update(branch.stores)
continue
self.loads[target] = (VAR_LOAD_RESOLVE, name)
- def dump_stores(self) -> t.Dict[str, str]:
- rv: t.Dict[str, str] = {}
+ def dump_stores(self) -> dict[str, str]:
+ rv: dict[str, str] = {}
node: t.Optional[Symbols] = self
while node is not None:
return rv
- def dump_param_targets(self) -> t.Set[str]:
+ def dump_param_targets(self) -> set[str]:
rv = set()
node: t.Optional[Symbols] = self
# cache for the lexers. Exists in order to be able to have multiple
# environments with the same lexer
-_lexer_cache: t.MutableMapping[t.Tuple, "Lexer"] = LRUCache(50) # type: ignore
+_lexer_cache: t.MutableMapping[tuple, "Lexer"] = LRUCache(50) # type: ignore
# static regular expressions
whitespace_re = re.compile(r"\s+")
return len(newline_re.findall(value))
-def compile_rules(environment: "Environment") -> t.List[t.Tuple[str, str]]:
+def compile_rules(environment: "Environment") -> list[tuple[str, str]]:
"""Compiles all the rules from the environment into a list of rules."""
e = re.escape
rules = [
"""
def __init__(
- self, message: str, cls: t.Type[TemplateSyntaxError] = TemplateSyntaxError
+ self, message: str, cls: type[TemplateSyntaxError] = TemplateSyntaxError
) -> None:
self.message = message
self.error_class = cls
filename: t.Optional[str],
):
self._iter = iter(generator)
- self._pushed: te.Deque[Token] = deque()
+ self._pushed: deque[Token] = deque()
self.name = name
self.filename = filename
self.closed = False
class _Rule(t.NamedTuple):
pattern: t.Pattern[str]
- tokens: t.Union[str, t.Tuple[str, ...], t.Tuple[Failure]]
+ tokens: t.Union[str, tuple[str, ...], tuple[Failure]]
command: t.Optional[str]
return re.compile(x, re.M | re.S)
# lexing rules for tags
- tag_rules: t.List[_Rule] = [
+ tag_rules: list[_Rule] = [
_Rule(whitespace_re, TOKEN_WHITESPACE, None),
_Rule(float_re, TOKEN_FLOAT, None),
_Rule(integer_re, TOKEN_INTEGER, None),
)
# global lexing rules
- self.rules: t.Dict[str, t.List[_Rule]] = {
+ self.rules: dict[str, list[_Rule]] = {
"root": [
# directives
_Rule(
def wrap(
self,
- stream: t.Iterable[t.Tuple[int, str, str]],
+ stream: t.Iterable[tuple[int, str, str]],
name: t.Optional[str] = None,
filename: t.Optional[str] = None,
) -> t.Iterator[Token]:
name: t.Optional[str],
filename: t.Optional[str] = None,
state: t.Optional[str] = None,
- ) -> t.Iterator[t.Tuple[int, str, str]]:
+ ) -> t.Iterator[tuple[int, str, str]]:
"""This method tokenizes the text and returns the tokens in a
generator. Use this method if you just want to tokenize a template.
statetokens = self.rules[stack[-1]]
source_length = len(source)
- balancing_stack: t.List[str] = []
+ balancing_stack: list[str] = []
newlines_stripped = 0
line_starting = True
from .environment import Template
-def split_template_path(template: str) -> t.List[str]:
+def split_template_path(template: str) -> list[str]:
"""Split a path into segments and perform a sanity check. If it detects
'..' in the path it will raise a `TemplateNotFound` error.
"""
def get_source(
self, environment: "Environment", template: str
- ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+ ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
"""Get the template source, filename and reload helper for a template.
It's passed the environment and template name and has to return a
tuple in the form ``(source, filename, uptodate)`` or raise a
)
raise TemplateNotFound(template)
- def list_templates(self) -> t.List[str]:
+ def list_templates(self) -> list[str]:
"""Iterates over all templates. If the loader does not support that
it should raise a :exc:`TypeError` which is the default behavior.
"""
def get_source(
self, environment: "Environment", template: str
- ) -> t.Tuple[str, str, t.Callable[[], bool]]:
+ ) -> tuple[str, str, t.Callable[[], bool]]:
pieces = split_template_path(template)
for searchpath in self.searchpath:
# Use normpath to convert Windows altsep to sep.
return contents, os.path.normpath(filename), uptodate
- def list_templates(self) -> t.List[str]:
+ def list_templates(self) -> list[str]:
found = set()
for searchpath in self.searchpath:
walk_dir = os.walk(searchpath, followlinks=self.followlinks)
if sys.version_info >= (3, 13):
- def _get_zipimporter_files(z: t.Any) -> t.Dict[str, object]:
+ def _get_zipimporter_files(z: t.Any) -> dict[str, object]:
try:
get_files = z._get_files
except AttributeError as e:
raise TypeError(
- "This zip import does not have the required"
- " metadata to list templates."
+ "This zip import does not have the required metadata to list templates."
) from e
return get_files()
+
else:
- def _get_zipimporter_files(z: t.Any) -> t.Dict[str, object]:
+ def _get_zipimporter_files(z: t.Any) -> dict[str, object]:
try:
files = z._files
except AttributeError as e:
raise TypeError(
- "This zip import does not have the required"
- " metadata to list templates."
+ "This zip import does not have the required metadata to list templates."
) from e
return files # type: ignore[no-any-return]
pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore
template_root = os.path.join(pkgdir, package_path).rstrip(os.sep)
else:
- roots: t.List[str] = []
+ roots: list[str] = []
# One element for regular packages, multiple for namespace
# packages, or None for single module file.
def get_source(
self, environment: "Environment", template: str
- ) -> t.Tuple[str, str, t.Optional[t.Callable[[], bool]]]:
+ ) -> tuple[str, str, t.Optional[t.Callable[[], bool]]]:
# Use posixpath even on Windows to avoid "drive:" or UNC
# segments breaking out of the search directory. Use normpath to
# convert Windows altsep to sep.
return source.decode(self.encoding), p, up_to_date
- def list_templates(self) -> t.List[str]:
- results: t.List[str] = []
+ def list_templates(self) -> list[str]:
+ results: list[str] = []
if self._archive is None:
# Package is a directory.
def get_source(
self, environment: "Environment", template: str
- ) -> t.Tuple[str, None, t.Callable[[], bool]]:
+ ) -> tuple[str, None, t.Callable[[], bool]]:
if template in self.mapping:
source = self.mapping[template]
return source, None, lambda: source == self.mapping.get(template)
raise TemplateNotFound(template)
- def list_templates(self) -> t.List[str]:
+ def list_templates(self) -> list[str]:
return sorted(self.mapping)
[str],
t.Optional[
t.Union[
- str, t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]
+ str, tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]
]
],
],
def get_source(
self, environment: "Environment", template: str
- ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+ ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
rv = self.load_func(template)
if rv is None:
self.mapping = mapping
self.delimiter = delimiter
- def get_loader(self, template: str) -> t.Tuple[BaseLoader, str]:
+ def get_loader(self, template: str) -> tuple[BaseLoader, str]:
try:
prefix, name = template.split(self.delimiter, 1)
loader = self.mapping[prefix]
def get_source(
self, environment: "Environment", template: str
- ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+ ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
loader, name = self.get_loader(template)
try:
return loader.get_source(environment, name)
# (the one that includes the prefix)
raise TemplateNotFound(name) from e
- def list_templates(self) -> t.List[str]:
+ def list_templates(self) -> list[str]:
result = []
for prefix, loader in self.mapping.items():
for template in loader.list_templates():
def get_source(
self, environment: "Environment", template: str
- ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+ ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
for loader in self.loaders:
try:
return loader.get_source(environment, template)
pass
raise TemplateNotFound(name)
- def list_templates(self) -> t.List[str]:
+ def list_templates(self) -> list[str]:
found = set()
for loader in self.loaders:
found.update(loader.list_templates())
def __init__(self, environment: "Environment") -> None:
super().__init__(environment, "<introspection>", "<introspection>")
- self.undeclared_identifiers: t.Set[str] = set()
+ self.undeclared_identifiers: set[str] = set()
def write(self, x: str) -> None:
"""Don't write."""
self.undeclared_identifiers.add(param)
-def find_undeclared_variables(ast: nodes.Template) -> t.Set[str]:
+def find_undeclared_variables(ast: nodes.Template) -> set[str]:
"""Returns a set of all variables in the AST that will be looked up from
the context at runtime. Because at compile time it's not known which
variables will be used depending on the path the execution takes at
_NodeBound = t.TypeVar("_NodeBound", bound="Node")
-_binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
+_binop_to_func: dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"*": operator.mul,
"/": operator.truediv,
"//": operator.floordiv,
"-": operator.sub,
}
-_uaop_to_func: t.Dict[str, t.Callable[[t.Any], t.Any]] = {
+_uaop_to_func: dict[str, t.Callable[[t.Any], t.Any]] = {
"not": operator.not_,
"+": operator.pos,
"-": operator.neg,
}
-_cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
+_cmpop_to_func: dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"eq": operator.eq,
"ne": operator.ne,
"gt": operator.gt,
def __new__(mcs, name, bases, d): # type: ignore
for attr in "fields", "attributes":
- storage: t.List[t.Tuple[str, ...]] = []
+ storage: list[tuple[str, ...]] = []
storage.extend(getattr(bases[0] if bases else object, attr, ()))
storage.extend(d.get(attr, ()))
assert len(bases) <= 1, "multiple inheritance not allowed"
all nodes automatically.
"""
- fields: t.Tuple[str, ...] = ()
- attributes: t.Tuple[str, ...] = ("lineno", "environment")
+ fields: tuple[str, ...] = ()
+ attributes: tuple[str, ...] = ("lineno", "environment")
abstract = True
lineno: int
self,
exclude: t.Optional[t.Container[str]] = None,
only: t.Optional[t.Container[str]] = None,
- ) -> t.Iterator[t.Tuple[str, t.Any]]:
+ ) -> t.Iterator[tuple[str, t.Any]]:
"""This method iterates over all fields that are defined and yields
``(key, value)`` tuples. Per default all fields are returned, but
it's possible to limit that to some fields by providing the `only`
elif isinstance(item, Node):
yield item
- def find(self, node_type: t.Type[_NodeBound]) -> t.Optional[_NodeBound]:
+ def find(self, node_type: type[_NodeBound]) -> t.Optional[_NodeBound]:
"""Find the first node of a given type. If no such node exists the
return value is `None`.
"""
return None
def find_all(
- self, node_type: t.Union[t.Type[_NodeBound], t.Tuple[t.Type[_NodeBound], ...]]
+ self, node_type: t.Union[type[_NodeBound], tuple[type[_NodeBound], ...]]
) -> t.Iterator[_NodeBound]:
"""Find all the nodes of a given type. If the type is a tuple,
the check is performed for any of the tuple items.
_dump(value)
buf.append(")")
- buf: t.List[str] = []
+ buf: list[str] = []
_dump(self)
return "".join(buf)
"""
fields = ("body",)
- body: t.List[Node]
+ body: list[Node]
class Output(Stmt):
"""
fields = ("nodes",)
- nodes: t.List["Expr"]
+ nodes: list["Expr"]
class Extends(Stmt):
fields = ("target", "iter", "body", "else_", "test", "recursive")
target: Node
iter: Node
- body: t.List[Node]
- else_: t.List[Node]
+ body: list[Node]
+ else_: list[Node]
test: t.Optional[Node]
recursive: bool
fields = ("test", "body", "elif_", "else_")
test: Node
- body: t.List[Node]
- elif_: t.List["If"]
- else_: t.List[Node]
+ body: list[Node]
+ elif_: list["If"]
+ else_: list[Node]
class Macro(Stmt):
fields = ("name", "args", "defaults", "body")
name: str
- args: t.List["Name"]
- defaults: t.List["Expr"]
- body: t.List[Node]
+ args: list["Name"]
+ defaults: list["Expr"]
+ body: list[Node]
class CallBlock(Stmt):
fields = ("call", "args", "defaults", "body")
call: "Call"
- args: t.List["Name"]
- defaults: t.List["Expr"]
- body: t.List[Node]
+ args: list["Name"]
+ defaults: list["Expr"]
+ body: list[Node]
class FilterBlock(Stmt):
"""Node for filter sections."""
fields = ("body", "filter")
- body: t.List[Node]
+ body: list[Node]
filter: "Filter"
"""
fields = ("targets", "values", "body")
- targets: t.List["Expr"]
- values: t.List["Expr"]
- body: t.List[Node]
+ targets: list["Expr"]
+ values: list["Expr"]
+ body: list[Node]
class Block(Stmt):
fields = ("name", "body", "scoped", "required")
name: str
- body: t.List[Node]
+ body: list[Node]
scoped: bool
required: bool
fields = ("template", "names", "with_context")
template: "Expr"
- names: t.List[t.Union[str, t.Tuple[str, str]]]
+ names: list[t.Union[str, tuple[str, str]]]
with_context: bool
fields = ("target", "filter", "body")
target: "Expr"
filter: t.Optional["Filter"]
- body: t.List[Node]
+ body: list[Node]
class Expr(Node):
"""
fields = ("items", "ctx")
- items: t.List[Expr]
+ items: list[Expr]
ctx: str
- def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[t.Any, ...]:
+ def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[t.Any, ...]:
eval_ctx = get_eval_context(self, eval_ctx)
return tuple(x.as_const(eval_ctx) for x in self.items)
"""Any list literal such as ``[1, 2, 3]``"""
fields = ("items",)
- items: t.List[Expr]
+ items: list[Expr]
- def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.List[t.Any]:
+ def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> list[t.Any]:
eval_ctx = get_eval_context(self, eval_ctx)
return [x.as_const(eval_ctx) for x in self.items]
"""
fields = ("items",)
- items: t.List["Pair"]
+ items: list["Pair"]
- def as_const(
- self, eval_ctx: t.Optional[EvalContext] = None
- ) -> t.Dict[t.Any, t.Any]:
+ def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> dict[t.Any, t.Any]:
eval_ctx = get_eval_context(self, eval_ctx)
return dict(x.as_const(eval_ctx) for x in self.items)
key: Expr
value: Expr
- def as_const(
- self, eval_ctx: t.Optional[EvalContext] = None
- ) -> t.Tuple[t.Any, t.Any]:
+ def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[t.Any, t.Any]:
eval_ctx = get_eval_context(self, eval_ctx)
return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
key: str
value: Expr
- def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[str, t.Any]:
+ def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[str, t.Any]:
eval_ctx = get_eval_context(self, eval_ctx)
return self.key, self.value.as_const(eval_ctx)
def args_as_const(
node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext]
-) -> t.Tuple[t.List[t.Any], t.Dict[t.Any, t.Any]]:
+) -> tuple[list[t.Any], dict[t.Any, t.Any]]:
args = [x.as_const(eval_ctx) for x in node.args]
kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
node: Expr
name: str
- args: t.List[Expr]
- kwargs: t.List[Pair]
+ args: list[Expr]
+ kwargs: list[Pair]
dyn_args: t.Optional[Expr]
dyn_kwargs: t.Optional[Expr]
abstract = True
fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs")
node: Expr
- args: t.List[Expr]
- kwargs: t.List[Keyword]
+ args: list[Expr]
+ kwargs: list[Keyword]
dyn_args: t.Optional[Expr]
dyn_kwargs: t.Optional[Expr]
"""
fields = ("nodes",)
- nodes: t.List[Expr]
+ nodes: list[Expr]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
eval_ctx = get_eval_context(self, eval_ctx)
fields = ("expr", "ops")
expr: Expr
- ops: t.List["Operand"]
+ ops: list["Operand"]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
eval_ctx = get_eval_context(self, eval_ctx)
"""An artificial scope."""
fields = ("body",)
- body: t.List[Node]
+ body: list[Node]
class OverlayScope(Stmt):
fields = ("context", "body")
context: Expr
- body: t.List[Node]
+ body: list[Node]
class EvalContextModifier(Stmt):
"""
fields = ("options",)
- options: t.List[Keyword]
+ options: list[Keyword]
class ScopedEvalContextModifier(EvalContextModifier):
"""
fields = ("body",)
- body: t.List[Node]
+ body: list[Node]
# make sure nobody creates custom nodes
)
_compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"])
-_math_nodes: t.Dict[str, t.Type[nodes.Expr]] = {
+_math_nodes: dict[str, type[nodes.Expr]] = {
"add": nodes.Add,
"sub": nodes.Sub,
"mul": nodes.Mul,
self.name = name
self.filename = filename
self.closed = False
- self.extensions: t.Dict[
- str, t.Callable[[Parser], t.Union[nodes.Node, t.List[nodes.Node]]]
+ self.extensions: dict[
+ str, t.Callable[[Parser], t.Union[nodes.Node, list[nodes.Node]]]
] = {}
for extension in environment.iter_extensions():
for tag in extension.tags:
self.extensions[tag] = extension.parse
self._last_identifier = 0
- self._tag_stack: t.List[str] = []
- self._end_token_stack: t.List[t.Tuple[str, ...]] = []
+ self._tag_stack: list[str] = []
+ self._end_token_stack: list[tuple[str, ...]] = []
def fail(
self,
msg: str,
lineno: t.Optional[int] = None,
- exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError,
+ exc: type[TemplateSyntaxError] = TemplateSyntaxError,
) -> "te.NoReturn":
"""Convenience method that raises `exc` with the message, passed
line number or last line number as well as the current name and
def _fail_ut_eof(
self,
name: t.Optional[str],
- end_token_stack: t.List[t.Tuple[str, ...]],
+ end_token_stack: list[tuple[str, ...]],
lineno: t.Optional[int],
) -> "te.NoReturn":
- expected: t.Set[str] = set()
+ expected: set[str] = set()
for exprs in end_token_stack:
expected.update(map(describe_token_expr, exprs))
if end_token_stack:
def fail_eof(
self,
- end_tokens: t.Optional[t.Tuple[str, ...]] = None,
+ end_tokens: t.Optional[tuple[str, ...]] = None,
lineno: t.Optional[int] = None,
) -> "te.NoReturn":
"""Like fail_unknown_tag but for end of template situations."""
stack.append(end_tokens)
self._fail_ut_eof(None, stack, lineno)
- def is_tuple_end(
- self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None
- ) -> bool:
+ def is_tuple_end(self, extra_end_rules: t.Optional[tuple[str, ...]] = None) -> bool:
"""Are we at the end of a tuple?"""
if self.stream.current.type in ("variable_end", "block_end", "rparen"):
return True
nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno)
return rv
- def parse_statement(self) -> t.Union[nodes.Node, t.List[nodes.Node]]:
+ def parse_statement(self) -> t.Union[nodes.Node, list[nodes.Node]]:
"""Parse a single statement."""
token = self.stream.current
if token.type != "name":
self._tag_stack.pop()
def parse_statements(
- self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False
- ) -> t.List[nodes.Node]:
+ self, end_tokens: tuple[str, ...], drop_needle: bool = False
+ ) -> list[nodes.Node]:
"""Parse multiple statements into a list until one of the end tokens
is reached. This is used to parse the body of statements as it also
parses template data if appropriate. The parser checks first if the
def parse_with(self) -> nodes.With:
node = nodes.With(lineno=next(self.stream).lineno)
- targets: t.List[nodes.Expr] = []
- values: t.List[nodes.Expr] = []
+ targets: list[nodes.Expr] = []
+ values: list[nodes.Expr] = []
while self.stream.current.type != "block_end":
if targets:
self.stream.expect("comma")
self,
with_tuple: bool = True,
name_only: bool = False,
- extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
+ extra_end_rules: t.Optional[tuple[str, ...]] = None,
with_namespace: bool = False,
) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: ...
self,
with_tuple: bool = True,
name_only: bool = False,
- extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
+ extra_end_rules: t.Optional[tuple[str, ...]] = None,
with_namespace: bool = False,
) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]:
"""Parse an assignment target. As Jinja allows assignments to
self,
simplified: bool = False,
with_condexpr: bool = True,
- extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
+ extra_end_rules: t.Optional[tuple[str, ...]] = None,
explicit_parentheses: bool = False,
with_namespace: bool = False,
) -> t.Union[nodes.Tuple, nodes.Expr]:
def parse() -> nodes.Expr:
return self.parse_expression(with_condexpr=with_condexpr)
- args: t.List[nodes.Expr] = []
+ args: list[nodes.Expr] = []
is_tuple = False
while True:
def parse_list(self) -> nodes.List:
token = self.stream.expect("lbracket")
- items: t.List[nodes.Expr] = []
+ items: list[nodes.Expr] = []
while self.stream.current.type != "rbracket":
if items:
self.stream.expect("comma")
def parse_dict(self) -> nodes.Dict:
token = self.stream.expect("lbrace")
- items: t.List[nodes.Pair] = []
+ items: list[nodes.Pair] = []
while self.stream.current.type != "rbrace":
if items:
self.stream.expect("comma")
arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
return nodes.Getitem(node, arg, "load", lineno=token.lineno)
if token.type == "lbracket":
- args: t.List[nodes.Expr] = []
+ args: list[nodes.Expr] = []
while self.stream.current.type != "rbracket":
if args:
self.stream.expect("comma")
def parse_subscribed(self) -> nodes.Expr:
lineno = self.stream.current.lineno
- args: t.List[t.Optional[nodes.Expr]]
+ args: list[t.Optional[nodes.Expr]]
if self.stream.current.type == "colon":
next(self.stream)
def parse_call_args(
self,
- ) -> t.Tuple[
- t.List[nodes.Expr],
- t.List[nodes.Keyword],
+ ) -> tuple[
+ list[nodes.Expr],
+ list[nodes.Keyword],
t.Union[nodes.Expr, None],
t.Union[nodes.Expr, None],
]:
next(self.stream)
name += "." + self.stream.expect("name").value
dyn_args = dyn_kwargs = None
- kwargs: t.List[nodes.Keyword] = []
+ kwargs: list[nodes.Keyword] = []
if self.stream.current.type == "lparen":
args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
elif self.stream.current.type in {
return node
def subparse(
- self, end_tokens: t.Optional[t.Tuple[str, ...]] = None
- ) -> t.List[nodes.Node]:
- body: t.List[nodes.Node] = []
- data_buffer: t.List[nodes.Node] = []
+ self, end_tokens: t.Optional[tuple[str, ...]] = None
+ ) -> list[nodes.Node]:
+ body: list[nodes.Node] = []
+ data_buffer: list[nodes.Node] = []
add_data = data_buffer.append
if end_tokens is not None:
def new_context(
environment: "Environment",
template_name: t.Optional[str],
- blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
- vars: t.Optional[t.Dict[str, t.Any]] = None,
+ blocks: dict[str, t.Callable[["Context"], t.Iterator[str]]],
+ vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
locals: t.Optional[t.Mapping[str, t.Any]] = None,
def __init__(
self,
environment: "Environment",
- parent: t.Dict[str, t.Any],
+ parent: dict[str, t.Any],
name: t.Optional[str],
- blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
+ blocks: dict[str, t.Callable[["Context"], t.Iterator[str]]],
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
):
self.parent = parent
- self.vars: t.Dict[str, t.Any] = {}
+ self.vars: dict[str, t.Any] = {}
self.environment: Environment = environment
self.eval_ctx = EvalContext(self.environment, name)
- self.exported_vars: t.Set[str] = set()
+ self.exported_vars: set[str] = set()
self.name = name
self.globals_keys = set() if globals is None else set(globals)
return missing
- def get_exported(self) -> t.Dict[str, t.Any]:
+ def get_exported(self) -> dict[str, t.Any]:
"""Get a new dict with the exported variables."""
return {k: self.vars[k] for k in self.exported_vars}
- def get_all(self) -> t.Dict[str, t.Any]:
+ def get_all(self) -> dict[str, t.Any]:
"""Return the complete context as dict including the exported
variables. For optimizations reasons this might not return an
actual copy so be careful with using it.
" StopIteration exception"
)
- def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context":
+ def derived(self, locals: t.Optional[dict[str, t.Any]] = None) -> "Context":
"""Internal helper function to create a derived context. This is
used in situations where the system needs a new context in the same
template that is independent.
self,
name: str,
context: "Context",
- stack: t.List[t.Callable[["Context"], t.Iterator[str]]],
+ stack: list[t.Callable[["Context"], t.Iterator[str]]],
depth: int,
) -> None:
self.name = name
def __init__(
self,
iterable: t.Iterable[V],
- undefined: t.Type["Undefined"],
+ undefined: type["Undefined"],
recurse: t.Optional["LoopRenderFunc"] = None,
depth0: int = 0,
) -> None:
def __iter__(self) -> "LoopContext":
return self
- def __next__(self) -> t.Tuple[t.Any, "LoopContext"]:
+ def __next__(self) -> tuple[t.Any, "LoopContext"]:
if self._after is not missing:
rv = self._after
self._after = missing
def __aiter__(self) -> "AsyncLoopContext":
return self
- async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]:
+ async def __anext__(self) -> tuple[t.Any, "AsyncLoopContext"]:
if self._after is not missing:
rv = self._after
self._after = missing
environment: "Environment",
func: t.Callable[..., str],
name: str,
- arguments: t.List[str],
+ arguments: list[str],
catch_kwargs: bool,
catch_varargs: bool,
caller: bool,
return self._invoke(arguments, autoescape)
- async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
+ async def _async_invoke(self, arguments: list[t.Any], autoescape: bool) -> str:
rv = await self._func(*arguments) # type: ignore
if autoescape:
return rv # type: ignore
- def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
+ def _invoke(self, arguments: list[t.Any], autoescape: bool) -> str:
if self._environment.is_async:
return self._async_invoke(arguments, autoescape) # type: ignore
hint: t.Optional[str] = None,
obj: t.Any = missing,
name: t.Optional[str] = None,
- exc: t.Type[TemplateRuntimeError] = UndefinedError,
+ exc: type[TemplateRuntimeError] = UndefinedError,
) -> None:
self._undefined_hint = hint
self._undefined_obj = obj
def make_logging_undefined(
- logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined
-) -> t.Type[Undefined]:
+ logger: t.Optional["logging.Logger"] = None, base: type[Undefined] = Undefined
+) -> type[Undefined]:
"""Given a logger object this returns a new undefined class that will
log certain failures. It will log iterations and printing. If no
logger is given a default logger is created.
MAX_RANGE = 100000
#: Unsafe function attributes.
-UNSAFE_FUNCTION_ATTRIBUTES: t.Set[str] = set()
+UNSAFE_FUNCTION_ATTRIBUTES: set[str] = set()
#: Unsafe method attributes. Function attributes are unsafe for methods too.
-UNSAFE_METHOD_ATTRIBUTES: t.Set[str] = set()
+UNSAFE_METHOD_ATTRIBUTES: set[str] = set()
#: unsafe generator attributes.
UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"}
#: unsafe attributes on async generators
UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"}
-_mutable_spec: t.Tuple[t.Tuple[t.Type[t.Any], t.FrozenSet[str]], ...] = (
+_mutable_spec: tuple[tuple[type[t.Any], frozenset[str]], ...] = (
(
abc.MutableSet,
frozenset(
#: default callback table for the binary operators. A copy of this is
#: available on each instance of a sandboxed environment as
#: :attr:`binop_table`
- default_binop_table: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
+ default_binop_table: dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
#: default callback table for the unary operators. A copy of this is
#: available on each instance of a sandboxed environment as
#: :attr:`unop_table`
- default_unop_table: t.Dict[str, t.Callable[[t.Any], t.Any]] = {
+ default_unop_table: dict[str, t.Callable[[t.Any], t.Any]] = {
"+": operator.pos,
"-": operator.neg,
}
#: interested in.
#:
#: .. versionadded:: 2.6
- intercepted_binops: t.FrozenSet[str] = frozenset()
+ intercepted_binops: frozenset[str] = frozenset()
#: a set of unary operators that should be intercepted. Each operator
#: that is added to this set (empty by default) is delegated to the
#: interested in.
#:
#: .. versionadded:: 2.6
- intercepted_unops: t.FrozenSet[str] = frozenset()
+ intercepted_unops: frozenset[str] = frozenset()
def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
super().__init__(*args, **kwargs)
if not isinstance(f_self, str):
return None
- str_type: t.Type[str] = type(f_self)
+ str_type: type[str] = type(f_self)
is_format_map = value.__name__ == "format_map"
formatter: SandboxedFormatter
def get_field(
self, field_name: str, args: t.Sequence[t.Any], kwargs: t.Mapping[str, t.Any]
- ) -> t.Tuple[t.Any, str]:
+ ) -> tuple[t.Any, str]:
first, rest = formatter_field_name_split(field_name)
obj = self.get_value(first, args, kwargs)
for is_attr, i in rest:
def __init__(self, capacity: int) -> None:
self.capacity = capacity
- self._mapping: t.Dict[t.Any, t.Any] = {}
- self._queue: te.Deque[t.Any] = deque()
+ self._mapping: dict[t.Any, t.Any] = {}
+ self._queue: deque[t.Any] = deque()
self._postinit()
def _postinit(self) -> None:
self.__dict__.update(d)
self._postinit()
- def __getnewargs__(self) -> t.Tuple[t.Any, ...]:
+ def __getnewargs__(self) -> tuple[t.Any, ...]:
return (self.capacity,)
def copy(self) -> "te.Self":
except ValueError:
pass
- def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]:
+ def items(self) -> t.Iterable[tuple[t.Any, t.Any]]:
"""Return a list of items."""
result = [(key, self._mapping[key]) for key in list(self._queue)]
result.reverse()
setattr(node, field, new_node)
return node
- def visit_list(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.List[Node]:
+ def visit_list(self, node: Node, *args: t.Any, **kwargs: t.Any) -> list[Node]:
"""As transformers may return lists in some places this method
can be used to enforce a list as return value.
"""
def test_reversed_bug(self, test_env_async):
tmpl = test_env_async.from_string(
- "{% for i in items %}{{ i }}"
- "{% if not loop.last %}"
- ",{% endif %}{% endfor %}"
+ "{% for i in items %}{{ i }}{% if not loop.last %},{% endif %}{% endfor %}"
)
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
def test_reversed_bug(self, env):
tmpl = env.from_string(
- "{% for i in items %}{{ i }}"
- "{% if not loop.last %}"
- ",{% endif %}{% endfor %}"
+ "{% for i in items %}{{ i }}{% if not loop.last %},{% endif %}{% endfor %}"
)
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
tb = format_exception(exc_info.type, exc_info.value, exc_info.tb)
m = re.search(expected_tb.strip(), "".join(tb))
- assert (
- m is not None
- ), f"Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}"
+ assert m is not None, (
+ f"Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}"
+ )
def test_runtime_error(self, fs_env):
def test():
newstyle=True,
)
t = env.from_string(
- '{% autoescape ae %}{{ gettext("foo", name='
- '"<test>") }}{% endautoescape %}'
+ '{% autoescape ae %}{{ gettext("foo", name="<test>") }}{% endautoescape %}'
)
assert t.render(ae=True) == "<strong>Wert: <test></strong>"
assert t.render(ae=False) == "<strong>Wert: <test></strong>"
def test_urlize(self, env):
tmpl = env.from_string('{{ "foo example.org bar"|urlize }}')
assert tmpl.render() == (
- 'foo <a href="https://example.org" rel="noopener">' "example.org</a> bar"
+ 'foo <a href="https://example.org" rel="noopener">example.org</a> bar'
)
tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
assert tmpl.render() == (
class TestLexer:
def test_raw1(self, env):
tmpl = env.from_string(
- "{% raw %}foo{% endraw %}|"
- "{%raw%}{{ bar }}|{% baz %}{% endraw %}"
+ "{% raw %}foo{% endraw %}|{%raw%}{{ bar }}|{% baz %}{% endraw %}"
)
assert tmpl.render() == "foo|{{ bar }}|{% baz %}"