fix type/lint/format findings

This commit is contained in:
Adam Englander 2025-05-28 10:06:54 -07:00 committed by David Lord
parent 51dbd8977e
commit a3dce7bb64
No known key found for this signature in database
GPG Key ID: 43368A7AA8CC5926
23 changed files with 262 additions and 283 deletions

View File

@ -95,5 +95,5 @@ def auto_aiter(
async def auto_to_list( async def auto_to_list(
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
) -> t.List["V"]: ) -> list["V"]:
return [x async for x in auto_aiter(value)] return [x async for x in auto_aiter(value)]

View File

@ -139,9 +139,7 @@ def has_safe_repr(value: t.Any) -> bool:
return False return False
def find_undeclared( def find_undeclared(nodes: t.Iterable[nodes.Node], names: t.Iterable[str]) -> set[str]:
nodes: t.Iterable[nodes.Node], names: t.Iterable[str]
) -> t.Set[str]:
"""Check if the names passed are accessed undeclared. The return value """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. is a set of all the undeclared names from the sequence of names found.
""" """
@ -253,8 +251,8 @@ class DependencyFinderVisitor(NodeVisitor):
"""A visitor that collects filter and test calls.""" """A visitor that collects filter and test calls."""
def __init__(self) -> None: def __init__(self) -> None:
self.filters: t.Set[str] = set() self.filters: set[str] = set()
self.tests: t.Set[str] = set() self.tests: set[str] = set()
def visit_Filter(self, node: nodes.Filter) -> None: def visit_Filter(self, node: nodes.Filter) -> None:
self.generic_visit(node) self.generic_visit(node)
@ -276,7 +274,7 @@ class UndeclaredNameVisitor(NodeVisitor):
def __init__(self, names: t.Iterable[str]) -> None: def __init__(self, names: t.Iterable[str]) -> None:
self.names = set(names) self.names = set(names)
self.undeclared: t.Set[str] = set() self.undeclared: set[str] = set()
def visit_Name(self, node: nodes.Name) -> None: def visit_Name(self, node: nodes.Name) -> None:
if node.ctx == "load" and node.name in self.names: if node.ctx == "load" and node.name in self.names:
@ -321,11 +319,11 @@ class CodeGenerator(NodeVisitor):
self.optimizer = Optimizer(environment) self.optimizer = Optimizer(environment)
# aliases for imports # 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 # a registry for all blocks. Because blocks are moved out
# into the global python scope they are registered here # 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 # the number of extends statements so far
self.extends_so_far = 0 self.extends_so_far = 0
@ -339,11 +337,11 @@ class CodeGenerator(NodeVisitor):
self.code_lineno = 1 self.code_lineno = 1
# registry of all filters and tests (global, not block local) # registry of all filters and tests (global, not block local)
self.tests: t.Dict[str, str] = {} self.tests: dict[str, str] = {}
self.filters: t.Dict[str, str] = {} self.filters: dict[str, str] = {}
# the debug information # 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 self._write_debug_info: t.Optional[int] = None
# the number of new lines before the next write() # the number of new lines before the next write()
@ -363,10 +361,10 @@ class CodeGenerator(NodeVisitor):
self._indentation = 0 self._indentation = 0
# Tracks toplevel assignments # Tracks toplevel assignments
self._assign_stack: t.List[t.Set[str]] = [] self._assign_stack: list[set[str]] = []
# Tracks parameter definition blocks # Tracks parameter definition blocks
self._param_def_block: t.List[t.Set[str]] = [] self._param_def_block: list[set[str]] = []
# Tracks the current context. # Tracks the current context.
self._context_reference_stack = ["context"] self._context_reference_stack = ["context"]
@ -613,7 +611,7 @@ class CodeGenerator(NodeVisitor):
def macro_body( def macro_body(
self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame 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.""" """Dump the function def of a macro or call block."""
frame = frame.inner() frame = frame.inner()
frame.symbols.analyze_node(node) frame.symbols.analyze_node(node)
@ -1511,7 +1509,7 @@ class CodeGenerator(NodeVisitor):
self.indent() self.indent()
finalize = self._make_finalize() 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 # Evaluate constants at compile time if possible. Each item in
# body will be either a list of static data or a node to be # body will be either a list of static data or a node to be
@ -1586,7 +1584,7 @@ class CodeGenerator(NodeVisitor):
# it is only valid if it references a Namespace object. Emit a check for # 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 # 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. # 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): for nsref in node.find_all(nodes.NSRef):
if nsref.name in seen_refs: if nsref.name in seen_refs:

View File

@ -128,7 +128,7 @@ def fake_traceback( # type: ignore
return sys.exc_info()[2].tb_next # type: ignore 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 """Based on the runtime locals, get the context that would be
available at that point in the template. available at that point in the template.
""" """
@ -136,7 +136,7 @@ def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any
ctx: t.Optional[Context] = real_locals.get("context") ctx: t.Optional[Context] = real_locals.get("context")
if ctx is not None: 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: else:
data = {} data = {}
@ -144,7 +144,7 @@ def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any
# rather than pushing a context. Local variables follow the scheme # rather than pushing a context. Local variables follow the scheme
# l_depth_name. Find the highest-depth local that has a value for # l_depth_name. Find the highest-depth local that has a value for
# each name. # 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(): for name, value in real_locals.items():
if not name.startswith("l_") or value is missing: if not name.startswith("l_") or value is missing:

View File

@ -36,7 +36,7 @@ DEFAULT_NAMESPACE = {
} }
# default policies # default policies
DEFAULT_POLICIES: t.Dict[str, t.Any] = { DEFAULT_POLICIES: dict[str, t.Any] = {
"compiler.ascii_str": True, "compiler.ascii_str": True,
"urlize.rel": "noopener", "urlize.rel": "noopener",
"urlize.target": None, "urlize.target": None,

View File

@ -66,7 +66,7 @@ _env_bound = t.TypeVar("_env_bound", bound="Environment")
# for direct template usage we have up to ten living environments # for direct template usage we have up to ten living environments
@lru_cache(maxsize=10) @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 """Return a new spontaneous environment. A spontaneous environment
is used for templates created directly rather than through an is used for templates created directly rather than through an
existing environment. existing environment.
@ -81,7 +81,7 @@ def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_b
def create_cache( def create_cache(
size: int, 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.""" """Return the cache class for the given size."""
if size == 0: if size == 0:
return None return None
@ -94,9 +94,9 @@ def create_cache(
def copy_cache( def copy_cache(
cache: t.Optional[ 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.""" """Create an empty copy of the given cache."""
if cache is None: if cache is None:
return None return None
@ -109,8 +109,8 @@ def copy_cache(
def load_extensions( def load_extensions(
environment: "Environment", environment: "Environment",
extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], extensions: t.Sequence[t.Union[str, type["Extension"]]],
) -> t.Dict[str, "Extension"]: ) -> dict[str, "Extension"]:
"""Load the extensions from the list and bind it to the environment. """Load the extensions from the list and bind it to the environment.
Returns a dict of instantiated extensions. Returns a dict of instantiated extensions.
""" """
@ -118,7 +118,7 @@ def load_extensions(
for extension in extensions: for extension in extensions:
if isinstance(extension, str): 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) result[extension.identifier] = extension(environment)
@ -127,9 +127,9 @@ def load_extensions(
def _environment_config_check(environment: _env_bound) -> _env_bound: def _environment_config_check(environment: _env_bound) -> _env_bound:
"""Perform a sanity check on the environment.""" """Perform a sanity check on the environment."""
assert issubclass( assert issubclass(environment.undefined, Undefined), (
environment.undefined, Undefined "'undefined' must be a subclass of 'jinja2.Undefined'."
), "'undefined' must be a subclass of 'jinja2.Undefined'." )
assert ( assert (
environment.block_start_string environment.block_start_string
!= environment.variable_start_string != environment.variable_start_string
@ -283,15 +283,15 @@ class Environment:
#: the class that is used for code generation. See #: the class that is used for code generation. See
#: :class:`~jinja2.compiler.CodeGenerator` for more information. #: :class:`~jinja2.compiler.CodeGenerator` for more information.
code_generator_class: t.Type["CodeGenerator"] = CodeGenerator code_generator_class: type["CodeGenerator"] = CodeGenerator
concat = "".join concat = "".join
#: the context class that is used for templates. See #: the context class that is used for templates. See
#: :class:`~jinja2.runtime.Context` for more information. #: :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__( def __init__(
self, self,
@ -307,9 +307,9 @@ class Environment:
lstrip_blocks: bool = LSTRIP_BLOCKS, lstrip_blocks: bool = LSTRIP_BLOCKS,
newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE,
keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, 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, optimized: bool = True,
undefined: t.Type[Undefined] = Undefined, undefined: type[Undefined] = Undefined,
finalize: t.Optional[t.Callable[..., t.Any]] = None, finalize: t.Optional[t.Callable[..., t.Any]] = None,
autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False,
loader: t.Optional["BaseLoader"] = None, loader: t.Optional["BaseLoader"] = None,
@ -344,7 +344,7 @@ class Environment:
self.keep_trailing_newline = keep_trailing_newline self.keep_trailing_newline = keep_trailing_newline
# runtime information # runtime information
self.undefined: t.Type[Undefined] = undefined self.undefined: type[Undefined] = undefined
self.optimized = optimized self.optimized = optimized
self.finalize = finalize self.finalize = finalize
self.autoescape = autoescape self.autoescape = autoescape
@ -369,7 +369,7 @@ class Environment:
self.is_async = enable_async self.is_async = enable_async
_environment_config_check(self) _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. """Adds an extension after the environment was created.
.. versionadded:: 2.5 .. versionadded:: 2.5
@ -399,9 +399,9 @@ class Environment:
lstrip_blocks: bool = missing, lstrip_blocks: bool = missing,
newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing,
keep_trailing_newline: bool = 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, optimized: bool = missing,
undefined: t.Type[Undefined] = missing, undefined: type[Undefined] = missing,
finalize: t.Optional[t.Callable[..., t.Any]] = missing, finalize: t.Optional[t.Callable[..., t.Any]] = missing,
autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing,
loader: t.Optional["BaseLoader"] = missing, loader: t.Optional["BaseLoader"] = missing,
@ -628,7 +628,7 @@ class Environment:
source: str, source: str,
name: t.Optional[str] = None, name: t.Optional[str] = None,
filename: 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 """Lex the given sourcecode and return a generator that yields
tokens as tuples in the form ``(lineno, token_type, value)``. tokens as tuples in the form ``(lineno, token_type, value)``.
This can be useful for :ref:`extension development <writing-extensions>` This can be useful for :ref:`extension development <writing-extensions>`
@ -677,7 +677,7 @@ class Environment:
stream = ext.filter_stream(stream) # type: ignore stream = ext.filter_stream(stream) # type: ignore
if not isinstance(stream, TokenStream): if not isinstance(stream, TokenStream):
stream = TokenStream(stream, name, filename) # type: ignore[unreachable] stream = TokenStream(stream, name, filename)
return stream return stream
@ -902,7 +902,7 @@ class Environment:
self, self,
extensions: t.Optional[t.Collection[str]] = None, extensions: t.Optional[t.Collection[str]] = None,
filter_func: t.Optional[t.Callable[[str], bool]] = 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 """Returns a list of templates for this environment. This requires
that the loader supports the loader's that the loader supports the loader's
:meth:`~BaseLoader.list_templates` method. :meth:`~BaseLoader.list_templates` method.
@ -1074,9 +1074,7 @@ class Environment:
@internalcode @internalcode
def get_or_select_template( def get_or_select_template(
self, self,
template_name_or_list: t.Union[ template_name_or_list: t.Union[str, "Template", list[t.Union[str, "Template"]]],
str, "Template", t.List[t.Union[str, "Template"]]
],
parent: t.Optional[str] = None, parent: t.Optional[str] = None,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None, globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
) -> "Template": ) -> "Template":
@ -1095,7 +1093,7 @@ class Environment:
self, self,
source: t.Union[str, nodes.Template], source: t.Union[str, nodes.Template],
globals: t.Optional[t.MutableMapping[str, t.Any]] = None, 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": ) -> "Template":
"""Load a template from a source string without using """Load a template from a source string without using
:attr:`loader`. :attr:`loader`.
@ -1154,13 +1152,13 @@ class Template:
#: Type of environment to create when creating a template directly #: Type of environment to create when creating a template directly
#: rather than through an existing environment. #: rather than through an existing environment.
environment_class: t.Type[Environment] = Environment environment_class: type[Environment] = Environment
environment: Environment environment: Environment
globals: t.MutableMapping[str, t.Any] globals: t.MutableMapping[str, t.Any]
name: t.Optional[str] name: t.Optional[str]
filename: 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]] root_render_func: t.Callable[[Context], t.Iterator[str]]
_module: t.Optional["TemplateModule"] _module: t.Optional["TemplateModule"]
_debug_info: str _debug_info: str
@ -1181,9 +1179,9 @@ class Template:
lstrip_blocks: bool = LSTRIP_BLOCKS, lstrip_blocks: bool = LSTRIP_BLOCKS,
newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE,
keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, 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, optimized: bool = True,
undefined: t.Type[Undefined] = Undefined, undefined: type[Undefined] = Undefined,
finalize: t.Optional[t.Callable[..., t.Any]] = None, finalize: t.Optional[t.Callable[..., t.Any]] = None,
autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False,
enable_async: bool = False, enable_async: bool = False,
@ -1336,7 +1334,7 @@ class Template:
if self.environment.is_async: if self.environment.is_async:
import asyncio 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)] return [x async for x in self.generate_async(*args, **kwargs)]
yield from asyncio.run(to_list()) yield from asyncio.run(to_list())
@ -1376,7 +1374,7 @@ class Template:
def new_context( def new_context(
self, self,
vars: t.Optional[t.Dict[str, t.Any]] = None, vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False, shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None, locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> Context: ) -> Context:
@ -1393,7 +1391,7 @@ class Template:
def make_module( def make_module(
self, self,
vars: t.Optional[t.Dict[str, t.Any]] = None, vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False, shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None, locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> "TemplateModule": ) -> "TemplateModule":
@ -1408,7 +1406,7 @@ class Template:
async def make_module_async( async def make_module_async(
self, self,
vars: t.Optional[t.Dict[str, t.Any]] = None, vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False, shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None, locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> "TemplateModule": ) -> "TemplateModule":
@ -1498,7 +1496,7 @@ class Template:
return self._uptodate() return self._uptodate()
@property @property
def debug_info(self) -> t.List[t.Tuple[int, int]]: def debug_info(self) -> list[tuple[int, int]]:
"""The debug info mapping.""" """The debug info mapping."""
if self._debug_info: if self._debug_info:
return [ return [
@ -1636,7 +1634,7 @@ class TemplateStream:
self.buffered = False self.buffered = False
def _buffered_generator(self, size: int) -> t.Iterator[str]: def _buffered_generator(self, size: int) -> t.Iterator[str]:
buf: t.List[str] = [] buf: list[str] = []
c_size = 0 c_size = 0
push = buf.append push = buf.append

View File

@ -42,7 +42,7 @@ if t.TYPE_CHECKING:
# I18N functions available in Jinja templates. If the I18N library # I18N functions available in Jinja templates. If the I18N library
# provides ugettext, it will be assigned to gettext. # provides ugettext, it will be assigned to gettext.
GETTEXT_FUNCTIONS: t.Tuple[str, ...] = ( GETTEXT_FUNCTIONS: tuple[str, ...] = (
"_", "_",
"gettext", "gettext",
"ngettext", "ngettext",
@ -77,7 +77,7 @@ class Extension:
cls.identifier = f"{cls.__module__}.{cls.__name__}" cls.identifier = f"{cls.__module__}.{cls.__name__}"
#: if this extension parses this is the list of tags it's listening to. #: 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 #: the priority of that extension. This is especially useful for
#: extensions that preprocess values. A lower value means higher #: extensions that preprocess values. A lower value means higher
@ -115,7 +115,7 @@ class Extension:
""" """
return stream 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 """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 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 is the name token that matched. This method has to return one or a
@ -138,8 +138,8 @@ class Extension:
def call_method( def call_method(
self, self,
name: str, name: str,
args: t.Optional[t.List[nodes.Expr]] = None, args: t.Optional[list[nodes.Expr]] = None,
kwargs: t.Optional[t.List[nodes.Keyword]] = None, kwargs: t.Optional[list[nodes.Keyword]] = None,
dyn_args: t.Optional[nodes.Expr] = None, dyn_args: t.Optional[nodes.Expr] = None,
dyn_kwargs: t.Optional[nodes.Expr] = None, dyn_kwargs: t.Optional[nodes.Expr] = None,
lineno: t.Optional[int] = None, lineno: t.Optional[int] = None,
@ -330,13 +330,13 @@ class InternationalizationExtension(Extension):
source: t.Union[str, nodes.Template], source: t.Union[str, nodes.Template],
gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS, gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS,
) -> t.Iterator[ ) -> 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): if isinstance(source, str):
source = self.environment.parse(source) source = self.environment.parse(source)
return extract_from_ast(source, gettext_functions) 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.""" """Parse a translatable tag."""
lineno = next(parser.stream).lineno lineno = next(parser.stream).lineno
@ -352,7 +352,7 @@ class InternationalizationExtension(Extension):
plural_expr: t.Optional[nodes.Expr] = None plural_expr: t.Optional[nodes.Expr] = None
plural_expr_assignment: t.Optional[nodes.Assign] = None plural_expr_assignment: t.Optional[nodes.Assign] = None
num_called_num = False num_called_num = False
variables: t.Dict[str, nodes.Expr] = {} variables: dict[str, nodes.Expr] = {}
trimmed = None trimmed = None
while parser.stream.current.type != "block_end": while parser.stream.current.type != "block_end":
if variables: if variables:
@ -463,7 +463,7 @@ class InternationalizationExtension(Extension):
def _parse_block( def _parse_block(
self, parser: "Parser", allow_pluralize: bool 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.""" """Parse until the next block tag with a given name."""
referenced = [] referenced = []
buf = [] buf = []
@ -513,7 +513,7 @@ class InternationalizationExtension(Extension):
singular: str, singular: str,
plural: t.Optional[str], plural: t.Optional[str],
context: t.Optional[str], context: t.Optional[str],
variables: t.Dict[str, nodes.Expr], variables: dict[str, nodes.Expr],
plural_expr: t.Optional[nodes.Expr], plural_expr: t.Optional[nodes.Expr],
vars_referenced: bool, vars_referenced: bool,
num_called_num: bool, num_called_num: bool,
@ -530,7 +530,7 @@ class InternationalizationExtension(Extension):
plural = plural.replace("%%", "%") plural = plural.replace("%%", "%")
func_name = "gettext" 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: if context is not None:
func_args.insert(0, nodes.Const(context)) func_args.insert(0, nodes.Const(context))
@ -640,9 +640,7 @@ def extract_from_ast(
ast: nodes.Template, ast: nodes.Template,
gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS, gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS,
babel_style: bool = True, babel_style: bool = True,
) -> t.Iterator[ ) -> t.Iterator[tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]]]]:
t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]]
]:
"""Extract localizable strings from the given template node. Per """Extract localizable strings from the given template node. Per
default this function returns matches in babel style that means non string default this function returns matches in babel style that means non string
parameters as well as keyword arguments are returned as `None`. This parameters as well as keyword arguments are returned as `None`. This
@ -677,7 +675,7 @@ def extract_from_ast(
to extract any comments. For comment support you have to use the babel to extract any comments. For comment support you have to use the babel
extraction interface or extract comments yourself. 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): for node in ast.find_all(nodes.Call):
if ( if (
@ -686,7 +684,7 @@ def extract_from_ast(
): ):
continue continue
strings: t.List[t.Optional[str]] = [] strings: list[t.Optional[str]] = []
for arg in node.args: for arg in node.args:
if isinstance(arg, nodes.Const) and isinstance(arg.value, str): if isinstance(arg, nodes.Const) and isinstance(arg.value, str):
@ -723,14 +721,14 @@ class _CommentFinder:
""" """
def __init__( 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: ) -> None:
self.tokens = tokens self.tokens = tokens
self.comment_tags = comment_tags self.comment_tags = comment_tags
self.offset = 0 self.offset = 0
self.last_lineno = 0 self.last_lineno = 0
def find_backwards(self, offset: int) -> t.List[str]: def find_backwards(self, offset: int) -> list[str]:
try: try:
for _, token_type, token_value in reversed( for _, token_type, token_value in reversed(
self.tokens[self.offset : offset] self.tokens[self.offset : offset]
@ -746,7 +744,7 @@ class _CommentFinder:
finally: finally:
self.offset = offset 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: if not self.comment_tags or self.last_lineno > lineno:
return [] return []
for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]): for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]):
@ -759,11 +757,9 @@ def babel_extract(
fileobj: t.BinaryIO, fileobj: t.BinaryIO,
keywords: t.Sequence[str], keywords: t.Sequence[str],
comment_tags: t.Sequence[str], comment_tags: t.Sequence[str],
options: t.Dict[str, t.Any], options: dict[str, t.Any],
) -> t.Iterator[ ) -> t.Iterator[
t.Tuple[ tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]], list[str]]
int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]], t.List[str]
]
]: ]:
"""Babel extraction method for Jinja templates. """Babel extraction method for Jinja templates.
@ -792,7 +788,7 @@ def babel_extract(
:return: an iterator over ``(lineno, funcname, message, comments)`` tuples. :return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
(comments will be empty currently) (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(","): for extension_name in options.get("extensions", "").split(","):
extension_name = extension_name.strip() extension_name = extension_name.strip()

View File

@ -87,7 +87,7 @@ def make_multi_attrgetter(
environment: "Environment", environment: "Environment",
attribute: t.Optional[t.Union[str, int]], attribute: t.Optional[t.Union[str, int]],
postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, 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 """Returns a callable that looks up the given comma separated
attributes from a passed object with the rules of the environment. attributes from a passed object with the rules of the environment.
Dots are allowed to access attributes of each attribute. Integer Dots are allowed to access attributes of each attribute. Integer
@ -105,7 +105,7 @@ def make_multi_attrgetter(
parts = [_prepare_attribute_parts(item) for item in split] 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) items = [None] * len(parts)
for i, attribute_part in enumerate(parts): for i, attribute_part in enumerate(parts):
@ -126,7 +126,7 @@ def make_multi_attrgetter(
def _prepare_attribute_parts( def _prepare_attribute_parts(
attr: t.Optional[t.Union[str, int]], attr: t.Optional[t.Union[str, int]],
) -> t.List[t.Union[str, int]]: ) -> list[t.Union[str, int]]:
if attr is None: if attr is None:
return [] return []
@ -145,7 +145,7 @@ def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup:
def do_urlencode( 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: ) -> str:
"""Quote data for use in a URL path or query using UTF-8. """Quote data for use in a URL path or query using UTF-8.
@ -166,7 +166,7 @@ def do_urlencode(
return url_quote(value) return url_quote(value)
if isinstance(value, dict): if isinstance(value, dict):
items: t.Iterable[t.Tuple[str, t.Any]] = value.items() items: t.Iterable[tuple[str, t.Any]] = value.items()
else: else:
items = value # type: ignore items = value # type: ignore
@ -221,7 +221,7 @@ def do_lower(s: str) -> str:
return soft_str(s).lower() 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. """Return an iterator over the ``(key, value)`` items of a mapping.
``x|items`` is the same as ``x.items()``, except if ``x`` is ``x|items`` is the same as ``x.items()``, except if ``x`` is
@ -346,7 +346,7 @@ def do_dictsort(
case_sensitive: bool = False, case_sensitive: bool = False,
by: 'te.Literal["key", "value"]' = "key", by: 'te.Literal["key", "value"]' = "key",
reverse: bool = False, 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 """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. be in the order you want to display them in, so sort them first.
@ -371,7 +371,7 @@ def do_dictsort(
else: else:
raise FilterArgumentError('You can only sort by either "key" or "value"') 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] value = item[pos]
if not case_sensitive: if not case_sensitive:
@ -389,7 +389,7 @@ def do_sort(
reverse: bool = False, reverse: bool = False,
case_sensitive: bool = False, case_sensitive: bool = False,
attribute: t.Optional[t.Union[str, int]] = None, attribute: t.Optional[t.Union[str, int]] = None,
) -> "t.List[V]": ) -> "list[V]":
"""Sort an iterable using Python's :func:`sorted`. """Sort an iterable using Python's :func:`sorted`.
.. sourcecode:: jinja .. sourcecode:: jinja
@ -1058,7 +1058,7 @@ def do_striptags(value: "t.Union[str, HasHTML]") -> str:
def sync_do_slice( def sync_do_slice(
value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None 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 """Slice an iterator and return a list of lists containing
those items. Useful if you want to create a div containing those items. Useful if you want to create a div containing
three ul tags that represent columns: three ul tags that represent columns:
@ -1104,13 +1104,13 @@ async def do_slice(
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
slices: int, slices: int,
fill_with: t.Optional[t.Any] = None, 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) return sync_do_slice(await auto_to_list(value), slices, fill_with)
def do_batch( def do_batch(
value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None 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` A filter that batches items. It works pretty much like `slice`
just the other way round. It returns a list of lists with the just the other way round. It returns a list of lists with the
@ -1129,7 +1129,7 @@ def do_batch(
{%- endfor %} {%- endfor %}
</table> </table>
""" """
tmp: t.List[V] = [] tmp: list[V] = []
for item in value: for item in value:
if len(tmp) == linecount: if len(tmp) == linecount:
@ -1187,7 +1187,7 @@ def do_round(
class _GroupTuple(t.NamedTuple): class _GroupTuple(t.NamedTuple):
grouper: t.Any grouper: t.Any
list: t.List[t.Any] list: list[t.Any]
# Use the regular tuple repr to hide this subclass if users print # Use the regular tuple repr to hide this subclass if users print
# out the value during debugging. # out the value during debugging.
@ -1205,7 +1205,7 @@ def sync_do_groupby(
attribute: t.Union[str, int], attribute: t.Union[str, int],
default: t.Optional[t.Any] = None, default: t.Optional[t.Any] = None,
case_sensitive: bool = False, case_sensitive: bool = False,
) -> "t.List[_GroupTuple]": ) -> "list[_GroupTuple]":
"""Group a sequence of objects by an attribute using Python's """Group a sequence of objects by an attribute using Python's
:func:`itertools.groupby`. The attribute can use dot notation for :func:`itertools.groupby`. The attribute can use dot notation for
nested access, like ``"address.city"``. Unlike Python's ``groupby``, nested access, like ``"address.city"``. Unlike Python's ``groupby``,
@ -1289,7 +1289,7 @@ async def do_groupby(
attribute: t.Union[str, int], attribute: t.Union[str, int],
default: t.Optional[t.Any] = None, default: t.Optional[t.Any] = None,
case_sensitive: bool = False, case_sensitive: bool = False,
) -> "t.List[_GroupTuple]": ) -> "list[_GroupTuple]":
expr = make_attrgetter( expr = make_attrgetter(
environment, environment,
attribute, attribute,
@ -1358,7 +1358,7 @@ async def do_sum(
return rv 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 """Convert the value into a list. If it was a string the returned list
will be a list of characters. will be a list of characters.
""" """
@ -1366,7 +1366,7 @@ def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
@async_variant(sync_do_list) # type: ignore @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) return await auto_to_list(value)
@ -1722,7 +1722,7 @@ def do_tojson(
def prepare_map( 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]: ) -> t.Callable[[t.Any], t.Any]:
if not args and "attribute" in kwargs: if not args and "attribute" in kwargs:
attribute = kwargs.pop("attribute") attribute = kwargs.pop("attribute")
@ -1751,8 +1751,8 @@ def prepare_map(
def prepare_select_or_reject( def prepare_select_or_reject(
context: "Context", context: "Context",
args: t.Tuple[t.Any, ...], args: tuple[t.Any, ...],
kwargs: t.Dict[str, t.Any], kwargs: dict[str, t.Any],
modfunc: t.Callable[[t.Any], t.Any], modfunc: t.Callable[[t.Any], t.Any],
lookup_attr: bool, lookup_attr: bool,
) -> t.Callable[[t.Any], t.Any]: ) -> t.Callable[[t.Any], t.Any]:
@ -1786,8 +1786,8 @@ def prepare_select_or_reject(
def select_or_reject( def select_or_reject(
context: "Context", context: "Context",
value: "t.Iterable[V]", value: "t.Iterable[V]",
args: t.Tuple[t.Any, ...], args: tuple[t.Any, ...],
kwargs: t.Dict[str, t.Any], kwargs: dict[str, t.Any],
modfunc: t.Callable[[t.Any], t.Any], modfunc: t.Callable[[t.Any], t.Any],
lookup_attr: bool, lookup_attr: bool,
) -> "t.Iterator[V]": ) -> "t.Iterator[V]":
@ -1802,8 +1802,8 @@ def select_or_reject(
async def async_select_or_reject( async def async_select_or_reject(
context: "Context", context: "Context",
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
args: t.Tuple[t.Any, ...], args: tuple[t.Any, ...],
kwargs: t.Dict[str, t.Any], kwargs: dict[str, t.Any],
modfunc: t.Callable[[t.Any], t.Any], modfunc: t.Callable[[t.Any], t.Any],
lookup_attr: bool, lookup_attr: bool,
) -> "t.AsyncIterator[V]": ) -> "t.AsyncIterator[V]":

View File

@ -42,16 +42,16 @@ class Symbols:
self.level: int = level self.level: int = level
self.parent = parent self.parent = parent
self.refs: t.Dict[str, str] = {} self.refs: dict[str, str] = {}
self.loads: t.Dict[str, t.Any] = {} self.loads: dict[str, t.Any] = {}
self.stores: t.Set[str] = set() self.stores: set[str] = set()
def analyze_node(self, node: nodes.Node, **kwargs: t.Any) -> None: def analyze_node(self, node: nodes.Node, **kwargs: t.Any) -> None:
visitor = RootVisitor(self) visitor = RootVisitor(self)
visitor.visit(node, **kwargs) visitor.visit(node, **kwargs)
def _define_ref( 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: ) -> str:
ident = f"l_{self.level}_{name}" ident = f"l_{self.level}_{name}"
self.refs[name] = ident self.refs[name] = ident
@ -121,7 +121,7 @@ class Symbols:
self._define_ref(name, load=(VAR_LOAD_RESOLVE, name)) self._define_ref(name, load=(VAR_LOAD_RESOLVE, name))
def branch_update(self, branch_symbols: t.Sequence["Symbols"]) -> None: def branch_update(self, branch_symbols: t.Sequence["Symbols"]) -> None:
stores: t.Set[str] = set() stores: set[str] = set()
for branch in branch_symbols: for branch in branch_symbols:
stores.update(branch.stores) stores.update(branch.stores)
@ -144,8 +144,8 @@ class Symbols:
continue continue
self.loads[target] = (VAR_LOAD_RESOLVE, name) self.loads[target] = (VAR_LOAD_RESOLVE, name)
def dump_stores(self) -> t.Dict[str, str]: def dump_stores(self) -> dict[str, str]:
rv: t.Dict[str, str] = {} rv: dict[str, str] = {}
node: t.Optional[Symbols] = self node: t.Optional[Symbols] = self
while node is not None: while node is not None:
@ -157,7 +157,7 @@ class Symbols:
return rv return rv
def dump_param_targets(self) -> t.Set[str]: def dump_param_targets(self) -> set[str]:
rv = set() rv = set()
node: t.Optional[Symbols] = self node: t.Optional[Symbols] = self

View File

@ -21,7 +21,7 @@ if t.TYPE_CHECKING:
# cache for the lexers. Exists in order to be able to have multiple # cache for the lexers. Exists in order to be able to have multiple
# environments with the same lexer # 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 # static regular expressions
whitespace_re = re.compile(r"\s+") whitespace_re = re.compile(r"\s+")
@ -210,7 +210,7 @@ def count_newlines(value: str) -> int:
return len(newline_re.findall(value)) 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.""" """Compiles all the rules from the environment into a list of rules."""
e = re.escape e = re.escape
rules = [ rules = [
@ -257,7 +257,7 @@ class Failure:
""" """
def __init__( def __init__(
self, message: str, cls: t.Type[TemplateSyntaxError] = TemplateSyntaxError self, message: str, cls: type[TemplateSyntaxError] = TemplateSyntaxError
) -> None: ) -> None:
self.message = message self.message = message
self.error_class = cls self.error_class = cls
@ -329,7 +329,7 @@ class TokenStream:
filename: t.Optional[str], filename: t.Optional[str],
): ):
self._iter = iter(generator) self._iter = iter(generator)
self._pushed: te.Deque[Token] = deque() self._pushed: deque[Token] = deque()
self.name = name self.name = name
self.filename = filename self.filename = filename
self.closed = False self.closed = False
@ -464,7 +464,7 @@ class OptionalLStrip(tuple): # type: ignore[type-arg]
class _Rule(t.NamedTuple): class _Rule(t.NamedTuple):
pattern: t.Pattern[str] 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] command: t.Optional[str]
@ -484,7 +484,7 @@ class Lexer:
return re.compile(x, re.M | re.S) return re.compile(x, re.M | re.S)
# lexing rules for tags # lexing rules for tags
tag_rules: t.List[_Rule] = [ tag_rules: list[_Rule] = [
_Rule(whitespace_re, TOKEN_WHITESPACE, None), _Rule(whitespace_re, TOKEN_WHITESPACE, None),
_Rule(float_re, TOKEN_FLOAT, None), _Rule(float_re, TOKEN_FLOAT, None),
_Rule(integer_re, TOKEN_INTEGER, None), _Rule(integer_re, TOKEN_INTEGER, None),
@ -523,7 +523,7 @@ class Lexer:
) )
# global lexing rules # global lexing rules
self.rules: t.Dict[str, t.List[_Rule]] = { self.rules: dict[str, list[_Rule]] = {
"root": [ "root": [
# directives # directives
_Rule( _Rule(
@ -614,7 +614,7 @@ class Lexer:
def wrap( def wrap(
self, self,
stream: t.Iterable[t.Tuple[int, str, str]], stream: t.Iterable[tuple[int, str, str]],
name: t.Optional[str] = None, name: t.Optional[str] = None,
filename: t.Optional[str] = None, filename: t.Optional[str] = None,
) -> t.Iterator[Token]: ) -> t.Iterator[Token]:
@ -672,7 +672,7 @@ class Lexer:
name: t.Optional[str], name: t.Optional[str],
filename: t.Optional[str] = None, filename: t.Optional[str] = None,
state: 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 """This method tokenizes the text and returns the tokens in a
generator. Use this method if you just want to tokenize a template. generator. Use this method if you just want to tokenize a template.
@ -696,7 +696,7 @@ class Lexer:
statetokens = self.rules[stack[-1]] statetokens = self.rules[stack[-1]]
source_length = len(source) source_length = len(source)
balancing_stack: t.List[str] = [] balancing_stack: list[str] = []
newlines_stripped = 0 newlines_stripped = 0
line_starting = True line_starting = True

View File

@ -22,7 +22,7 @@ if t.TYPE_CHECKING:
from .environment import Template 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 """Split a path into segments and perform a sanity check. If it detects
'..' in the path it will raise a `TemplateNotFound` error. '..' in the path it will raise a `TemplateNotFound` error.
""" """
@ -74,7 +74,7 @@ class BaseLoader:
def get_source( def get_source(
self, environment: "Environment", template: str 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. """Get the template source, filename and reload helper for a template.
It's passed the environment and template name and has to return a It's passed the environment and template name and has to return a
tuple in the form ``(source, filename, uptodate)`` or raise a tuple in the form ``(source, filename, uptodate)`` or raise a
@ -98,7 +98,7 @@ class BaseLoader:
) )
raise TemplateNotFound(template) 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 """Iterates over all templates. If the loader does not support that
it should raise a :exc:`TypeError` which is the default behavior. it should raise a :exc:`TypeError` which is the default behavior.
""" """
@ -193,7 +193,7 @@ class FileSystemLoader(BaseLoader):
def get_source( def get_source(
self, environment: "Environment", template: str self, environment: "Environment", template: str
) -> t.Tuple[str, str, t.Callable[[], bool]]: ) -> tuple[str, str, t.Callable[[], bool]]:
pieces = split_template_path(template) pieces = split_template_path(template)
for searchpath in self.searchpath: for searchpath in self.searchpath:
@ -225,7 +225,7 @@ class FileSystemLoader(BaseLoader):
# Use normpath to convert Windows altsep to sep. # Use normpath to convert Windows altsep to sep.
return contents, os.path.normpath(filename), uptodate return contents, os.path.normpath(filename), uptodate
def list_templates(self) -> t.List[str]: def list_templates(self) -> list[str]:
found = set() found = set()
for searchpath in self.searchpath: for searchpath in self.searchpath:
walk_dir = os.walk(searchpath, followlinks=self.followlinks) walk_dir = os.walk(searchpath, followlinks=self.followlinks)
@ -245,24 +245,23 @@ class FileSystemLoader(BaseLoader):
if sys.version_info >= (3, 13): 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: try:
get_files = z._get_files get_files = z._get_files
except AttributeError as e: except AttributeError as e:
raise TypeError( raise TypeError(
"This zip import does not have the required" "This zip import does not have the required metadata to list templates."
" metadata to list templates."
) from e ) from e
return get_files() return get_files()
else: else:
def _get_zipimporter_files(z: t.Any) -> t.Dict[str, object]: def _get_zipimporter_files(z: t.Any) -> dict[str, object]:
try: try:
files = z._files files = z._files
except AttributeError as e: except AttributeError as e:
raise TypeError( raise TypeError(
"This zip import does not have the required" "This zip import does not have the required metadata to list templates."
" metadata to list templates."
) from e ) from e
return files # type: ignore[no-any-return] return files # type: ignore[no-any-return]
@ -333,7 +332,7 @@ class PackageLoader(BaseLoader):
pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore
template_root = os.path.join(pkgdir, package_path).rstrip(os.sep) template_root = os.path.join(pkgdir, package_path).rstrip(os.sep)
else: else:
roots: t.List[str] = [] roots: list[str] = []
# One element for regular packages, multiple for namespace # One element for regular packages, multiple for namespace
# packages, or None for single module file. # packages, or None for single module file.
@ -365,7 +364,7 @@ class PackageLoader(BaseLoader):
def get_source( def get_source(
self, environment: "Environment", template: str 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 # Use posixpath even on Windows to avoid "drive:" or UNC
# segments breaking out of the search directory. Use normpath to # segments breaking out of the search directory. Use normpath to
# convert Windows altsep to sep. # convert Windows altsep to sep.
@ -401,8 +400,8 @@ class PackageLoader(BaseLoader):
return source.decode(self.encoding), p, up_to_date return source.decode(self.encoding), p, up_to_date
def list_templates(self) -> t.List[str]: def list_templates(self) -> list[str]:
results: t.List[str] = [] results: list[str] = []
if self._archive is None: if self._archive is None:
# Package is a directory. # Package is a directory.
@ -444,13 +443,13 @@ class DictLoader(BaseLoader):
def get_source( def get_source(
self, environment: "Environment", template: str self, environment: "Environment", template: str
) -> t.Tuple[str, None, t.Callable[[], bool]]: ) -> tuple[str, None, t.Callable[[], bool]]:
if template in self.mapping: if template in self.mapping:
source = self.mapping[template] source = self.mapping[template]
return source, None, lambda: source == self.mapping.get(template) return source, None, lambda: source == self.mapping.get(template)
raise TemplateNotFound(template) raise TemplateNotFound(template)
def list_templates(self) -> t.List[str]: def list_templates(self) -> list[str]:
return sorted(self.mapping) return sorted(self.mapping)
@ -478,7 +477,7 @@ class FunctionLoader(BaseLoader):
[str], [str],
t.Optional[ t.Optional[
t.Union[ 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]]]
] ]
], ],
], ],
@ -487,7 +486,7 @@ class FunctionLoader(BaseLoader):
def get_source( def get_source(
self, environment: "Environment", template: str 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) rv = self.load_func(template)
if rv is None: if rv is None:
@ -520,7 +519,7 @@ class PrefixLoader(BaseLoader):
self.mapping = mapping self.mapping = mapping
self.delimiter = delimiter self.delimiter = delimiter
def get_loader(self, template: str) -> t.Tuple[BaseLoader, str]: def get_loader(self, template: str) -> tuple[BaseLoader, str]:
try: try:
prefix, name = template.split(self.delimiter, 1) prefix, name = template.split(self.delimiter, 1)
loader = self.mapping[prefix] loader = self.mapping[prefix]
@ -530,7 +529,7 @@ class PrefixLoader(BaseLoader):
def get_source( def get_source(
self, environment: "Environment", template: str 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) loader, name = self.get_loader(template)
try: try:
return loader.get_source(environment, name) return loader.get_source(environment, name)
@ -554,7 +553,7 @@ class PrefixLoader(BaseLoader):
# (the one that includes the prefix) # (the one that includes the prefix)
raise TemplateNotFound(name) from e raise TemplateNotFound(name) from e
def list_templates(self) -> t.List[str]: def list_templates(self) -> list[str]:
result = [] result = []
for prefix, loader in self.mapping.items(): for prefix, loader in self.mapping.items():
for template in loader.list_templates(): for template in loader.list_templates():
@ -581,7 +580,7 @@ class ChoiceLoader(BaseLoader):
def get_source( def get_source(
self, environment: "Environment", template: str 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: for loader in self.loaders:
try: try:
return loader.get_source(environment, template) return loader.get_source(environment, template)
@ -603,7 +602,7 @@ class ChoiceLoader(BaseLoader):
pass pass
raise TemplateNotFound(name) raise TemplateNotFound(name)
def list_templates(self) -> t.List[str]: def list_templates(self) -> list[str]:
found = set() found = set()
for loader in self.loaders: for loader in self.loaders:
found.update(loader.list_templates()) found.update(loader.list_templates())

View File

@ -17,7 +17,7 @@ class TrackingCodeGenerator(CodeGenerator):
def __init__(self, environment: "Environment") -> None: def __init__(self, environment: "Environment") -> None:
super().__init__(environment, "<introspection>", "<introspection>") super().__init__(environment, "<introspection>", "<introspection>")
self.undeclared_identifiers: t.Set[str] = set() self.undeclared_identifiers: set[str] = set()
def write(self, x: str) -> None: def write(self, x: str) -> None:
"""Don't write.""" """Don't write."""
@ -31,7 +31,7 @@ class TrackingCodeGenerator(CodeGenerator):
self.undeclared_identifiers.add(param) 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 """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 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 variables will be used depending on the path the execution takes at

View File

@ -19,7 +19,7 @@ if t.TYPE_CHECKING:
_NodeBound = t.TypeVar("_NodeBound", bound="Node") _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.mul,
"/": operator.truediv, "/": operator.truediv,
"//": operator.floordiv, "//": operator.floordiv,
@ -29,13 +29,13 @@ _binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"-": operator.sub, "-": 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_, "not": operator.not_,
"+": operator.pos, "+": operator.pos,
"-": operator.neg, "-": 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, "eq": operator.eq,
"ne": operator.ne, "ne": operator.ne,
"gt": operator.gt, "gt": operator.gt,
@ -58,7 +58,7 @@ class NodeType(type):
def __new__(mcs, name, bases, d): # type: ignore def __new__(mcs, name, bases, d): # type: ignore
for attr in "fields", "attributes": 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(getattr(bases[0] if bases else object, attr, ()))
storage.extend(d.get(attr, ())) storage.extend(d.get(attr, ()))
assert len(bases) <= 1, "multiple inheritance not allowed" assert len(bases) <= 1, "multiple inheritance not allowed"
@ -119,8 +119,8 @@ class Node(metaclass=NodeType):
all nodes automatically. all nodes automatically.
""" """
fields: t.Tuple[str, ...] = () fields: tuple[str, ...] = ()
attributes: t.Tuple[str, ...] = ("lineno", "environment") attributes: tuple[str, ...] = ("lineno", "environment")
abstract = True abstract = True
lineno: int lineno: int
@ -148,7 +148,7 @@ class Node(metaclass=NodeType):
self, self,
exclude: t.Optional[t.Container[str]] = None, exclude: t.Optional[t.Container[str]] = None,
only: 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 """This method iterates over all fields that are defined and yields
``(key, value)`` tuples. Per default all fields are returned, but ``(key, value)`` tuples. Per default all fields are returned, but
it's possible to limit that to some fields by providing the `only` it's possible to limit that to some fields by providing the `only`
@ -183,7 +183,7 @@ class Node(metaclass=NodeType):
elif isinstance(item, Node): elif isinstance(item, Node):
yield item 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 """Find the first node of a given type. If no such node exists the
return value is `None`. return value is `None`.
""" """
@ -193,7 +193,7 @@ class Node(metaclass=NodeType):
return None return None
def find_all( 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]: ) -> t.Iterator[_NodeBound]:
"""Find all the nodes of a given type. If the type is a tuple, """Find all the nodes of a given type. If the type is a tuple,
the check is performed for any of the tuple items. the check is performed for any of the tuple items.
@ -274,7 +274,7 @@ class Node(metaclass=NodeType):
_dump(value) _dump(value)
buf.append(")") buf.append(")")
buf: t.List[str] = [] buf: list[str] = []
_dump(self) _dump(self)
return "".join(buf) return "".join(buf)
@ -297,7 +297,7 @@ class Template(Node):
""" """
fields = ("body",) fields = ("body",)
body: t.List[Node] body: list[Node]
class Output(Stmt): class Output(Stmt):
@ -306,7 +306,7 @@ class Output(Stmt):
""" """
fields = ("nodes",) fields = ("nodes",)
nodes: t.List["Expr"] nodes: list["Expr"]
class Extends(Stmt): class Extends(Stmt):
@ -328,8 +328,8 @@ class For(Stmt):
fields = ("target", "iter", "body", "else_", "test", "recursive") fields = ("target", "iter", "body", "else_", "test", "recursive")
target: Node target: Node
iter: Node iter: Node
body: t.List[Node] body: list[Node]
else_: t.List[Node] else_: list[Node]
test: t.Optional[Node] test: t.Optional[Node]
recursive: bool recursive: bool
@ -339,9 +339,9 @@ class If(Stmt):
fields = ("test", "body", "elif_", "else_") fields = ("test", "body", "elif_", "else_")
test: Node test: Node
body: t.List[Node] body: list[Node]
elif_: t.List["If"] elif_: list["If"]
else_: t.List[Node] else_: list[Node]
class Macro(Stmt): class Macro(Stmt):
@ -352,9 +352,9 @@ class Macro(Stmt):
fields = ("name", "args", "defaults", "body") fields = ("name", "args", "defaults", "body")
name: str name: str
args: t.List["Name"] args: list["Name"]
defaults: t.List["Expr"] defaults: list["Expr"]
body: t.List[Node] body: list[Node]
class CallBlock(Stmt): class CallBlock(Stmt):
@ -364,16 +364,16 @@ class CallBlock(Stmt):
fields = ("call", "args", "defaults", "body") fields = ("call", "args", "defaults", "body")
call: "Call" call: "Call"
args: t.List["Name"] args: list["Name"]
defaults: t.List["Expr"] defaults: list["Expr"]
body: t.List[Node] body: list[Node]
class FilterBlock(Stmt): class FilterBlock(Stmt):
"""Node for filter sections.""" """Node for filter sections."""
fields = ("body", "filter") fields = ("body", "filter")
body: t.List[Node] body: list[Node]
filter: "Filter" filter: "Filter"
@ -385,9 +385,9 @@ class With(Stmt):
""" """
fields = ("targets", "values", "body") fields = ("targets", "values", "body")
targets: t.List["Expr"] targets: list["Expr"]
values: t.List["Expr"] values: list["Expr"]
body: t.List[Node] body: list[Node]
class Block(Stmt): class Block(Stmt):
@ -399,7 +399,7 @@ class Block(Stmt):
fields = ("name", "body", "scoped", "required") fields = ("name", "body", "scoped", "required")
name: str name: str
body: t.List[Node] body: list[Node]
scoped: bool scoped: bool
required: bool required: bool
@ -436,7 +436,7 @@ class FromImport(Stmt):
fields = ("template", "names", "with_context") fields = ("template", "names", "with_context")
template: "Expr" template: "Expr"
names: t.List[t.Union[str, t.Tuple[str, str]]] names: list[t.Union[str, tuple[str, str]]]
with_context: bool with_context: bool
@ -461,7 +461,7 @@ class AssignBlock(Stmt):
fields = ("target", "filter", "body") fields = ("target", "filter", "body")
target: "Expr" target: "Expr"
filter: t.Optional["Filter"] filter: t.Optional["Filter"]
body: t.List[Node] body: list[Node]
class Expr(Node): class Expr(Node):
@ -627,10 +627,10 @@ class Tuple(Literal):
""" """
fields = ("items", "ctx") fields = ("items", "ctx")
items: t.List[Expr] items: list[Expr]
ctx: str 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) eval_ctx = get_eval_context(self, eval_ctx)
return tuple(x.as_const(eval_ctx) for x in self.items) return tuple(x.as_const(eval_ctx) for x in self.items)
@ -645,9 +645,9 @@ class List(Literal):
"""Any list literal such as ``[1, 2, 3]``""" """Any list literal such as ``[1, 2, 3]``"""
fields = ("items",) 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) eval_ctx = get_eval_context(self, eval_ctx)
return [x.as_const(eval_ctx) for x in self.items] return [x.as_const(eval_ctx) for x in self.items]
@ -658,11 +658,9 @@ class Dict(Literal):
""" """
fields = ("items",) fields = ("items",)
items: t.List["Pair"] items: list["Pair"]
def as_const( def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> dict[t.Any, t.Any]:
self, eval_ctx: t.Optional[EvalContext] = None
) -> t.Dict[t.Any, t.Any]:
eval_ctx = get_eval_context(self, eval_ctx) eval_ctx = get_eval_context(self, eval_ctx)
return dict(x.as_const(eval_ctx) for x in self.items) return dict(x.as_const(eval_ctx) for x in self.items)
@ -674,9 +672,7 @@ class Pair(Helper):
key: Expr key: Expr
value: Expr value: Expr
def as_const( def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[t.Any, t.Any]:
self, eval_ctx: t.Optional[EvalContext] = None
) -> t.Tuple[t.Any, t.Any]:
eval_ctx = get_eval_context(self, eval_ctx) eval_ctx = get_eval_context(self, eval_ctx)
return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx) return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
@ -688,7 +684,7 @@ class Keyword(Helper):
key: str key: str
value: Expr 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) eval_ctx = get_eval_context(self, eval_ctx)
return self.key, self.value.as_const(eval_ctx) return self.key, self.value.as_const(eval_ctx)
@ -717,7 +713,7 @@ class CondExpr(Expr):
def args_as_const( def args_as_const(
node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext] 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] args = [x.as_const(eval_ctx) for x in node.args]
kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs) kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
@ -740,8 +736,8 @@ class _FilterTestCommon(Expr):
fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs") fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
node: Expr node: Expr
name: str name: str
args: t.List[Expr] args: list[Expr]
kwargs: t.List[Pair] kwargs: list[Pair]
dyn_args: t.Optional[Expr] dyn_args: t.Optional[Expr]
dyn_kwargs: t.Optional[Expr] dyn_kwargs: t.Optional[Expr]
abstract = True abstract = True
@ -824,8 +820,8 @@ class Call(Expr):
fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs") fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs")
node: Expr node: Expr
args: t.List[Expr] args: list[Expr]
kwargs: t.List[Keyword] kwargs: list[Keyword]
dyn_args: t.Optional[Expr] dyn_args: t.Optional[Expr]
dyn_kwargs: t.Optional[Expr] dyn_kwargs: t.Optional[Expr]
@ -901,7 +897,7 @@ class Concat(Expr):
""" """
fields = ("nodes",) fields = ("nodes",)
nodes: t.List[Expr] nodes: list[Expr]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str: def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
eval_ctx = get_eval_context(self, eval_ctx) eval_ctx = get_eval_context(self, eval_ctx)
@ -915,7 +911,7 @@ class Compare(Expr):
fields = ("expr", "ops") fields = ("expr", "ops")
expr: Expr expr: Expr
ops: t.List["Operand"] ops: list["Operand"]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
eval_ctx = get_eval_context(self, eval_ctx) eval_ctx = get_eval_context(self, eval_ctx)
@ -1152,7 +1148,7 @@ class Scope(Stmt):
"""An artificial scope.""" """An artificial scope."""
fields = ("body",) fields = ("body",)
body: t.List[Node] body: list[Node]
class OverlayScope(Stmt): class OverlayScope(Stmt):
@ -1171,7 +1167,7 @@ class OverlayScope(Stmt):
fields = ("context", "body") fields = ("context", "body")
context: Expr context: Expr
body: t.List[Node] body: list[Node]
class EvalContextModifier(Stmt): class EvalContextModifier(Stmt):
@ -1184,7 +1180,7 @@ class EvalContextModifier(Stmt):
""" """
fields = ("options",) fields = ("options",)
options: t.List[Keyword] options: list[Keyword]
class ScopedEvalContextModifier(EvalContextModifier): class ScopedEvalContextModifier(EvalContextModifier):
@ -1194,7 +1190,7 @@ class ScopedEvalContextModifier(EvalContextModifier):
""" """
fields = ("body",) fields = ("body",)
body: t.List[Node] body: list[Node]
# make sure nobody creates custom nodes # make sure nobody creates custom nodes

View File

@ -35,7 +35,7 @@ _statement_keywords = frozenset(
) )
_compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"]) _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, "add": nodes.Add,
"sub": nodes.Sub, "sub": nodes.Sub,
"mul": nodes.Mul, "mul": nodes.Mul,
@ -63,21 +63,21 @@ class Parser:
self.name = name self.name = name
self.filename = filename self.filename = filename
self.closed = False self.closed = False
self.extensions: t.Dict[ self.extensions: dict[
str, t.Callable[[Parser], t.Union[nodes.Node, t.List[nodes.Node]]] str, t.Callable[[Parser], t.Union[nodes.Node, list[nodes.Node]]]
] = {} ] = {}
for extension in environment.iter_extensions(): for extension in environment.iter_extensions():
for tag in extension.tags: for tag in extension.tags:
self.extensions[tag] = extension.parse self.extensions[tag] = extension.parse
self._last_identifier = 0 self._last_identifier = 0
self._tag_stack: t.List[str] = [] self._tag_stack: list[str] = []
self._end_token_stack: t.List[t.Tuple[str, ...]] = [] self._end_token_stack: list[tuple[str, ...]] = []
def fail( def fail(
self, self,
msg: str, msg: str,
lineno: t.Optional[int] = None, lineno: t.Optional[int] = None,
exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError, exc: type[TemplateSyntaxError] = TemplateSyntaxError,
) -> "te.NoReturn": ) -> "te.NoReturn":
"""Convenience method that raises `exc` with the message, passed """Convenience method that raises `exc` with the message, passed
line number or last line number as well as the current name and line number or last line number as well as the current name and
@ -90,10 +90,10 @@ class Parser:
def _fail_ut_eof( def _fail_ut_eof(
self, self,
name: t.Optional[str], name: t.Optional[str],
end_token_stack: t.List[t.Tuple[str, ...]], end_token_stack: list[tuple[str, ...]],
lineno: t.Optional[int], lineno: t.Optional[int],
) -> "te.NoReturn": ) -> "te.NoReturn":
expected: t.Set[str] = set() expected: set[str] = set()
for exprs in end_token_stack: for exprs in end_token_stack:
expected.update(map(describe_token_expr, exprs)) expected.update(map(describe_token_expr, exprs))
if end_token_stack: if end_token_stack:
@ -138,7 +138,7 @@ class Parser:
def fail_eof( def fail_eof(
self, self,
end_tokens: t.Optional[t.Tuple[str, ...]] = None, end_tokens: t.Optional[tuple[str, ...]] = None,
lineno: t.Optional[int] = None, lineno: t.Optional[int] = None,
) -> "te.NoReturn": ) -> "te.NoReturn":
"""Like fail_unknown_tag but for end of template situations.""" """Like fail_unknown_tag but for end of template situations."""
@ -147,9 +147,7 @@ class Parser:
stack.append(end_tokens) stack.append(end_tokens)
self._fail_ut_eof(None, stack, lineno) self._fail_ut_eof(None, stack, lineno)
def is_tuple_end( def is_tuple_end(self, extra_end_rules: t.Optional[tuple[str, ...]] = None) -> bool:
self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None
) -> bool:
"""Are we at the end of a tuple?""" """Are we at the end of a tuple?"""
if self.stream.current.type in ("variable_end", "block_end", "rparen"): if self.stream.current.type in ("variable_end", "block_end", "rparen"):
return True return True
@ -164,7 +162,7 @@ class Parser:
nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno) nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno)
return rv 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.""" """Parse a single statement."""
token = self.stream.current token = self.stream.current
if token.type != "name": if token.type != "name":
@ -194,8 +192,8 @@ class Parser:
self._tag_stack.pop() self._tag_stack.pop()
def parse_statements( def parse_statements(
self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False self, end_tokens: tuple[str, ...], drop_needle: bool = False
) -> t.List[nodes.Node]: ) -> list[nodes.Node]:
"""Parse multiple statements into a list until one of the end tokens """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 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 parses template data if appropriate. The parser checks first if the
@ -272,8 +270,8 @@ class Parser:
def parse_with(self) -> nodes.With: def parse_with(self) -> nodes.With:
node = nodes.With(lineno=next(self.stream).lineno) node = nodes.With(lineno=next(self.stream).lineno)
targets: t.List[nodes.Expr] = [] targets: list[nodes.Expr] = []
values: t.List[nodes.Expr] = [] values: list[nodes.Expr] = []
while self.stream.current.type != "block_end": while self.stream.current.type != "block_end":
if targets: if targets:
self.stream.expect("comma") self.stream.expect("comma")
@ -466,7 +464,7 @@ class Parser:
self, self,
with_tuple: bool = True, with_tuple: bool = True,
name_only: bool = False, 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, with_namespace: bool = False,
) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: ... ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: ...
@ -474,7 +472,7 @@ class Parser:
self, self,
with_tuple: bool = True, with_tuple: bool = True,
name_only: bool = False, 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, with_namespace: bool = False,
) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]:
"""Parse an assignment target. As Jinja allows assignments to """Parse an assignment target. As Jinja allows assignments to
@ -686,7 +684,7 @@ class Parser:
self, self,
simplified: bool = False, simplified: bool = False,
with_condexpr: bool = True, 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, explicit_parentheses: bool = False,
with_namespace: bool = False, with_namespace: bool = False,
) -> t.Union[nodes.Tuple, nodes.Expr]: ) -> t.Union[nodes.Tuple, nodes.Expr]:
@ -720,7 +718,7 @@ class Parser:
def parse() -> nodes.Expr: def parse() -> nodes.Expr:
return self.parse_expression(with_condexpr=with_condexpr) return self.parse_expression(with_condexpr=with_condexpr)
args: t.List[nodes.Expr] = [] args: list[nodes.Expr] = []
is_tuple = False is_tuple = False
while True: while True:
@ -753,7 +751,7 @@ class Parser:
def parse_list(self) -> nodes.List: def parse_list(self) -> nodes.List:
token = self.stream.expect("lbracket") token = self.stream.expect("lbracket")
items: t.List[nodes.Expr] = [] items: list[nodes.Expr] = []
while self.stream.current.type != "rbracket": while self.stream.current.type != "rbracket":
if items: if items:
self.stream.expect("comma") self.stream.expect("comma")
@ -765,7 +763,7 @@ class Parser:
def parse_dict(self) -> nodes.Dict: def parse_dict(self) -> nodes.Dict:
token = self.stream.expect("lbrace") token = self.stream.expect("lbrace")
items: t.List[nodes.Pair] = [] items: list[nodes.Pair] = []
while self.stream.current.type != "rbrace": while self.stream.current.type != "rbrace":
if items: if items:
self.stream.expect("comma") self.stream.expect("comma")
@ -824,7 +822,7 @@ class Parser:
arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
return nodes.Getitem(node, arg, "load", lineno=token.lineno) return nodes.Getitem(node, arg, "load", lineno=token.lineno)
if token.type == "lbracket": if token.type == "lbracket":
args: t.List[nodes.Expr] = [] args: list[nodes.Expr] = []
while self.stream.current.type != "rbracket": while self.stream.current.type != "rbracket":
if args: if args:
self.stream.expect("comma") self.stream.expect("comma")
@ -839,7 +837,7 @@ class Parser:
def parse_subscribed(self) -> nodes.Expr: def parse_subscribed(self) -> nodes.Expr:
lineno = self.stream.current.lineno lineno = self.stream.current.lineno
args: t.List[t.Optional[nodes.Expr]] args: list[t.Optional[nodes.Expr]]
if self.stream.current.type == "colon": if self.stream.current.type == "colon":
next(self.stream) next(self.stream)
@ -871,9 +869,9 @@ class Parser:
def parse_call_args( def parse_call_args(
self, self,
) -> t.Tuple[ ) -> tuple[
t.List[nodes.Expr], list[nodes.Expr],
t.List[nodes.Keyword], list[nodes.Keyword],
t.Union[nodes.Expr, None], t.Union[nodes.Expr, None],
t.Union[nodes.Expr, None], t.Union[nodes.Expr, None],
]: ]:
@ -967,7 +965,7 @@ class Parser:
next(self.stream) next(self.stream)
name += "." + self.stream.expect("name").value name += "." + self.stream.expect("name").value
dyn_args = dyn_kwargs = None dyn_args = dyn_kwargs = None
kwargs: t.List[nodes.Keyword] = [] kwargs: list[nodes.Keyword] = []
if self.stream.current.type == "lparen": if self.stream.current.type == "lparen":
args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args() args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
elif self.stream.current.type in { elif self.stream.current.type in {
@ -994,10 +992,10 @@ class Parser:
return node return node
def subparse( def subparse(
self, end_tokens: t.Optional[t.Tuple[str, ...]] = None self, end_tokens: t.Optional[tuple[str, ...]] = None
) -> t.List[nodes.Node]: ) -> list[nodes.Node]:
body: t.List[nodes.Node] = [] body: list[nodes.Node] = []
data_buffer: t.List[nodes.Node] = [] data_buffer: list[nodes.Node] = []
add_data = data_buffer.append add_data = data_buffer.append
if end_tokens is not None: if end_tokens is not None:

View File

@ -93,8 +93,8 @@ def str_join(seq: t.Iterable[t.Any]) -> str:
def new_context( def new_context(
environment: "Environment", environment: "Environment",
template_name: t.Optional[str], template_name: t.Optional[str],
blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]], blocks: dict[str, t.Callable[["Context"], t.Iterator[str]]],
vars: t.Optional[t.Dict[str, t.Any]] = None, vars: t.Optional[dict[str, t.Any]] = None,
shared: bool = False, shared: bool = False,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None, globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
locals: t.Optional[t.Mapping[str, t.Any]] = None, locals: t.Optional[t.Mapping[str, t.Any]] = None,
@ -165,16 +165,16 @@ class Context:
def __init__( def __init__(
self, self,
environment: "Environment", environment: "Environment",
parent: t.Dict[str, t.Any], parent: dict[str, t.Any],
name: t.Optional[str], 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, globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
): ):
self.parent = parent self.parent = parent
self.vars: t.Dict[str, t.Any] = {} self.vars: dict[str, t.Any] = {}
self.environment: Environment = environment self.environment: Environment = environment
self.eval_ctx = EvalContext(self.environment, name) self.eval_ctx = EvalContext(self.environment, name)
self.exported_vars: t.Set[str] = set() self.exported_vars: set[str] = set()
self.name = name self.name = name
self.globals_keys = set() if globals is None else set(globals) self.globals_keys = set() if globals is None else set(globals)
@ -244,11 +244,11 @@ class Context:
return missing 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.""" """Get a new dict with the exported variables."""
return {k: self.vars[k] for k in self.exported_vars} 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 """Return the complete context as dict including the exported
variables. For optimizations reasons this might not return an variables. For optimizations reasons this might not return an
actual copy so be careful with using it. actual copy so be careful with using it.
@ -307,7 +307,7 @@ class Context:
" StopIteration exception" " 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 """Internal helper function to create a derived context. This is
used in situations where the system needs a new context in the same used in situations where the system needs a new context in the same
template that is independent. template that is independent.
@ -348,7 +348,7 @@ class BlockReference:
self, self,
name: str, name: str,
context: "Context", context: "Context",
stack: t.List[t.Callable[["Context"], t.Iterator[str]]], stack: list[t.Callable[["Context"], t.Iterator[str]]],
depth: int, depth: int,
) -> None: ) -> None:
self.name = name self.name = name
@ -408,7 +408,7 @@ class LoopContext:
def __init__( def __init__(
self, self,
iterable: t.Iterable[V], iterable: t.Iterable[V],
undefined: t.Type["Undefined"], undefined: type["Undefined"],
recurse: t.Optional["LoopRenderFunc"] = None, recurse: t.Optional["LoopRenderFunc"] = None,
depth0: int = 0, depth0: int = 0,
) -> None: ) -> None:
@ -558,7 +558,7 @@ class LoopContext:
def __iter__(self) -> "LoopContext": def __iter__(self) -> "LoopContext":
return self return self
def __next__(self) -> t.Tuple[t.Any, "LoopContext"]: def __next__(self) -> tuple[t.Any, "LoopContext"]:
if self._after is not missing: if self._after is not missing:
rv = self._after rv = self._after
self._after = missing self._after = missing
@ -646,7 +646,7 @@ class AsyncLoopContext(LoopContext):
def __aiter__(self) -> "AsyncLoopContext": def __aiter__(self) -> "AsyncLoopContext":
return self 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: if self._after is not missing:
rv = self._after rv = self._after
self._after = missing self._after = missing
@ -667,7 +667,7 @@ class Macro:
environment: "Environment", environment: "Environment",
func: t.Callable[..., str], func: t.Callable[..., str],
name: str, name: str,
arguments: t.List[str], arguments: list[str],
catch_kwargs: bool, catch_kwargs: bool,
catch_varargs: bool, catch_varargs: bool,
caller: bool, caller: bool,
@ -769,7 +769,7 @@ class Macro:
return self._invoke(arguments, autoescape) 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 rv = await self._func(*arguments) # type: ignore
if autoescape: if autoescape:
@ -777,7 +777,7 @@ class Macro:
return rv # type: ignore 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: if self._environment.is_async:
return self._async_invoke(arguments, autoescape) # type: ignore return self._async_invoke(arguments, autoescape) # type: ignore
@ -820,7 +820,7 @@ class Undefined:
hint: t.Optional[str] = None, hint: t.Optional[str] = None,
obj: t.Any = missing, obj: t.Any = missing,
name: t.Optional[str] = None, name: t.Optional[str] = None,
exc: t.Type[TemplateRuntimeError] = UndefinedError, exc: type[TemplateRuntimeError] = UndefinedError,
) -> None: ) -> None:
self._undefined_hint = hint self._undefined_hint = hint
self._undefined_obj = obj self._undefined_obj = obj
@ -910,8 +910,8 @@ class Undefined:
def make_logging_undefined( def make_logging_undefined(
logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined logger: t.Optional["logging.Logger"] = None, base: type[Undefined] = Undefined
) -> t.Type[Undefined]: ) -> type[Undefined]:
"""Given a logger object this returns a new undefined class that will """Given a logger object this returns a new undefined class that will
log certain failures. It will log iterations and printing. If no log certain failures. It will log iterations and printing. If no
logger is given a default logger is created. logger is given a default logger is created.

View File

@ -25,10 +25,10 @@ F = t.TypeVar("F", bound=t.Callable[..., t.Any])
MAX_RANGE = 100000 MAX_RANGE = 100000
#: Unsafe function attributes. #: 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. 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.
UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"} UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"}
@ -39,7 +39,7 @@ UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"}
#: unsafe attributes on async generators #: unsafe attributes on async generators
UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"} 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, abc.MutableSet,
frozenset( frozenset(
@ -190,7 +190,7 @@ class SandboxedEnvironment(Environment):
#: default callback table for the binary operators. A copy of this is #: default callback table for the binary operators. A copy of this is
#: available on each instance of a sandboxed environment as #: available on each instance of a sandboxed environment as
#: :attr:`binop_table` #: :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.add,
"-": operator.sub, "-": operator.sub,
"*": operator.mul, "*": operator.mul,
@ -203,7 +203,7 @@ class SandboxedEnvironment(Environment):
#: default callback table for the unary operators. A copy of this is #: default callback table for the unary operators. A copy of this is
#: available on each instance of a sandboxed environment as #: available on each instance of a sandboxed environment as
#: :attr:`unop_table` #: :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.pos,
"-": operator.neg, "-": operator.neg,
} }
@ -222,7 +222,7 @@ class SandboxedEnvironment(Environment):
#: interested in. #: interested in.
#: #:
#: .. versionadded:: 2.6 #: .. 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 #: a set of unary operators that should be intercepted. Each operator
#: that is added to this set (empty by default) is delegated to the #: that is added to this set (empty by default) is delegated to the
@ -237,7 +237,7 @@ class SandboxedEnvironment(Environment):
#: interested in. #: interested in.
#: #:
#: .. versionadded:: 2.6 #: .. versionadded:: 2.6
intercepted_unops: t.FrozenSet[str] = frozenset() intercepted_unops: frozenset[str] = frozenset()
def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -357,7 +357,7 @@ class SandboxedEnvironment(Environment):
if not isinstance(f_self, str): if not isinstance(f_self, str):
return None return None
str_type: t.Type[str] = type(f_self) str_type: type[str] = type(f_self)
is_format_map = value.__name__ == "format_map" is_format_map = value.__name__ == "format_map"
formatter: SandboxedFormatter formatter: SandboxedFormatter
@ -421,7 +421,7 @@ class SandboxedFormatter(Formatter):
def get_field( def get_field(
self, field_name: str, args: t.Sequence[t.Any], kwargs: t.Mapping[str, t.Any] 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) first, rest = formatter_field_name_split(field_name)
obj = self.get_value(first, args, kwargs) obj = self.get_value(first, args, kwargs)
for is_attr, i in rest: for is_attr, i in rest:

View File

@ -438,8 +438,8 @@ class LRUCache:
def __init__(self, capacity: int) -> None: def __init__(self, capacity: int) -> None:
self.capacity = capacity self.capacity = capacity
self._mapping: t.Dict[t.Any, t.Any] = {} self._mapping: dict[t.Any, t.Any] = {}
self._queue: te.Deque[t.Any] = deque() self._queue: deque[t.Any] = deque()
self._postinit() self._postinit()
def _postinit(self) -> None: def _postinit(self) -> None:
@ -461,7 +461,7 @@ class LRUCache:
self.__dict__.update(d) self.__dict__.update(d)
self._postinit() self._postinit()
def __getnewargs__(self) -> t.Tuple[t.Any, ...]: def __getnewargs__(self) -> tuple[t.Any, ...]:
return (self.capacity,) return (self.capacity,)
def copy(self) -> "te.Self": def copy(self) -> "te.Self":
@ -552,7 +552,7 @@ class LRUCache:
except ValueError: except ValueError:
pass 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.""" """Return a list of items."""
result = [(key, self._mapping[key]) for key in list(self._queue)] result = [(key, self._mapping[key]) for key in list(self._queue)]
result.reverse() result.reverse()

View File

@ -80,7 +80,7 @@ class NodeTransformer(NodeVisitor):
setattr(node, field, new_node) setattr(node, field, new_node)
return 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 """As transformers may return lists in some places this method
can be used to enforce a list as return value. can be used to enforce a list as return value.
""" """

View File

@ -449,9 +449,7 @@ class TestAsyncForLoop:
def test_reversed_bug(self, test_env_async): def test_reversed_bug(self, test_env_async):
tmpl = test_env_async.from_string( tmpl = test_env_async.from_string(
"{% for i in items %}{{ i }}" "{% for i in items %}{{ i }}{% if not loop.last %},{% endif %}{% endfor %}"
"{% if not loop.last %}"
",{% endif %}{% endfor %}"
) )
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3" assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"

View File

@ -191,9 +191,7 @@ class TestForLoop:
def test_reversed_bug(self, env): def test_reversed_bug(self, env):
tmpl = env.from_string( tmpl = env.from_string(
"{% for i in items %}{{ i }}" "{% for i in items %}{{ i }}{% if not loop.last %},{% endif %}{% endfor %}"
"{% if not loop.last %}"
",{% endif %}{% endfor %}"
) )
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3" assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"

View File

@ -23,9 +23,9 @@ class TestDebug:
tb = format_exception(exc_info.type, exc_info.value, exc_info.tb) tb = format_exception(exc_info.type, exc_info.value, exc_info.tb)
m = re.search(expected_tb.strip(), "".join(tb)) m = re.search(expected_tb.strip(), "".join(tb))
assert ( assert m is not None, (
m is not None f"Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}"
), f"Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}" )
def test_runtime_error(self, fs_env): def test_runtime_error(self, fs_env):
def test(): def test():

View File

@ -554,8 +554,7 @@ class TestNewstyleInternationalization:
newstyle=True, newstyle=True,
) )
t = env.from_string( t = env.from_string(
'{% autoescape ae %}{{ gettext("foo", name=' '{% autoescape ae %}{{ gettext("foo", name="<test>") }}{% endautoescape %}'
'"<test>") }}{% endautoescape %}'
) )
assert t.render(ae=True) == "<strong>Wert: &lt;test&gt;</strong>" assert t.render(ae=True) == "<strong>Wert: &lt;test&gt;</strong>"
assert t.render(ae=False) == "<strong>Wert: <test></strong>" assert t.render(ae=False) == "<strong>Wert: <test></strong>"

View File

@ -357,7 +357,7 @@ class TestFilter:
def test_urlize(self, env): def test_urlize(self, env):
tmpl = env.from_string('{{ "foo example.org bar"|urlize }}') tmpl = env.from_string('{{ "foo example.org bar"|urlize }}')
assert tmpl.render() == ( 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 }}') tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
assert tmpl.render() == ( assert tmpl.render() == (

View File

@ -43,8 +43,7 @@ class TestTokenStream:
class TestLexer: class TestLexer:
def test_raw1(self, env): def test_raw1(self, env):
tmpl = env.from_string( tmpl = env.from_string(
"{% raw %}foo{% endraw %}|" "{% raw %}foo{% endraw %}|{%raw%}{{ bar }}|{% baz %}{% endraw %}"
"{%raw%}{{ bar }}|{% baz %}{% endraw %}"
) )
assert tmpl.render() == "foo|{{ bar }}|{% baz %}" assert tmpl.render() == "foo|{{ bar }}|{% baz %}"