From: Adam Englander Date: Wed, 28 May 2025 17:06:54 +0000 (-0700) Subject: fix type/lint/format findings X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2093%2Fhead;p=thirdparty%2Fjinja.git fix type/lint/format findings --- diff --git a/src/jinja2/async_utils.py b/src/jinja2/async_utils.py index f0c14020..182ffb0a 100644 --- a/src/jinja2/async_utils.py +++ b/src/jinja2/async_utils.py @@ -95,5 +95,5 @@ def auto_aiter( async def auto_to_list( value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", -) -> t.List["V"]: +) -> list["V"]: return [x async for x in auto_aiter(value)] diff --git a/src/jinja2/compiler.py b/src/jinja2/compiler.py index a4ff6a1b..3931ff0d 100644 --- a/src/jinja2/compiler.py +++ b/src/jinja2/compiler.py @@ -139,9 +139,7 @@ def has_safe_repr(value: t.Any) -> bool: return False -def find_undeclared( - nodes: t.Iterable[nodes.Node], names: t.Iterable[str] -) -> t.Set[str]: +def find_undeclared(nodes: t.Iterable[nodes.Node], names: t.Iterable[str]) -> set[str]: """Check if the names passed are accessed undeclared. The return value is a set of all the undeclared names from the sequence of names found. """ @@ -253,8 +251,8 @@ class DependencyFinderVisitor(NodeVisitor): """A visitor that collects filter and test calls.""" def __init__(self) -> None: - self.filters: t.Set[str] = set() - self.tests: t.Set[str] = set() + self.filters: set[str] = set() + self.tests: set[str] = set() def visit_Filter(self, node: nodes.Filter) -> None: self.generic_visit(node) @@ -276,7 +274,7 @@ class UndeclaredNameVisitor(NodeVisitor): def __init__(self, names: t.Iterable[str]) -> None: self.names = set(names) - self.undeclared: t.Set[str] = set() + self.undeclared: set[str] = set() def visit_Name(self, node: nodes.Name) -> None: if node.ctx == "load" and node.name in self.names: @@ -321,11 +319,11 @@ class CodeGenerator(NodeVisitor): self.optimizer = Optimizer(environment) # aliases for imports - self.import_aliases: t.Dict[str, str] = {} + self.import_aliases: dict[str, str] = {} # a registry for all blocks. Because blocks are moved out # into the global python scope they are registered here - self.blocks: t.Dict[str, nodes.Block] = {} + self.blocks: dict[str, nodes.Block] = {} # the number of extends statements so far self.extends_so_far = 0 @@ -339,11 +337,11 @@ class CodeGenerator(NodeVisitor): self.code_lineno = 1 # registry of all filters and tests (global, not block local) - self.tests: t.Dict[str, str] = {} - self.filters: t.Dict[str, str] = {} + self.tests: dict[str, str] = {} + self.filters: dict[str, str] = {} # the debug information - self.debug_info: t.List[t.Tuple[int, int]] = [] + self.debug_info: list[tuple[int, int]] = [] self._write_debug_info: t.Optional[int] = None # the number of new lines before the next write() @@ -363,10 +361,10 @@ class CodeGenerator(NodeVisitor): self._indentation = 0 # Tracks toplevel assignments - self._assign_stack: t.List[t.Set[str]] = [] + self._assign_stack: list[set[str]] = [] # Tracks parameter definition blocks - self._param_def_block: t.List[t.Set[str]] = [] + self._param_def_block: list[set[str]] = [] # Tracks the current context. self._context_reference_stack = ["context"] @@ -613,7 +611,7 @@ class CodeGenerator(NodeVisitor): def macro_body( self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame - ) -> t.Tuple[Frame, MacroRef]: + ) -> tuple[Frame, MacroRef]: """Dump the function def of a macro or call block.""" frame = frame.inner() frame.symbols.analyze_node(node) @@ -1511,7 +1509,7 @@ class CodeGenerator(NodeVisitor): self.indent() finalize = self._make_finalize() - body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = [] + body: list[t.Union[list[t.Any], nodes.Expr]] = [] # Evaluate constants at compile time if possible. Each item in # body will be either a list of static data or a node to be @@ -1586,7 +1584,7 @@ class CodeGenerator(NodeVisitor): # it is only valid if it references a Namespace object. Emit a check for # that for each ref here, before assignment code is emitted. This can't # be done in visit_NSRef as the ref could be in the middle of a tuple. - seen_refs: t.Set[str] = set() + seen_refs: set[str] = set() for nsref in node.find_all(nodes.NSRef): if nsref.name in seen_refs: diff --git a/src/jinja2/debug.py b/src/jinja2/debug.py index f85a319e..41265d4f 100644 --- a/src/jinja2/debug.py +++ b/src/jinja2/debug.py @@ -128,7 +128,7 @@ def fake_traceback( # 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 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") if ctx is not None: - data: t.Dict[str, t.Any] = ctx.get_all().copy() + data: dict[str, t.Any] = ctx.get_all().copy() else: data = {} @@ -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 # l_depth_name. Find the highest-depth local that has a value for # each name. - local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} + local_overrides: dict[str, tuple[int, t.Any]] = {} for name, value in real_locals.items(): if not name.startswith("l_") or value is missing: diff --git a/src/jinja2/defaults.py b/src/jinja2/defaults.py index 638cad3d..b698c67e 100644 --- a/src/jinja2/defaults.py +++ b/src/jinja2/defaults.py @@ -36,7 +36,7 @@ DEFAULT_NAMESPACE = { } # default policies -DEFAULT_POLICIES: t.Dict[str, t.Any] = { +DEFAULT_POLICIES: dict[str, t.Any] = { "compiler.ascii_str": True, "urlize.rel": "noopener", "urlize.target": None, diff --git a/src/jinja2/environment.py b/src/jinja2/environment.py index a99cc2d1..af6420b7 100644 --- a/src/jinja2/environment.py +++ b/src/jinja2/environment.py @@ -66,7 +66,7 @@ _env_bound = t.TypeVar("_env_bound", bound="Environment") # for direct template usage we have up to ten living environments @lru_cache(maxsize=10) -def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: +def get_spontaneous_environment(cls: type[_env_bound], *args: t.Any) -> _env_bound: """Return a new spontaneous environment. A spontaneous environment is used for templates created directly rather than through an existing environment. @@ -81,7 +81,7 @@ def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_b def create_cache( size: int, -) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[BaseLoader]", str], "Template"]]: +) -> t.Optional[t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]]: """Return the cache class for the given size.""" if size == 0: return None @@ -94,9 +94,9 @@ def create_cache( def copy_cache( cache: t.Optional[ - t.MutableMapping[t.Tuple["weakref.ref[BaseLoader]", str], "Template"] + t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"] ], -) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[BaseLoader]", str], "Template"]]: +) -> t.Optional[t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]]: """Create an empty copy of the given cache.""" if cache is None: return None @@ -109,8 +109,8 @@ def copy_cache( def load_extensions( environment: "Environment", - extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], -) -> t.Dict[str, "Extension"]: + extensions: t.Sequence[t.Union[str, type["Extension"]]], +) -> dict[str, "Extension"]: """Load the extensions from the list and bind it to the environment. Returns a dict of instantiated extensions. """ @@ -118,7 +118,7 @@ def load_extensions( for extension in extensions: if isinstance(extension, str): - extension = t.cast(t.Type["Extension"], import_string(extension)) + extension = t.cast(type["Extension"], import_string(extension)) result[extension.identifier] = extension(environment) @@ -127,9 +127,9 @@ def load_extensions( def _environment_config_check(environment: _env_bound) -> _env_bound: """Perform a sanity check on the environment.""" - assert issubclass( - environment.undefined, Undefined - ), "'undefined' must be a subclass of 'jinja2.Undefined'." + assert issubclass(environment.undefined, Undefined), ( + "'undefined' must be a subclass of 'jinja2.Undefined'." + ) assert ( environment.block_start_string != environment.variable_start_string @@ -283,15 +283,15 @@ class Environment: #: the class that is used for code generation. See #: :class:`~jinja2.compiler.CodeGenerator` for more information. - code_generator_class: t.Type["CodeGenerator"] = CodeGenerator + code_generator_class: type["CodeGenerator"] = CodeGenerator concat = "".join #: the context class that is used for templates. See #: :class:`~jinja2.runtime.Context` for more information. - context_class: t.Type[Context] = Context + context_class: type[Context] = Context - template_class: t.Type["Template"] + template_class: type["Template"] def __init__( self, @@ -307,9 +307,9 @@ class Environment: lstrip_blocks: bool = LSTRIP_BLOCKS, newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, - extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + extensions: t.Sequence[t.Union[str, type["Extension"]]] = (), optimized: bool = True, - undefined: t.Type[Undefined] = Undefined, + undefined: type[Undefined] = Undefined, finalize: t.Optional[t.Callable[..., t.Any]] = None, autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, loader: t.Optional["BaseLoader"] = None, @@ -344,7 +344,7 @@ class Environment: self.keep_trailing_newline = keep_trailing_newline # runtime information - self.undefined: t.Type[Undefined] = undefined + self.undefined: type[Undefined] = undefined self.optimized = optimized self.finalize = finalize self.autoescape = autoescape @@ -369,7 +369,7 @@ class Environment: self.is_async = enable_async _environment_config_check(self) - def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: + def add_extension(self, extension: t.Union[str, type["Extension"]]) -> None: """Adds an extension after the environment was created. .. versionadded:: 2.5 @@ -399,9 +399,9 @@ class Environment: lstrip_blocks: bool = missing, newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, keep_trailing_newline: bool = missing, - extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, + extensions: t.Sequence[t.Union[str, type["Extension"]]] = missing, optimized: bool = missing, - undefined: t.Type[Undefined] = missing, + undefined: type[Undefined] = missing, finalize: t.Optional[t.Callable[..., t.Any]] = missing, autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, loader: t.Optional["BaseLoader"] = missing, @@ -628,7 +628,7 @@ class Environment: source: str, name: t.Optional[str] = None, filename: t.Optional[str] = None, - ) -> t.Iterator[t.Tuple[int, str, str]]: + ) -> t.Iterator[tuple[int, str, str]]: """Lex the given sourcecode and return a generator that yields tokens as tuples in the form ``(lineno, token_type, value)``. This can be useful for :ref:`extension development ` @@ -677,7 +677,7 @@ class Environment: stream = ext.filter_stream(stream) # type: ignore if not isinstance(stream, TokenStream): - stream = TokenStream(stream, name, filename) # type: ignore[unreachable] + stream = TokenStream(stream, name, filename) return stream @@ -902,7 +902,7 @@ class Environment: self, extensions: t.Optional[t.Collection[str]] = None, filter_func: t.Optional[t.Callable[[str], bool]] = None, - ) -> t.List[str]: + ) -> list[str]: """Returns a list of templates for this environment. This requires that the loader supports the loader's :meth:`~BaseLoader.list_templates` method. @@ -1074,9 +1074,7 @@ class Environment: @internalcode def get_or_select_template( self, - template_name_or_list: t.Union[ - str, "Template", t.List[t.Union[str, "Template"]] - ], + template_name_or_list: t.Union[str, "Template", list[t.Union[str, "Template"]]], parent: t.Optional[str] = None, globals: t.Optional[t.MutableMapping[str, t.Any]] = None, ) -> "Template": @@ -1095,7 +1093,7 @@ class Environment: self, source: t.Union[str, nodes.Template], globals: t.Optional[t.MutableMapping[str, t.Any]] = None, - template_class: t.Optional[t.Type["Template"]] = None, + template_class: t.Optional[type["Template"]] = None, ) -> "Template": """Load a template from a source string without using :attr:`loader`. @@ -1154,13 +1152,13 @@ class Template: #: Type of environment to create when creating a template directly #: rather than through an existing environment. - environment_class: t.Type[Environment] = Environment + environment_class: type[Environment] = Environment environment: Environment globals: t.MutableMapping[str, t.Any] name: t.Optional[str] filename: t.Optional[str] - blocks: t.Dict[str, t.Callable[[Context], t.Iterator[str]]] + blocks: dict[str, t.Callable[[Context], t.Iterator[str]]] root_render_func: t.Callable[[Context], t.Iterator[str]] _module: t.Optional["TemplateModule"] _debug_info: str @@ -1181,9 +1179,9 @@ class Template: lstrip_blocks: bool = LSTRIP_BLOCKS, newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, - extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + extensions: t.Sequence[t.Union[str, type["Extension"]]] = (), optimized: bool = True, - undefined: t.Type[Undefined] = Undefined, + undefined: type[Undefined] = Undefined, finalize: t.Optional[t.Callable[..., t.Any]] = None, autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, enable_async: bool = False, @@ -1336,7 +1334,7 @@ class Template: if self.environment.is_async: import asyncio - async def to_list() -> t.List[str]: + async def to_list() -> list[str]: return [x async for x in self.generate_async(*args, **kwargs)] yield from asyncio.run(to_list()) @@ -1376,7 +1374,7 @@ class Template: def new_context( self, - vars: t.Optional[t.Dict[str, t.Any]] = None, + vars: t.Optional[dict[str, t.Any]] = None, shared: bool = False, locals: t.Optional[t.Mapping[str, t.Any]] = None, ) -> Context: @@ -1393,7 +1391,7 @@ class Template: def make_module( self, - vars: t.Optional[t.Dict[str, t.Any]] = None, + vars: t.Optional[dict[str, t.Any]] = None, shared: bool = False, locals: t.Optional[t.Mapping[str, t.Any]] = None, ) -> "TemplateModule": @@ -1408,7 +1406,7 @@ class Template: async def make_module_async( self, - vars: t.Optional[t.Dict[str, t.Any]] = None, + vars: t.Optional[dict[str, t.Any]] = None, shared: bool = False, locals: t.Optional[t.Mapping[str, t.Any]] = None, ) -> "TemplateModule": @@ -1498,7 +1496,7 @@ class Template: return self._uptodate() @property - def debug_info(self) -> t.List[t.Tuple[int, int]]: + def debug_info(self) -> list[tuple[int, int]]: """The debug info mapping.""" if self._debug_info: return [ @@ -1636,7 +1634,7 @@ class TemplateStream: self.buffered = False def _buffered_generator(self, size: int) -> t.Iterator[str]: - buf: t.List[str] = [] + buf: list[str] = [] c_size = 0 push = buf.append diff --git a/src/jinja2/ext.py b/src/jinja2/ext.py index d8ab7eff..1c27df94 100644 --- a/src/jinja2/ext.py +++ b/src/jinja2/ext.py @@ -42,7 +42,7 @@ if t.TYPE_CHECKING: # I18N functions available in Jinja templates. If the I18N library # provides ugettext, it will be assigned to gettext. -GETTEXT_FUNCTIONS: t.Tuple[str, ...] = ( +GETTEXT_FUNCTIONS: tuple[str, ...] = ( "_", "gettext", "ngettext", @@ -77,7 +77,7 @@ class Extension: cls.identifier = f"{cls.__module__}.{cls.__name__}" #: if this extension parses this is the list of tags it's listening to. - tags: t.Set[str] = set() + tags: set[str] = set() #: the priority of that extension. This is especially useful for #: extensions that preprocess values. A lower value means higher @@ -115,7 +115,7 @@ class Extension: """ return stream - def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]: + def parse(self, parser: "Parser") -> t.Union[nodes.Node, list[nodes.Node]]: """If any of the :attr:`tags` matched this method is called with the parser as first argument. The token the parser stream is pointing at is the name token that matched. This method has to return one or a @@ -138,8 +138,8 @@ class Extension: def call_method( self, name: str, - args: t.Optional[t.List[nodes.Expr]] = None, - kwargs: t.Optional[t.List[nodes.Keyword]] = None, + args: t.Optional[list[nodes.Expr]] = None, + kwargs: t.Optional[list[nodes.Keyword]] = None, dyn_args: t.Optional[nodes.Expr] = None, dyn_kwargs: t.Optional[nodes.Expr] = None, lineno: t.Optional[int] = None, @@ -330,13 +330,13 @@ class InternationalizationExtension(Extension): source: t.Union[str, nodes.Template], gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS, ) -> t.Iterator[ - t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]] + tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]]] ]: if isinstance(source, str): source = self.environment.parse(source) return extract_from_ast(source, gettext_functions) - def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]: + def parse(self, parser: "Parser") -> t.Union[nodes.Node, list[nodes.Node]]: """Parse a translatable tag.""" lineno = next(parser.stream).lineno @@ -352,7 +352,7 @@ class InternationalizationExtension(Extension): plural_expr: t.Optional[nodes.Expr] = None plural_expr_assignment: t.Optional[nodes.Assign] = None num_called_num = False - variables: t.Dict[str, nodes.Expr] = {} + variables: dict[str, nodes.Expr] = {} trimmed = None while parser.stream.current.type != "block_end": if variables: @@ -463,7 +463,7 @@ class InternationalizationExtension(Extension): def _parse_block( self, parser: "Parser", allow_pluralize: bool - ) -> t.Tuple[t.List[str], str]: + ) -> tuple[list[str], str]: """Parse until the next block tag with a given name.""" referenced = [] buf = [] @@ -513,7 +513,7 @@ class InternationalizationExtension(Extension): singular: str, plural: t.Optional[str], context: t.Optional[str], - variables: t.Dict[str, nodes.Expr], + variables: dict[str, nodes.Expr], plural_expr: t.Optional[nodes.Expr], vars_referenced: bool, num_called_num: bool, @@ -530,7 +530,7 @@ class InternationalizationExtension(Extension): plural = plural.replace("%%", "%") func_name = "gettext" - func_args: t.List[nodes.Expr] = [nodes.Const(singular)] + func_args: list[nodes.Expr] = [nodes.Const(singular)] if context is not None: func_args.insert(0, nodes.Const(context)) @@ -640,9 +640,7 @@ def extract_from_ast( ast: nodes.Template, gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS, babel_style: bool = True, -) -> t.Iterator[ - t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]] -]: +) -> t.Iterator[tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]]]]: """Extract localizable strings from the given template node. Per default this function returns matches in babel style that means non string parameters as well as keyword arguments are returned as `None`. This @@ -677,7 +675,7 @@ def extract_from_ast( to extract any comments. For comment support you have to use the babel extraction interface or extract comments yourself. """ - out: t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]] + out: t.Union[t.Optional[str], tuple[t.Optional[str], ...]] for node in ast.find_all(nodes.Call): if ( @@ -686,7 +684,7 @@ def extract_from_ast( ): continue - strings: t.List[t.Optional[str]] = [] + strings: list[t.Optional[str]] = [] for arg in node.args: if isinstance(arg, nodes.Const) and isinstance(arg.value, str): @@ -723,14 +721,14 @@ class _CommentFinder: """ def __init__( - self, tokens: t.Sequence[t.Tuple[int, str, str]], comment_tags: t.Sequence[str] + self, tokens: t.Sequence[tuple[int, str, str]], comment_tags: t.Sequence[str] ) -> None: self.tokens = tokens self.comment_tags = comment_tags self.offset = 0 self.last_lineno = 0 - def find_backwards(self, offset: int) -> t.List[str]: + def find_backwards(self, offset: int) -> list[str]: try: for _, token_type, token_value in reversed( self.tokens[self.offset : offset] @@ -746,7 +744,7 @@ class _CommentFinder: finally: self.offset = offset - def find_comments(self, lineno: int) -> t.List[str]: + def find_comments(self, lineno: int) -> list[str]: if not self.comment_tags or self.last_lineno > lineno: return [] for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]): @@ -759,11 +757,9 @@ def babel_extract( fileobj: t.BinaryIO, keywords: t.Sequence[str], comment_tags: t.Sequence[str], - options: t.Dict[str, t.Any], + options: dict[str, t.Any], ) -> t.Iterator[ - t.Tuple[ - int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]], t.List[str] - ] + tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]], list[str]] ]: """Babel extraction method for Jinja templates. @@ -792,7 +788,7 @@ def babel_extract( :return: an iterator over ``(lineno, funcname, message, comments)`` tuples. (comments will be empty currently) """ - extensions: t.Dict[t.Type[Extension], None] = {} + extensions: dict[type[Extension], None] = {} for extension_name in options.get("extensions", "").split(","): extension_name = extension_name.strip() diff --git a/src/jinja2/filters.py b/src/jinja2/filters.py index 2bcba4fb..73a0cdce 100644 --- a/src/jinja2/filters.py +++ b/src/jinja2/filters.py @@ -87,7 +87,7 @@ def make_multi_attrgetter( environment: "Environment", attribute: t.Optional[t.Union[str, int]], postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, -) -> t.Callable[[t.Any], t.List[t.Any]]: +) -> t.Callable[[t.Any], list[t.Any]]: """Returns a callable that looks up the given comma separated attributes from a passed object with the rules of the environment. Dots are allowed to access attributes of each attribute. Integer @@ -105,7 +105,7 @@ def make_multi_attrgetter( parts = [_prepare_attribute_parts(item) for item in split] - def attrgetter(item: t.Any) -> t.List[t.Any]: + def attrgetter(item: t.Any) -> list[t.Any]: items = [None] * len(parts) for i, attribute_part in enumerate(parts): @@ -126,7 +126,7 @@ def make_multi_attrgetter( def _prepare_attribute_parts( attr: t.Optional[t.Union[str, int]], -) -> t.List[t.Union[str, int]]: +) -> list[t.Union[str, int]]: if attr is None: return [] @@ -145,7 +145,7 @@ def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup: def do_urlencode( - value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[t.Tuple[str, t.Any]]], + value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[tuple[str, t.Any]]], ) -> str: """Quote data for use in a URL path or query using UTF-8. @@ -166,7 +166,7 @@ def do_urlencode( return url_quote(value) if isinstance(value, dict): - items: t.Iterable[t.Tuple[str, t.Any]] = value.items() + items: t.Iterable[tuple[str, t.Any]] = value.items() else: items = value # type: ignore @@ -221,7 +221,7 @@ def do_lower(s: str) -> str: return soft_str(s).lower() -def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]: +def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[tuple[K, V]]: """Return an iterator over the ``(key, value)`` items of a mapping. ``x|items`` is the same as ``x.items()``, except if ``x`` is @@ -346,7 +346,7 @@ def do_dictsort( case_sensitive: bool = False, by: 'te.Literal["key", "value"]' = "key", reverse: bool = False, -) -> t.List[t.Tuple[K, V]]: +) -> list[tuple[K, V]]: """Sort a dict and yield (key, value) pairs. Python dicts may not be in the order you want to display them in, so sort them first. @@ -371,7 +371,7 @@ def do_dictsort( else: raise FilterArgumentError('You can only sort by either "key" or "value"') - def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any: + def sort_func(item: tuple[t.Any, t.Any]) -> t.Any: value = item[pos] if not case_sensitive: @@ -389,7 +389,7 @@ def do_sort( reverse: bool = False, case_sensitive: bool = False, attribute: t.Optional[t.Union[str, int]] = None, -) -> "t.List[V]": +) -> "list[V]": """Sort an iterable using Python's :func:`sorted`. .. sourcecode:: jinja @@ -1058,7 +1058,7 @@ def do_striptags(value: "t.Union[str, HasHTML]") -> str: def sync_do_slice( value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None -) -> "t.Iterator[t.List[V]]": +) -> "t.Iterator[list[V]]": """Slice an iterator and return a list of lists containing those items. Useful if you want to create a div containing three ul tags that represent columns: @@ -1104,13 +1104,13 @@ async def do_slice( value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", slices: int, fill_with: t.Optional[t.Any] = None, -) -> "t.Iterator[t.List[V]]": +) -> "t.Iterator[list[V]]": return sync_do_slice(await auto_to_list(value), slices, fill_with) def do_batch( value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None -) -> "t.Iterator[t.List[V]]": +) -> "t.Iterator[list[V]]": """ A filter that batches items. It works pretty much like `slice` just the other way round. It returns a list of lists with the @@ -1129,7 +1129,7 @@ def do_batch( {%- endfor %} """ - tmp: t.List[V] = [] + tmp: list[V] = [] for item in value: if len(tmp) == linecount: @@ -1187,7 +1187,7 @@ def do_round( class _GroupTuple(t.NamedTuple): grouper: t.Any - list: t.List[t.Any] + list: list[t.Any] # Use the regular tuple repr to hide this subclass if users print # out the value during debugging. @@ -1205,7 +1205,7 @@ def sync_do_groupby( attribute: t.Union[str, int], default: t.Optional[t.Any] = None, case_sensitive: bool = False, -) -> "t.List[_GroupTuple]": +) -> "list[_GroupTuple]": """Group a sequence of objects by an attribute using Python's :func:`itertools.groupby`. The attribute can use dot notation for nested access, like ``"address.city"``. Unlike Python's ``groupby``, @@ -1289,7 +1289,7 @@ async def do_groupby( attribute: t.Union[str, int], default: t.Optional[t.Any] = None, case_sensitive: bool = False, -) -> "t.List[_GroupTuple]": +) -> "list[_GroupTuple]": expr = make_attrgetter( environment, attribute, @@ -1358,7 +1358,7 @@ async def do_sum( return rv -def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]": +def sync_do_list(value: "t.Iterable[V]") -> "list[V]": """Convert the value into a list. If it was a string the returned list will be a list of characters. """ @@ -1366,7 +1366,7 @@ def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]": @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) @@ -1722,7 +1722,7 @@ def do_tojson( def prepare_map( - context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any] + context: "Context", args: tuple[t.Any, ...], kwargs: dict[str, t.Any] ) -> t.Callable[[t.Any], t.Any]: if not args and "attribute" in kwargs: attribute = kwargs.pop("attribute") @@ -1751,8 +1751,8 @@ def prepare_map( def prepare_select_or_reject( context: "Context", - args: t.Tuple[t.Any, ...], - kwargs: t.Dict[str, t.Any], + args: tuple[t.Any, ...], + kwargs: dict[str, t.Any], modfunc: t.Callable[[t.Any], t.Any], lookup_attr: bool, ) -> t.Callable[[t.Any], t.Any]: @@ -1786,8 +1786,8 @@ def prepare_select_or_reject( def select_or_reject( context: "Context", value: "t.Iterable[V]", - args: t.Tuple[t.Any, ...], - kwargs: t.Dict[str, t.Any], + args: tuple[t.Any, ...], + kwargs: dict[str, t.Any], modfunc: t.Callable[[t.Any], t.Any], lookup_attr: bool, ) -> "t.Iterator[V]": @@ -1802,8 +1802,8 @@ def select_or_reject( async def async_select_or_reject( context: "Context", value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", - args: t.Tuple[t.Any, ...], - kwargs: t.Dict[str, t.Any], + args: tuple[t.Any, ...], + kwargs: dict[str, t.Any], modfunc: t.Callable[[t.Any], t.Any], lookup_attr: bool, ) -> "t.AsyncIterator[V]": diff --git a/src/jinja2/idtracking.py b/src/jinja2/idtracking.py index e6dd8cd1..d04c6d7f 100644 --- a/src/jinja2/idtracking.py +++ b/src/jinja2/idtracking.py @@ -42,16 +42,16 @@ class Symbols: self.level: int = level self.parent = parent - self.refs: t.Dict[str, str] = {} - self.loads: t.Dict[str, t.Any] = {} - self.stores: t.Set[str] = set() + self.refs: dict[str, str] = {} + self.loads: dict[str, t.Any] = {} + self.stores: set[str] = set() def analyze_node(self, node: nodes.Node, **kwargs: t.Any) -> None: visitor = RootVisitor(self) visitor.visit(node, **kwargs) def _define_ref( - self, name: str, load: t.Optional[t.Tuple[str, t.Optional[str]]] = None + self, name: str, load: t.Optional[tuple[str, t.Optional[str]]] = None ) -> str: ident = f"l_{self.level}_{name}" self.refs[name] = ident @@ -121,7 +121,7 @@ class Symbols: self._define_ref(name, load=(VAR_LOAD_RESOLVE, name)) def branch_update(self, branch_symbols: t.Sequence["Symbols"]) -> None: - stores: t.Set[str] = set() + stores: set[str] = set() for branch in branch_symbols: stores.update(branch.stores) @@ -144,8 +144,8 @@ class Symbols: continue self.loads[target] = (VAR_LOAD_RESOLVE, name) - def dump_stores(self) -> t.Dict[str, str]: - rv: t.Dict[str, str] = {} + def dump_stores(self) -> dict[str, str]: + rv: dict[str, str] = {} node: t.Optional[Symbols] = self while node is not None: @@ -157,7 +157,7 @@ class Symbols: return rv - def dump_param_targets(self) -> t.Set[str]: + def dump_param_targets(self) -> set[str]: rv = set() node: t.Optional[Symbols] = self diff --git a/src/jinja2/lexer.py b/src/jinja2/lexer.py index 9b1c9697..d96e9a08 100644 --- a/src/jinja2/lexer.py +++ b/src/jinja2/lexer.py @@ -21,7 +21,7 @@ if t.TYPE_CHECKING: # cache for the lexers. Exists in order to be able to have multiple # environments with the same lexer -_lexer_cache: t.MutableMapping[t.Tuple, "Lexer"] = LRUCache(50) # type: ignore +_lexer_cache: t.MutableMapping[tuple, "Lexer"] = LRUCache(50) # type: ignore # static regular expressions whitespace_re = re.compile(r"\s+") @@ -210,7 +210,7 @@ def count_newlines(value: str) -> int: return len(newline_re.findall(value)) -def compile_rules(environment: "Environment") -> t.List[t.Tuple[str, str]]: +def compile_rules(environment: "Environment") -> list[tuple[str, str]]: """Compiles all the rules from the environment into a list of rules.""" e = re.escape rules = [ @@ -257,7 +257,7 @@ class Failure: """ def __init__( - self, message: str, cls: t.Type[TemplateSyntaxError] = TemplateSyntaxError + self, message: str, cls: type[TemplateSyntaxError] = TemplateSyntaxError ) -> None: self.message = message self.error_class = cls @@ -329,7 +329,7 @@ class TokenStream: filename: t.Optional[str], ): self._iter = iter(generator) - self._pushed: te.Deque[Token] = deque() + self._pushed: deque[Token] = deque() self.name = name self.filename = filename self.closed = False @@ -464,7 +464,7 @@ class OptionalLStrip(tuple): # type: ignore[type-arg] class _Rule(t.NamedTuple): pattern: t.Pattern[str] - tokens: t.Union[str, t.Tuple[str, ...], t.Tuple[Failure]] + tokens: t.Union[str, tuple[str, ...], tuple[Failure]] command: t.Optional[str] @@ -484,7 +484,7 @@ class Lexer: return re.compile(x, re.M | re.S) # lexing rules for tags - tag_rules: t.List[_Rule] = [ + tag_rules: list[_Rule] = [ _Rule(whitespace_re, TOKEN_WHITESPACE, None), _Rule(float_re, TOKEN_FLOAT, None), _Rule(integer_re, TOKEN_INTEGER, None), @@ -523,7 +523,7 @@ class Lexer: ) # global lexing rules - self.rules: t.Dict[str, t.List[_Rule]] = { + self.rules: dict[str, list[_Rule]] = { "root": [ # directives _Rule( @@ -614,7 +614,7 @@ class Lexer: def wrap( self, - stream: t.Iterable[t.Tuple[int, str, str]], + stream: t.Iterable[tuple[int, str, str]], name: t.Optional[str] = None, filename: t.Optional[str] = None, ) -> t.Iterator[Token]: @@ -672,7 +672,7 @@ class Lexer: name: t.Optional[str], filename: t.Optional[str] = None, state: t.Optional[str] = None, - ) -> t.Iterator[t.Tuple[int, str, str]]: + ) -> t.Iterator[tuple[int, str, str]]: """This method tokenizes the text and returns the tokens in a generator. Use this method if you just want to tokenize a template. @@ -696,7 +696,7 @@ class Lexer: statetokens = self.rules[stack[-1]] source_length = len(source) - balancing_stack: t.List[str] = [] + balancing_stack: list[str] = [] newlines_stripped = 0 line_starting = True diff --git a/src/jinja2/loaders.py b/src/jinja2/loaders.py index 725ecfcd..e14613f7 100644 --- a/src/jinja2/loaders.py +++ b/src/jinja2/loaders.py @@ -22,7 +22,7 @@ if t.TYPE_CHECKING: from .environment import Template -def split_template_path(template: str) -> t.List[str]: +def split_template_path(template: str) -> list[str]: """Split a path into segments and perform a sanity check. If it detects '..' in the path it will raise a `TemplateNotFound` error. """ @@ -74,7 +74,7 @@ class BaseLoader: def get_source( self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: """Get the template source, filename and reload helper for a template. It's passed the environment and template name and has to return a tuple in the form ``(source, filename, uptodate)`` or raise a @@ -98,7 +98,7 @@ class BaseLoader: ) raise TemplateNotFound(template) - def list_templates(self) -> t.List[str]: + def list_templates(self) -> list[str]: """Iterates over all templates. If the loader does not support that it should raise a :exc:`TypeError` which is the default behavior. """ @@ -193,7 +193,7 @@ class FileSystemLoader(BaseLoader): def get_source( self, environment: "Environment", template: str - ) -> t.Tuple[str, str, t.Callable[[], bool]]: + ) -> tuple[str, str, t.Callable[[], bool]]: pieces = split_template_path(template) for searchpath in self.searchpath: @@ -225,7 +225,7 @@ class FileSystemLoader(BaseLoader): # Use normpath to convert Windows altsep to sep. return contents, os.path.normpath(filename), uptodate - def list_templates(self) -> t.List[str]: + def list_templates(self) -> list[str]: found = set() for searchpath in self.searchpath: walk_dir = os.walk(searchpath, followlinks=self.followlinks) @@ -245,24 +245,23 @@ class FileSystemLoader(BaseLoader): if sys.version_info >= (3, 13): - def _get_zipimporter_files(z: t.Any) -> t.Dict[str, object]: + def _get_zipimporter_files(z: t.Any) -> dict[str, object]: try: get_files = z._get_files except AttributeError as e: raise TypeError( - "This zip import does not have the required" - " metadata to list templates." + "This zip import does not have the required metadata to list templates." ) from e return get_files() + else: - def _get_zipimporter_files(z: t.Any) -> t.Dict[str, object]: + def _get_zipimporter_files(z: t.Any) -> dict[str, object]: try: files = z._files except AttributeError as e: raise TypeError( - "This zip import does not have the required" - " metadata to list templates." + "This zip import does not have the required metadata to list templates." ) from e return files # type: ignore[no-any-return] @@ -333,7 +332,7 @@ class PackageLoader(BaseLoader): pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore template_root = os.path.join(pkgdir, package_path).rstrip(os.sep) else: - roots: t.List[str] = [] + roots: list[str] = [] # One element for regular packages, multiple for namespace # packages, or None for single module file. @@ -365,7 +364,7 @@ class PackageLoader(BaseLoader): def get_source( self, environment: "Environment", template: str - ) -> t.Tuple[str, str, t.Optional[t.Callable[[], bool]]]: + ) -> tuple[str, str, t.Optional[t.Callable[[], bool]]]: # Use posixpath even on Windows to avoid "drive:" or UNC # segments breaking out of the search directory. Use normpath to # convert Windows altsep to sep. @@ -401,8 +400,8 @@ class PackageLoader(BaseLoader): return source.decode(self.encoding), p, up_to_date - def list_templates(self) -> t.List[str]: - results: t.List[str] = [] + def list_templates(self) -> list[str]: + results: list[str] = [] if self._archive is None: # Package is a directory. @@ -444,13 +443,13 @@ class DictLoader(BaseLoader): def get_source( self, environment: "Environment", template: str - ) -> t.Tuple[str, None, t.Callable[[], bool]]: + ) -> tuple[str, None, t.Callable[[], bool]]: if template in self.mapping: source = self.mapping[template] return source, None, lambda: source == self.mapping.get(template) raise TemplateNotFound(template) - def list_templates(self) -> t.List[str]: + def list_templates(self) -> list[str]: return sorted(self.mapping) @@ -478,7 +477,7 @@ class FunctionLoader(BaseLoader): [str], t.Optional[ t.Union[ - str, t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]] + str, tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]] ] ], ], @@ -487,7 +486,7 @@ class FunctionLoader(BaseLoader): def get_source( self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: rv = self.load_func(template) if rv is None: @@ -520,7 +519,7 @@ class PrefixLoader(BaseLoader): self.mapping = mapping self.delimiter = delimiter - def get_loader(self, template: str) -> t.Tuple[BaseLoader, str]: + def get_loader(self, template: str) -> tuple[BaseLoader, str]: try: prefix, name = template.split(self.delimiter, 1) loader = self.mapping[prefix] @@ -530,7 +529,7 @@ class PrefixLoader(BaseLoader): def get_source( self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: loader, name = self.get_loader(template) try: return loader.get_source(environment, name) @@ -554,7 +553,7 @@ class PrefixLoader(BaseLoader): # (the one that includes the prefix) raise TemplateNotFound(name) from e - def list_templates(self) -> t.List[str]: + def list_templates(self) -> list[str]: result = [] for prefix, loader in self.mapping.items(): for template in loader.list_templates(): @@ -581,7 +580,7 @@ class ChoiceLoader(BaseLoader): def get_source( self, environment: "Environment", template: str - ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: + ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]: for loader in self.loaders: try: return loader.get_source(environment, template) @@ -603,7 +602,7 @@ class ChoiceLoader(BaseLoader): pass raise TemplateNotFound(name) - def list_templates(self) -> t.List[str]: + def list_templates(self) -> list[str]: found = set() for loader in self.loaders: found.update(loader.list_templates()) diff --git a/src/jinja2/meta.py b/src/jinja2/meta.py index 298499e2..33094812 100644 --- a/src/jinja2/meta.py +++ b/src/jinja2/meta.py @@ -17,7 +17,7 @@ class TrackingCodeGenerator(CodeGenerator): def __init__(self, environment: "Environment") -> None: super().__init__(environment, "", "") - self.undeclared_identifiers: t.Set[str] = set() + self.undeclared_identifiers: set[str] = set() def write(self, x: str) -> None: """Don't write.""" @@ -31,7 +31,7 @@ class TrackingCodeGenerator(CodeGenerator): self.undeclared_identifiers.add(param) -def find_undeclared_variables(ast: nodes.Template) -> t.Set[str]: +def find_undeclared_variables(ast: nodes.Template) -> set[str]: """Returns a set of all variables in the AST that will be looked up from the context at runtime. Because at compile time it's not known which variables will be used depending on the path the execution takes at diff --git a/src/jinja2/nodes.py b/src/jinja2/nodes.py index 2f93b90e..dc8d72ba 100644 --- a/src/jinja2/nodes.py +++ b/src/jinja2/nodes.py @@ -19,7 +19,7 @@ if t.TYPE_CHECKING: _NodeBound = t.TypeVar("_NodeBound", bound="Node") -_binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { +_binop_to_func: dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { "*": operator.mul, "/": operator.truediv, "//": operator.floordiv, @@ -29,13 +29,13 @@ _binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { "-": operator.sub, } -_uaop_to_func: t.Dict[str, t.Callable[[t.Any], t.Any]] = { +_uaop_to_func: dict[str, t.Callable[[t.Any], t.Any]] = { "not": operator.not_, "+": operator.pos, "-": operator.neg, } -_cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { +_cmpop_to_func: dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { "eq": operator.eq, "ne": operator.ne, "gt": operator.gt, @@ -58,7 +58,7 @@ class NodeType(type): def __new__(mcs, name, bases, d): # type: ignore for attr in "fields", "attributes": - storage: t.List[t.Tuple[str, ...]] = [] + storage: list[tuple[str, ...]] = [] storage.extend(getattr(bases[0] if bases else object, attr, ())) storage.extend(d.get(attr, ())) assert len(bases) <= 1, "multiple inheritance not allowed" @@ -119,8 +119,8 @@ class Node(metaclass=NodeType): all nodes automatically. """ - fields: t.Tuple[str, ...] = () - attributes: t.Tuple[str, ...] = ("lineno", "environment") + fields: tuple[str, ...] = () + attributes: tuple[str, ...] = ("lineno", "environment") abstract = True lineno: int @@ -148,7 +148,7 @@ class Node(metaclass=NodeType): self, exclude: t.Optional[t.Container[str]] = None, only: t.Optional[t.Container[str]] = None, - ) -> t.Iterator[t.Tuple[str, t.Any]]: + ) -> t.Iterator[tuple[str, t.Any]]: """This method iterates over all fields that are defined and yields ``(key, value)`` tuples. Per default all fields are returned, but it's possible to limit that to some fields by providing the `only` @@ -183,7 +183,7 @@ class Node(metaclass=NodeType): elif isinstance(item, Node): yield item - def find(self, node_type: t.Type[_NodeBound]) -> t.Optional[_NodeBound]: + def find(self, node_type: type[_NodeBound]) -> t.Optional[_NodeBound]: """Find the first node of a given type. If no such node exists the return value is `None`. """ @@ -193,7 +193,7 @@ class Node(metaclass=NodeType): return None def find_all( - self, node_type: t.Union[t.Type[_NodeBound], t.Tuple[t.Type[_NodeBound], ...]] + self, node_type: t.Union[type[_NodeBound], tuple[type[_NodeBound], ...]] ) -> t.Iterator[_NodeBound]: """Find all the nodes of a given type. If the type is a tuple, the check is performed for any of the tuple items. @@ -274,7 +274,7 @@ class Node(metaclass=NodeType): _dump(value) buf.append(")") - buf: t.List[str] = [] + buf: list[str] = [] _dump(self) return "".join(buf) @@ -297,7 +297,7 @@ class Template(Node): """ fields = ("body",) - body: t.List[Node] + body: list[Node] class Output(Stmt): @@ -306,7 +306,7 @@ class Output(Stmt): """ fields = ("nodes",) - nodes: t.List["Expr"] + nodes: list["Expr"] class Extends(Stmt): @@ -328,8 +328,8 @@ class For(Stmt): fields = ("target", "iter", "body", "else_", "test", "recursive") target: Node iter: Node - body: t.List[Node] - else_: t.List[Node] + body: list[Node] + else_: list[Node] test: t.Optional[Node] recursive: bool @@ -339,9 +339,9 @@ class If(Stmt): fields = ("test", "body", "elif_", "else_") test: Node - body: t.List[Node] - elif_: t.List["If"] - else_: t.List[Node] + body: list[Node] + elif_: list["If"] + else_: list[Node] class Macro(Stmt): @@ -352,9 +352,9 @@ class Macro(Stmt): fields = ("name", "args", "defaults", "body") name: str - args: t.List["Name"] - defaults: t.List["Expr"] - body: t.List[Node] + args: list["Name"] + defaults: list["Expr"] + body: list[Node] class CallBlock(Stmt): @@ -364,16 +364,16 @@ class CallBlock(Stmt): fields = ("call", "args", "defaults", "body") call: "Call" - args: t.List["Name"] - defaults: t.List["Expr"] - body: t.List[Node] + args: list["Name"] + defaults: list["Expr"] + body: list[Node] class FilterBlock(Stmt): """Node for filter sections.""" fields = ("body", "filter") - body: t.List[Node] + body: list[Node] filter: "Filter" @@ -385,9 +385,9 @@ class With(Stmt): """ fields = ("targets", "values", "body") - targets: t.List["Expr"] - values: t.List["Expr"] - body: t.List[Node] + targets: list["Expr"] + values: list["Expr"] + body: list[Node] class Block(Stmt): @@ -399,7 +399,7 @@ class Block(Stmt): fields = ("name", "body", "scoped", "required") name: str - body: t.List[Node] + body: list[Node] scoped: bool required: bool @@ -436,7 +436,7 @@ class FromImport(Stmt): fields = ("template", "names", "with_context") template: "Expr" - names: t.List[t.Union[str, t.Tuple[str, str]]] + names: list[t.Union[str, tuple[str, str]]] with_context: bool @@ -461,7 +461,7 @@ class AssignBlock(Stmt): fields = ("target", "filter", "body") target: "Expr" filter: t.Optional["Filter"] - body: t.List[Node] + body: list[Node] class Expr(Node): @@ -627,10 +627,10 @@ class Tuple(Literal): """ fields = ("items", "ctx") - items: t.List[Expr] + items: list[Expr] ctx: str - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[t.Any, ...]: + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[t.Any, ...]: eval_ctx = get_eval_context(self, eval_ctx) return tuple(x.as_const(eval_ctx) for x in self.items) @@ -645,9 +645,9 @@ class List(Literal): """Any list literal such as ``[1, 2, 3]``""" fields = ("items",) - items: t.List[Expr] + items: list[Expr] - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.List[t.Any]: + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> list[t.Any]: eval_ctx = get_eval_context(self, eval_ctx) return [x.as_const(eval_ctx) for x in self.items] @@ -658,11 +658,9 @@ class Dict(Literal): """ fields = ("items",) - items: t.List["Pair"] + items: list["Pair"] - def as_const( - self, eval_ctx: t.Optional[EvalContext] = None - ) -> t.Dict[t.Any, t.Any]: + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> dict[t.Any, t.Any]: eval_ctx = get_eval_context(self, eval_ctx) return dict(x.as_const(eval_ctx) for x in self.items) @@ -674,9 +672,7 @@ class Pair(Helper): key: Expr value: Expr - def as_const( - self, eval_ctx: t.Optional[EvalContext] = None - ) -> t.Tuple[t.Any, t.Any]: + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[t.Any, t.Any]: eval_ctx = get_eval_context(self, eval_ctx) return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx) @@ -688,7 +684,7 @@ class Keyword(Helper): key: str value: Expr - def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[str, t.Any]: + def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[str, t.Any]: eval_ctx = get_eval_context(self, eval_ctx) return self.key, self.value.as_const(eval_ctx) @@ -717,7 +713,7 @@ class CondExpr(Expr): def args_as_const( node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext] -) -> t.Tuple[t.List[t.Any], t.Dict[t.Any, t.Any]]: +) -> tuple[list[t.Any], dict[t.Any, t.Any]]: args = [x.as_const(eval_ctx) for x in node.args] kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs) @@ -740,8 +736,8 @@ class _FilterTestCommon(Expr): fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs") node: Expr name: str - args: t.List[Expr] - kwargs: t.List[Pair] + args: list[Expr] + kwargs: list[Pair] dyn_args: t.Optional[Expr] dyn_kwargs: t.Optional[Expr] abstract = True @@ -824,8 +820,8 @@ class Call(Expr): fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs") node: Expr - args: t.List[Expr] - kwargs: t.List[Keyword] + args: list[Expr] + kwargs: list[Keyword] dyn_args: t.Optional[Expr] dyn_kwargs: t.Optional[Expr] @@ -901,7 +897,7 @@ class Concat(Expr): """ fields = ("nodes",) - nodes: t.List[Expr] + nodes: list[Expr] def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str: eval_ctx = get_eval_context(self, eval_ctx) @@ -915,7 +911,7 @@ class Compare(Expr): fields = ("expr", "ops") expr: Expr - ops: t.List["Operand"] + ops: list["Operand"] def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any: eval_ctx = get_eval_context(self, eval_ctx) @@ -1152,7 +1148,7 @@ class Scope(Stmt): """An artificial scope.""" fields = ("body",) - body: t.List[Node] + body: list[Node] class OverlayScope(Stmt): @@ -1171,7 +1167,7 @@ class OverlayScope(Stmt): fields = ("context", "body") context: Expr - body: t.List[Node] + body: list[Node] class EvalContextModifier(Stmt): @@ -1184,7 +1180,7 @@ class EvalContextModifier(Stmt): """ fields = ("options",) - options: t.List[Keyword] + options: list[Keyword] class ScopedEvalContextModifier(EvalContextModifier): @@ -1194,7 +1190,7 @@ class ScopedEvalContextModifier(EvalContextModifier): """ fields = ("body",) - body: t.List[Node] + body: list[Node] # make sure nobody creates custom nodes diff --git a/src/jinja2/parser.py b/src/jinja2/parser.py index 5f6dfa89..d119507d 100644 --- a/src/jinja2/parser.py +++ b/src/jinja2/parser.py @@ -35,7 +35,7 @@ _statement_keywords = frozenset( ) _compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"]) -_math_nodes: t.Dict[str, t.Type[nodes.Expr]] = { +_math_nodes: dict[str, type[nodes.Expr]] = { "add": nodes.Add, "sub": nodes.Sub, "mul": nodes.Mul, @@ -63,21 +63,21 @@ class Parser: self.name = name self.filename = filename self.closed = False - self.extensions: t.Dict[ - str, t.Callable[[Parser], t.Union[nodes.Node, t.List[nodes.Node]]] + self.extensions: dict[ + str, t.Callable[[Parser], t.Union[nodes.Node, list[nodes.Node]]] ] = {} for extension in environment.iter_extensions(): for tag in extension.tags: self.extensions[tag] = extension.parse self._last_identifier = 0 - self._tag_stack: t.List[str] = [] - self._end_token_stack: t.List[t.Tuple[str, ...]] = [] + self._tag_stack: list[str] = [] + self._end_token_stack: list[tuple[str, ...]] = [] def fail( self, msg: str, lineno: t.Optional[int] = None, - exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError, + exc: type[TemplateSyntaxError] = TemplateSyntaxError, ) -> "te.NoReturn": """Convenience method that raises `exc` with the message, passed line number or last line number as well as the current name and @@ -90,10 +90,10 @@ class Parser: def _fail_ut_eof( self, name: t.Optional[str], - end_token_stack: t.List[t.Tuple[str, ...]], + end_token_stack: list[tuple[str, ...]], lineno: t.Optional[int], ) -> "te.NoReturn": - expected: t.Set[str] = set() + expected: set[str] = set() for exprs in end_token_stack: expected.update(map(describe_token_expr, exprs)) if end_token_stack: @@ -138,7 +138,7 @@ class Parser: def fail_eof( self, - end_tokens: t.Optional[t.Tuple[str, ...]] = None, + end_tokens: t.Optional[tuple[str, ...]] = None, lineno: t.Optional[int] = None, ) -> "te.NoReturn": """Like fail_unknown_tag but for end of template situations.""" @@ -147,9 +147,7 @@ class Parser: stack.append(end_tokens) self._fail_ut_eof(None, stack, lineno) - def is_tuple_end( - self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None - ) -> bool: + def is_tuple_end(self, extra_end_rules: t.Optional[tuple[str, ...]] = None) -> bool: """Are we at the end of a tuple?""" if self.stream.current.type in ("variable_end", "block_end", "rparen"): return True @@ -164,7 +162,7 @@ class Parser: nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno) return rv - def parse_statement(self) -> t.Union[nodes.Node, t.List[nodes.Node]]: + def parse_statement(self) -> t.Union[nodes.Node, list[nodes.Node]]: """Parse a single statement.""" token = self.stream.current if token.type != "name": @@ -194,8 +192,8 @@ class Parser: self._tag_stack.pop() def parse_statements( - self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False - ) -> t.List[nodes.Node]: + self, end_tokens: tuple[str, ...], drop_needle: bool = False + ) -> list[nodes.Node]: """Parse multiple statements into a list until one of the end tokens is reached. This is used to parse the body of statements as it also parses template data if appropriate. The parser checks first if the @@ -272,8 +270,8 @@ class Parser: def parse_with(self) -> nodes.With: node = nodes.With(lineno=next(self.stream).lineno) - targets: t.List[nodes.Expr] = [] - values: t.List[nodes.Expr] = [] + targets: list[nodes.Expr] = [] + values: list[nodes.Expr] = [] while self.stream.current.type != "block_end": if targets: self.stream.expect("comma") @@ -466,7 +464,7 @@ class Parser: self, with_tuple: bool = True, name_only: bool = False, - extra_end_rules: t.Optional[t.Tuple[str, ...]] = None, + extra_end_rules: t.Optional[tuple[str, ...]] = None, with_namespace: bool = False, ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: ... @@ -474,7 +472,7 @@ class Parser: self, with_tuple: bool = True, name_only: bool = False, - extra_end_rules: t.Optional[t.Tuple[str, ...]] = None, + extra_end_rules: t.Optional[tuple[str, ...]] = None, with_namespace: bool = False, ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: """Parse an assignment target. As Jinja allows assignments to @@ -686,7 +684,7 @@ class Parser: self, simplified: bool = False, with_condexpr: bool = True, - extra_end_rules: t.Optional[t.Tuple[str, ...]] = None, + extra_end_rules: t.Optional[tuple[str, ...]] = None, explicit_parentheses: bool = False, with_namespace: bool = False, ) -> t.Union[nodes.Tuple, nodes.Expr]: @@ -720,7 +718,7 @@ class Parser: def parse() -> nodes.Expr: return self.parse_expression(with_condexpr=with_condexpr) - args: t.List[nodes.Expr] = [] + args: list[nodes.Expr] = [] is_tuple = False while True: @@ -753,7 +751,7 @@ class Parser: def parse_list(self) -> nodes.List: token = self.stream.expect("lbracket") - items: t.List[nodes.Expr] = [] + items: list[nodes.Expr] = [] while self.stream.current.type != "rbracket": if items: self.stream.expect("comma") @@ -765,7 +763,7 @@ class Parser: def parse_dict(self) -> nodes.Dict: token = self.stream.expect("lbrace") - items: t.List[nodes.Pair] = [] + items: list[nodes.Pair] = [] while self.stream.current.type != "rbrace": if items: self.stream.expect("comma") @@ -824,7 +822,7 @@ class Parser: arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) return nodes.Getitem(node, arg, "load", lineno=token.lineno) if token.type == "lbracket": - args: t.List[nodes.Expr] = [] + args: list[nodes.Expr] = [] while self.stream.current.type != "rbracket": if args: self.stream.expect("comma") @@ -839,7 +837,7 @@ class Parser: def parse_subscribed(self) -> nodes.Expr: lineno = self.stream.current.lineno - args: t.List[t.Optional[nodes.Expr]] + args: list[t.Optional[nodes.Expr]] if self.stream.current.type == "colon": next(self.stream) @@ -871,9 +869,9 @@ class Parser: def parse_call_args( self, - ) -> t.Tuple[ - t.List[nodes.Expr], - t.List[nodes.Keyword], + ) -> tuple[ + list[nodes.Expr], + list[nodes.Keyword], t.Union[nodes.Expr, None], t.Union[nodes.Expr, None], ]: @@ -967,7 +965,7 @@ class Parser: next(self.stream) name += "." + self.stream.expect("name").value dyn_args = dyn_kwargs = None - kwargs: t.List[nodes.Keyword] = [] + kwargs: list[nodes.Keyword] = [] if self.stream.current.type == "lparen": args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args() elif self.stream.current.type in { @@ -994,10 +992,10 @@ class Parser: return node def subparse( - self, end_tokens: t.Optional[t.Tuple[str, ...]] = None - ) -> t.List[nodes.Node]: - body: t.List[nodes.Node] = [] - data_buffer: t.List[nodes.Node] = [] + self, end_tokens: t.Optional[tuple[str, ...]] = None + ) -> list[nodes.Node]: + body: list[nodes.Node] = [] + data_buffer: list[nodes.Node] = [] add_data = data_buffer.append if end_tokens is not None: diff --git a/src/jinja2/runtime.py b/src/jinja2/runtime.py index da30c814..00b81e28 100644 --- a/src/jinja2/runtime.py +++ b/src/jinja2/runtime.py @@ -93,8 +93,8 @@ def str_join(seq: t.Iterable[t.Any]) -> str: def new_context( environment: "Environment", template_name: t.Optional[str], - blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]], - vars: t.Optional[t.Dict[str, t.Any]] = None, + blocks: dict[str, t.Callable[["Context"], t.Iterator[str]]], + vars: t.Optional[dict[str, t.Any]] = None, shared: bool = False, globals: t.Optional[t.MutableMapping[str, t.Any]] = None, locals: t.Optional[t.Mapping[str, t.Any]] = None, @@ -165,16 +165,16 @@ class Context: def __init__( self, environment: "Environment", - parent: t.Dict[str, t.Any], + parent: dict[str, t.Any], name: t.Optional[str], - blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]], + blocks: dict[str, t.Callable[["Context"], t.Iterator[str]]], globals: t.Optional[t.MutableMapping[str, t.Any]] = None, ): self.parent = parent - self.vars: t.Dict[str, t.Any] = {} + self.vars: dict[str, t.Any] = {} self.environment: Environment = environment self.eval_ctx = EvalContext(self.environment, name) - self.exported_vars: t.Set[str] = set() + self.exported_vars: set[str] = set() self.name = name self.globals_keys = set() if globals is None else set(globals) @@ -244,11 +244,11 @@ class Context: return missing - def get_exported(self) -> t.Dict[str, t.Any]: + def get_exported(self) -> dict[str, t.Any]: """Get a new dict with the exported variables.""" return {k: self.vars[k] for k in self.exported_vars} - def get_all(self) -> t.Dict[str, t.Any]: + def get_all(self) -> dict[str, t.Any]: """Return the complete context as dict including the exported variables. For optimizations reasons this might not return an actual copy so be careful with using it. @@ -307,7 +307,7 @@ class Context: " StopIteration exception" ) - def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context": + def derived(self, locals: t.Optional[dict[str, t.Any]] = None) -> "Context": """Internal helper function to create a derived context. This is used in situations where the system needs a new context in the same template that is independent. @@ -348,7 +348,7 @@ class BlockReference: self, name: str, context: "Context", - stack: t.List[t.Callable[["Context"], t.Iterator[str]]], + stack: list[t.Callable[["Context"], t.Iterator[str]]], depth: int, ) -> None: self.name = name @@ -408,7 +408,7 @@ class LoopContext: def __init__( self, iterable: t.Iterable[V], - undefined: t.Type["Undefined"], + undefined: type["Undefined"], recurse: t.Optional["LoopRenderFunc"] = None, depth0: int = 0, ) -> None: @@ -558,7 +558,7 @@ class LoopContext: def __iter__(self) -> "LoopContext": return self - def __next__(self) -> t.Tuple[t.Any, "LoopContext"]: + def __next__(self) -> tuple[t.Any, "LoopContext"]: if self._after is not missing: rv = self._after self._after = missing @@ -646,7 +646,7 @@ class AsyncLoopContext(LoopContext): def __aiter__(self) -> "AsyncLoopContext": return self - async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]: + async def __anext__(self) -> tuple[t.Any, "AsyncLoopContext"]: if self._after is not missing: rv = self._after self._after = missing @@ -667,7 +667,7 @@ class Macro: environment: "Environment", func: t.Callable[..., str], name: str, - arguments: t.List[str], + arguments: list[str], catch_kwargs: bool, catch_varargs: bool, caller: bool, @@ -769,7 +769,7 @@ class Macro: return self._invoke(arguments, autoescape) - async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: + async def _async_invoke(self, arguments: list[t.Any], autoescape: bool) -> str: rv = await self._func(*arguments) # type: ignore if autoescape: @@ -777,7 +777,7 @@ class Macro: return rv # type: ignore - def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: + def _invoke(self, arguments: list[t.Any], autoescape: bool) -> str: if self._environment.is_async: return self._async_invoke(arguments, autoescape) # type: ignore @@ -820,7 +820,7 @@ class Undefined: hint: t.Optional[str] = None, obj: t.Any = missing, name: t.Optional[str] = None, - exc: t.Type[TemplateRuntimeError] = UndefinedError, + exc: type[TemplateRuntimeError] = UndefinedError, ) -> None: self._undefined_hint = hint self._undefined_obj = obj @@ -910,8 +910,8 @@ class Undefined: def make_logging_undefined( - logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined -) -> t.Type[Undefined]: + logger: t.Optional["logging.Logger"] = None, base: type[Undefined] = Undefined +) -> type[Undefined]: """Given a logger object this returns a new undefined class that will log certain failures. It will log iterations and printing. If no logger is given a default logger is created. diff --git a/src/jinja2/sandbox.py b/src/jinja2/sandbox.py index 9c9dae22..1e221a83 100644 --- a/src/jinja2/sandbox.py +++ b/src/jinja2/sandbox.py @@ -25,10 +25,10 @@ F = t.TypeVar("F", bound=t.Callable[..., t.Any]) MAX_RANGE = 100000 #: Unsafe function attributes. -UNSAFE_FUNCTION_ATTRIBUTES: t.Set[str] = set() +UNSAFE_FUNCTION_ATTRIBUTES: set[str] = set() #: Unsafe method attributes. Function attributes are unsafe for methods too. -UNSAFE_METHOD_ATTRIBUTES: t.Set[str] = set() +UNSAFE_METHOD_ATTRIBUTES: set[str] = set() #: unsafe generator attributes. UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"} @@ -39,7 +39,7 @@ UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"} #: unsafe attributes on async generators UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"} -_mutable_spec: t.Tuple[t.Tuple[t.Type[t.Any], t.FrozenSet[str]], ...] = ( +_mutable_spec: tuple[tuple[type[t.Any], frozenset[str]], ...] = ( ( abc.MutableSet, frozenset( @@ -190,7 +190,7 @@ class SandboxedEnvironment(Environment): #: default callback table for the binary operators. A copy of this is #: available on each instance of a sandboxed environment as #: :attr:`binop_table` - default_binop_table: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { + default_binop_table: dict[str, t.Callable[[t.Any, t.Any], t.Any]] = { "+": operator.add, "-": operator.sub, "*": operator.mul, @@ -203,7 +203,7 @@ class SandboxedEnvironment(Environment): #: default callback table for the unary operators. A copy of this is #: available on each instance of a sandboxed environment as #: :attr:`unop_table` - default_unop_table: t.Dict[str, t.Callable[[t.Any], t.Any]] = { + default_unop_table: dict[str, t.Callable[[t.Any], t.Any]] = { "+": operator.pos, "-": operator.neg, } @@ -222,7 +222,7 @@ class SandboxedEnvironment(Environment): #: interested in. #: #: .. versionadded:: 2.6 - intercepted_binops: t.FrozenSet[str] = frozenset() + intercepted_binops: frozenset[str] = frozenset() #: a set of unary operators that should be intercepted. Each operator #: that is added to this set (empty by default) is delegated to the @@ -237,7 +237,7 @@ class SandboxedEnvironment(Environment): #: interested in. #: #: .. versionadded:: 2.6 - intercepted_unops: t.FrozenSet[str] = frozenset() + intercepted_unops: frozenset[str] = frozenset() def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: super().__init__(*args, **kwargs) @@ -357,7 +357,7 @@ class SandboxedEnvironment(Environment): if not isinstance(f_self, str): return None - str_type: t.Type[str] = type(f_self) + str_type: type[str] = type(f_self) is_format_map = value.__name__ == "format_map" formatter: SandboxedFormatter @@ -421,7 +421,7 @@ class SandboxedFormatter(Formatter): def get_field( self, field_name: str, args: t.Sequence[t.Any], kwargs: t.Mapping[str, t.Any] - ) -> t.Tuple[t.Any, str]: + ) -> tuple[t.Any, str]: first, rest = formatter_field_name_split(field_name) obj = self.get_value(first, args, kwargs) for is_attr, i in rest: diff --git a/src/jinja2/utils.py b/src/jinja2/utils.py index 7c922629..875300f5 100644 --- a/src/jinja2/utils.py +++ b/src/jinja2/utils.py @@ -438,8 +438,8 @@ class LRUCache: def __init__(self, capacity: int) -> None: self.capacity = capacity - self._mapping: t.Dict[t.Any, t.Any] = {} - self._queue: te.Deque[t.Any] = deque() + self._mapping: dict[t.Any, t.Any] = {} + self._queue: deque[t.Any] = deque() self._postinit() def _postinit(self) -> None: @@ -461,7 +461,7 @@ class LRUCache: self.__dict__.update(d) self._postinit() - def __getnewargs__(self) -> t.Tuple[t.Any, ...]: + def __getnewargs__(self) -> tuple[t.Any, ...]: return (self.capacity,) def copy(self) -> "te.Self": @@ -552,7 +552,7 @@ class LRUCache: except ValueError: pass - def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]: + def items(self) -> t.Iterable[tuple[t.Any, t.Any]]: """Return a list of items.""" result = [(key, self._mapping[key]) for key in list(self._queue)] result.reverse() diff --git a/src/jinja2/visitor.py b/src/jinja2/visitor.py index 7b8e1806..f25912e1 100644 --- a/src/jinja2/visitor.py +++ b/src/jinja2/visitor.py @@ -80,7 +80,7 @@ class NodeTransformer(NodeVisitor): setattr(node, field, new_node) return node - def visit_list(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.List[Node]: + def visit_list(self, node: Node, *args: t.Any, **kwargs: t.Any) -> list[Node]: """As transformers may return lists in some places this method can be used to enforce a list as return value. """ diff --git a/tests/test_async.py b/tests/test_async.py index 9bd9fda1..d995cd48 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -449,9 +449,7 @@ class TestAsyncForLoop: def test_reversed_bug(self, test_env_async): tmpl = test_env_async.from_string( - "{% for i in items %}{{ i }}" - "{% if not loop.last %}" - ",{% endif %}{% endfor %}" + "{% for i in items %}{{ i }}{% if not loop.last %},{% endif %}{% endfor %}" ) assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3" diff --git a/tests/test_core_tags.py b/tests/test_core_tags.py index 2d847a2c..6abbbdf3 100644 --- a/tests/test_core_tags.py +++ b/tests/test_core_tags.py @@ -191,9 +191,7 @@ class TestForLoop: def test_reversed_bug(self, env): tmpl = env.from_string( - "{% for i in items %}{{ i }}" - "{% if not loop.last %}" - ",{% endif %}{% endfor %}" + "{% for i in items %}{{ i }}{% if not loop.last %},{% endif %}{% endfor %}" ) assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3" diff --git a/tests/test_debug.py b/tests/test_debug.py index bc11f401..4d5cf3e5 100644 --- a/tests/test_debug.py +++ b/tests/test_debug.py @@ -23,9 +23,9 @@ class TestDebug: tb = format_exception(exc_info.type, exc_info.value, exc_info.tb) m = re.search(expected_tb.strip(), "".join(tb)) - assert ( - m is not None - ), f"Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}" + assert m is not None, ( + f"Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}" + ) def test_runtime_error(self, fs_env): def test(): diff --git a/tests/test_ext.py b/tests/test_ext.py index 0b48ca25..f6041216 100644 --- a/tests/test_ext.py +++ b/tests/test_ext.py @@ -554,8 +554,7 @@ class TestNewstyleInternationalization: newstyle=True, ) t = env.from_string( - '{% autoescape ae %}{{ gettext("foo", name=' - '"") }}{% endautoescape %}' + '{% autoescape ae %}{{ gettext("foo", name="") }}{% endautoescape %}' ) assert t.render(ae=True) == "Wert: <test>" assert t.render(ae=False) == "Wert: " diff --git a/tests/test_filters.py b/tests/test_filters.py index 2cb53ac9..4601469a 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -357,7 +357,7 @@ class TestFilter: def test_urlize(self, env): tmpl = env.from_string('{{ "foo example.org bar"|urlize }}') assert tmpl.render() == ( - 'foo ' "example.org bar" + 'foo example.org bar' ) tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}') assert tmpl.render() == ( diff --git a/tests/test_lexnparse.py b/tests/test_lexnparse.py index c02adad5..0f0dbf33 100644 --- a/tests/test_lexnparse.py +++ b/tests/test_lexnparse.py @@ -43,8 +43,7 @@ class TestTokenStream: class TestLexer: def test_raw1(self, env): tmpl = env.from_string( - "{% raw %}foo{% endraw %}|" - "{%raw%}{{ bar }}|{% baz %}{% endraw %}" + "{% raw %}foo{% endraw %}|{%raw%}{{ bar }}|{% baz %}{% endraw %}" ) assert tmpl.render() == "foo|{{ bar }}|{% baz %}"