]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
fix ruff pyupgrade findings 2096/head
authorDavid Lord <davidism@gmail.com>
Wed, 28 May 2025 18:10:30 +0000 (11:10 -0700)
committerDavid Lord <davidism@gmail.com>
Wed, 28 May 2025 18:13:57 +0000 (11:13 -0700)
21 files changed:
src/jinja2/async_utils.py
src/jinja2/bccache.py
src/jinja2/compiler.py
src/jinja2/debug.py
src/jinja2/defaults.py
src/jinja2/environment.py
src/jinja2/exceptions.py
src/jinja2/ext.py
src/jinja2/filters.py
src/jinja2/idtracking.py
src/jinja2/lexer.py
src/jinja2/loaders.py
src/jinja2/meta.py
src/jinja2/nativetypes.py
src/jinja2/nodes.py
src/jinja2/optimizer.py
src/jinja2/parser.py
src/jinja2/runtime.py
src/jinja2/sandbox.py
src/jinja2/utils.py
src/jinja2/visitor.py

index 182ffb0a7ffc658b824c90b2afc45bec2e2c6331..2e6546aeb2bf20b7c267a555df5550344c79e29a 100644 (file)
@@ -85,7 +85,7 @@ class _IteratorToAsyncIterator(t.Generic[V]):
 
 
 def auto_aiter(
-    iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    iterable: "t.AsyncIterable[V] | t.Iterable[V]",
 ) -> "t.AsyncIterator[V]":
     if hasattr(iterable, "__aiter__"):
         return iterable.__aiter__()
@@ -94,6 +94,6 @@ def auto_aiter(
 
 
 async def auto_to_list(
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
 ) -> list["V"]:
     return [x async for x in auto_aiter(value)]
index ada8b099ff251ea9c6da4c42e1383f37e359f06a..7d18cebad3294e758368fe6ba2e187b117878a89 100644 (file)
@@ -27,9 +27,7 @@ if t.TYPE_CHECKING:
     class _MemcachedClient(te.Protocol):
         def get(self, key: str) -> bytes: ...
 
-        def set(
-            self, key: str, value: bytes, timeout: t.Optional[int] = None
-        ) -> None: ...
+        def set(self, key: str, value: bytes, timeout: int | None = None) -> None: ...
 
 
 bc_version = 5
@@ -60,7 +58,7 @@ class Bucket:
 
     def reset(self) -> None:
         """Resets the bucket (unloads the bytecode)."""
-        self.code: t.Optional[CodeType] = None
+        self.code: CodeType | None = None
 
     def load_bytecode(self, f: t.BinaryIO) -> None:
         """Loads bytecode from a file or file like object."""
@@ -149,9 +147,7 @@ class BytecodeCache:
         by a particular environment.
         """
 
-    def get_cache_key(
-        self, name: str, filename: t.Optional[t.Union[str]] = None
-    ) -> str:
+    def get_cache_key(self, name: str, filename: str | None = None) -> str:
         """Returns the unique hash key for this template name."""
         hash = sha1(name.encode("utf-8"))
 
@@ -168,7 +164,7 @@ class BytecodeCache:
         self,
         environment: "Environment",
         name: str,
-        filename: t.Optional[str],
+        filename: str | None,
         source: str,
     ) -> Bucket:
         """Return a cache bucket for the given template.  All arguments are
@@ -204,7 +200,7 @@ class FileSystemBytecodeCache(BytecodeCache):
     """
 
     def __init__(
-        self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache"
+        self, directory: str | None = None, pattern: str = "__jinja2_%s.cache"
     ) -> None:
         if directory is None:
             directory = self._get_default_cache_dir()
@@ -377,7 +373,7 @@ class MemcachedBytecodeCache(BytecodeCache):
         self,
         client: "_MemcachedClient",
         prefix: str = "jinja2/bytecode/",
-        timeout: t.Optional[int] = None,
+        timeout: int | None = None,
         ignore_memcache_errors: bool = True,
     ):
         self.client = client
index 3931ff0d5f17a20ba6b357aa218640f51cfea7a6..84cd513028021b327715400bfa89d28f4e3120cd 100644 (file)
@@ -101,12 +101,12 @@ def _make_unop(
 def generate(
     node: nodes.Template,
     environment: "Environment",
-    name: t.Optional[str],
-    filename: t.Optional[str],
-    stream: t.Optional[t.TextIO] = None,
+    name: str | None,
+    filename: str | None,
+    stream: t.TextIO | None = None,
     defer_init: bool = False,
     optimized: bool = True,
-) -> t.Optional[str]:
+) -> str | None:
     """Generate the python source for a node tree."""
     if not isinstance(node, nodes.Template):
         raise TypeError("Can't compile non template nodes")
@@ -153,7 +153,7 @@ def find_undeclared(nodes: t.Iterable[nodes.Node], names: t.Iterable[str]) -> se
 
 
 class MacroRef:
-    def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None:
+    def __init__(self, node: nodes.Macro | nodes.CallBlock) -> None:
         self.node = node
         self.accesses_caller = False
         self.accesses_kwargs = False
@@ -167,7 +167,7 @@ class Frame:
         self,
         eval_ctx: EvalContext,
         parent: t.Optional["Frame"] = None,
-        level: t.Optional[int] = None,
+        level: int | None = None,
     ) -> None:
         self.eval_ctx = eval_ctx
 
@@ -185,10 +185,10 @@ class Frame:
             # this for example affects {% filter %} or {% macro %}.  If a frame
             # is buffered this variable points to the name of the list used as
             # buffer.
-            self.buffer: t.Optional[str] = None
+            self.buffer: str | None = None
 
             # the name of the block we're in, otherwise None.
-            self.block: t.Optional[str] = None
+            self.block: str | None = None
 
         else:
             self.symbols = Symbols(parent.symbols, level=level)
@@ -299,9 +299,9 @@ class CodeGenerator(NodeVisitor):
     def __init__(
         self,
         environment: "Environment",
-        name: t.Optional[str],
-        filename: t.Optional[str],
-        stream: t.Optional[t.TextIO] = None,
+        name: str | None,
+        filename: str | None,
+        stream: t.TextIO | None = None,
         defer_init: bool = False,
         optimized: bool = True,
     ) -> None:
@@ -313,7 +313,7 @@ class CodeGenerator(NodeVisitor):
         self.stream = stream
         self.created_block_context = False
         self.defer_init = defer_init
-        self.optimizer: t.Optional[Optimizer] = None
+        self.optimizer: Optimizer | None = None
 
         if optimized:
             self.optimizer = Optimizer(environment)
@@ -342,7 +342,7 @@ class CodeGenerator(NodeVisitor):
 
         # the debug information
         self.debug_info: list[tuple[int, int]] = []
-        self._write_debug_info: t.Optional[int] = None
+        self._write_debug_info: int | None = None
 
         # the number of new lines before the next write()
         self._new_lines = 0
@@ -417,7 +417,7 @@ class CodeGenerator(NodeVisitor):
         """Outdent by step."""
         self._indentation -= step
 
-    def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None:
+    def start_write(self, frame: Frame, node: nodes.Node | None = None) -> None:
         """Yield or write into the frame buffer."""
         if frame.buffer is None:
             self.writeline("yield ", node)
@@ -430,7 +430,7 @@ class CodeGenerator(NodeVisitor):
             self.write(")")
 
     def simple_write(
-        self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None
+        self, s: str, frame: Frame, node: nodes.Node | None = None
     ) -> None:
         """Simple shortcut for start_write + write + end_write."""
         self.start_write(frame, node)
@@ -462,14 +462,12 @@ class CodeGenerator(NodeVisitor):
             self._new_lines = 0
         self.stream.write(x)
 
-    def writeline(
-        self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0
-    ) -> None:
+    def writeline(self, x: str, node: nodes.Node | None = None, extra: int = 0) -> None:
         """Combination of newline and write."""
         self.newline(node, extra)
         self.write(x)
 
-    def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None:
+    def newline(self, node: nodes.Node | None = None, extra: int = 0) -> None:
         """Add one or more newlines before the next write."""
         self._new_lines = max(self._new_lines, 1 + extra)
         if node is not None and node.lineno != self._last_line:
@@ -478,9 +476,9 @@ class CodeGenerator(NodeVisitor):
 
     def signature(
         self,
-        node: t.Union[nodes.Call, nodes.Filter, nodes.Test],
+        node: nodes.Call | nodes.Filter | nodes.Test,
         frame: Frame,
-        extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None,
+        extra_kwargs: t.Mapping[str, t.Any] | None = None,
     ) -> None:
         """Writes a function call to the stream for the current node.
         A leading comma is added automatically.  The extra keyword
@@ -610,7 +608,7 @@ class CodeGenerator(NodeVisitor):
         return f"{self.choose_async()}def {name}"
 
     def macro_body(
-        self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame
+        self, node: nodes.Macro | nodes.CallBlock, frame: Frame
     ) -> tuple[Frame, MacroRef]:
         """Dump the function def of a macro or call block."""
         frame = frame.inner()
@@ -824,9 +822,7 @@ class CodeGenerator(NodeVisitor):
 
     # -- Statement Visitors
 
-    def visit_Template(
-        self, node: nodes.Template, frame: t.Optional[Frame] = None
-    ) -> None:
+    def visit_Template(self, node: nodes.Template, frame: Frame | None = None) -> None:
         assert frame is None, "no root frame allowed"
         eval_ctx = EvalContext(self.environment, self.name)
 
@@ -1096,7 +1092,7 @@ class CodeGenerator(NodeVisitor):
             self.outdent()
 
     def _import_common(
-        self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame
+        self, node: nodes.Import | nodes.FromImport, frame: Frame
     ) -> None:
         self.write(f"{self.choose_async('await ')}environment.get_template(")
         self.visit(node.template, frame)
@@ -1369,7 +1365,7 @@ class CodeGenerator(NodeVisitor):
         with_frame = frame.inner()
         with_frame.symbols.analyze_node(node)
         self.enter_frame(with_frame)
-        for target, expr in zip(node.targets, node.values):
+        for target, expr in zip(node.targets, node.values, strict=False):
             self.newline()
             self.visit(target, with_frame)
             self.write(" = ")
@@ -1382,8 +1378,8 @@ class CodeGenerator(NodeVisitor):
         self.visit(node.node, frame)
 
     class _FinalizeInfo(t.NamedTuple):
-        const: t.Optional[t.Callable[..., str]]
-        src: t.Optional[str]
+        const: t.Callable[..., str] | None
+        src: str | None
 
     @staticmethod
     def _default_finalize(value: t.Any) -> t.Any:
@@ -1393,7 +1389,7 @@ class CodeGenerator(NodeVisitor):
         """
         return str(value)
 
-    _finalize: t.Optional[_FinalizeInfo] = None
+    _finalize: _FinalizeInfo | None = None
 
     def _make_finalize(self) -> _FinalizeInfo:
         """Build the finalize function to be used on constants and at
@@ -1411,7 +1407,7 @@ class CodeGenerator(NodeVisitor):
         if self._finalize is not None:
             return self._finalize
 
-        finalize: t.Optional[t.Callable[..., t.Any]]
+        finalize: t.Callable[..., t.Any] | None
         finalize = default = self._default_finalize
         src = None
 
@@ -1509,7 +1505,7 @@ class CodeGenerator(NodeVisitor):
             self.indent()
 
         finalize = self._make_finalize()
-        body: list[t.Union[list[t.Any], nodes.Expr]] = []
+        body: list[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
@@ -1791,7 +1787,7 @@ class CodeGenerator(NodeVisitor):
 
     @contextmanager
     def _filter_test_common(
-        self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool
+        self, node: nodes.Filter | nodes.Test, frame: Frame, is_filter: bool
     ) -> t.Iterator[None]:
         if self.environment.is_async:
             self.write("(await auto_await(")
index 41265d4f3a53422b0b5a98e2b3bdbf643a61e5af..01dc76f5f7e2297cca8d9029b05f78a0b9fec6fa 100644 (file)
@@ -11,7 +11,7 @@ if t.TYPE_CHECKING:
     from .runtime import Context
 
 
-def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException:
+def rewrite_traceback_stack(source: str | None = None) -> BaseException:
     """Rewrite the current exception to replace any tracebacks from
     within compiled template code with tracebacks that look like they
     came from the template source.
@@ -74,7 +74,7 @@ def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException:
 
 
 def fake_traceback(  # type: ignore
-    exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int
+    exc_value: BaseException, tb: TracebackType | None, filename: str, lineno: int
 ) -> TracebackType:
     """Produce a new traceback object that looks like it came from the
     template source instead of the compiled code. The filename, line
@@ -133,7 +133,7 @@ def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> dict[str, t.Any]:
     available at that point in the template.
     """
     # Start with the current template context.
-    ctx: t.Optional[Context] = real_locals.get("context")
+    ctx: Context | None = real_locals.get("context")
 
     if ctx is not None:
         data: dict[str, t.Any] = ctx.get_all().copy()
index b698c67ec4deb48838f8178aad78e28dbacb29de..a9e89d736e0c55271ebdfcdae43a761951146a7d 100644 (file)
@@ -17,8 +17,8 @@ VARIABLE_START_STRING = "{{"
 VARIABLE_END_STRING = "}}"
 COMMENT_START_STRING = "{#"
 COMMENT_END_STRING = "#}"
-LINE_STATEMENT_PREFIX: t.Optional[str] = None
-LINE_COMMENT_PREFIX: t.Optional[str] = None
+LINE_STATEMENT_PREFIX: str | None = None
+LINE_COMMENT_PREFIX: str | None = None
 TRIM_BLOCKS = False
 LSTRIP_BLOCKS = False
 NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n"
index 942384f977e1ecbd829d1b7c32199ebeeef8c2ce..acaaffb5946c7a4f8973db47a317a286d496ada1 100644 (file)
@@ -82,7 +82,7 @@ def get_spontaneous_environment(cls: type[_env_bound], *args: t.Any) -> _env_bou
 
 def create_cache(
     size: int,
-) -> t.Optional[t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]]:
+) -> t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"] | None:
     """Return the cache class for the given size."""
     if size == 0:
         return None
@@ -94,10 +94,8 @@ def create_cache(
 
 
 def copy_cache(
-    cache: t.Optional[
-        t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]
-    ],
-) -> t.Optional[t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"]]:
+    cache: t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"] | None,
+) -> t.MutableMapping[tuple["weakref.ref[BaseLoader]", str], "Template"] | None:
     """Create an empty copy of the given cache."""
     if cache is None:
         return None
@@ -110,7 +108,7 @@ def copy_cache(
 
 def load_extensions(
     environment: "Environment",
-    extensions: t.Sequence[t.Union[str, type["Extension"]]],
+    extensions: t.Sequence[str | type["Extension"]],
 ) -> dict[str, "Extension"]:
     """Load the extensions from the list and bind it to the environment.
     Returns a dict of instantiated extensions.
@@ -302,17 +300,17 @@ class Environment:
         variable_end_string: str = VARIABLE_END_STRING,
         comment_start_string: str = COMMENT_START_STRING,
         comment_end_string: str = COMMENT_END_STRING,
-        line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX,
-        line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX,
+        line_statement_prefix: str | None = LINE_STATEMENT_PREFIX,
+        line_comment_prefix: str | None = LINE_COMMENT_PREFIX,
         trim_blocks: bool = TRIM_BLOCKS,
         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, type["Extension"]]] = (),
+        extensions: t.Sequence[str | type["Extension"]] = (),
         optimized: bool = True,
         undefined: type[Undefined] = Undefined,
-        finalize: t.Optional[t.Callable[..., t.Any]] = None,
-        autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False,
+        finalize: t.Callable[..., t.Any] | None = None,
+        autoescape: bool | t.Callable[[str | None], bool] = False,
         loader: t.Optional["BaseLoader"] = None,
         cache_size: int = 400,
         auto_reload: bool = True,
@@ -370,7 +368,7 @@ class Environment:
         self.is_async = enable_async
         _environment_config_check(self)
 
-    def add_extension(self, extension: t.Union[str, type["Extension"]]) -> None:
+    def add_extension(self, extension: str | type["Extension"]) -> None:
         """Adds an extension after the environment was created.
 
         .. versionadded:: 2.5
@@ -394,17 +392,17 @@ class Environment:
         variable_end_string: str = missing,
         comment_start_string: str = missing,
         comment_end_string: str = missing,
-        line_statement_prefix: t.Optional[str] = missing,
-        line_comment_prefix: t.Optional[str] = missing,
+        line_statement_prefix: str | None = missing,
+        line_comment_prefix: str | None = missing,
         trim_blocks: bool = missing,
         lstrip_blocks: bool = missing,
         newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing,
         keep_trailing_newline: bool = missing,
-        extensions: t.Sequence[t.Union[str, type["Extension"]]] = missing,
+        extensions: t.Sequence[str | type["Extension"]] = missing,
         optimized: bool = missing,
         undefined: type[Undefined] = missing,
-        finalize: t.Optional[t.Callable[..., t.Any]] = missing,
-        autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing,
+        finalize: t.Callable[..., t.Any] | None = missing,
+        autoescape: bool | t.Callable[[str | None], bool] = missing,
         loader: t.Optional["BaseLoader"] = missing,
         cache_size: int = missing,
         auto_reload: bool = missing,
@@ -466,9 +464,7 @@ class Environment:
         """Iterates over the extensions by priority."""
         return iter(sorted(self.extensions.values(), key=lambda x: x.priority))
 
-    def getitem(
-        self, obj: t.Any, argument: t.Union[str, t.Any]
-    ) -> t.Union[t.Any, Undefined]:
+    def getitem(self, obj: t.Any, argument: str | t.Any) -> t.Any | Undefined:
         """Get an item or attribute of an object but prefer the item."""
         try:
             return obj[argument]
@@ -500,12 +496,12 @@ class Environment:
 
     def _filter_test_common(
         self,
-        name: t.Union[str, Undefined],
+        name: str | Undefined,
         value: t.Any,
-        args: t.Optional[t.Sequence[t.Any]],
-        kwargs: t.Optional[t.Mapping[str, t.Any]],
-        context: t.Optional[Context],
-        eval_ctx: t.Optional[EvalContext],
+        args: t.Sequence[t.Any] | None,
+        kwargs: t.Mapping[str, t.Any] | None,
+        context: Context | None,
+        eval_ctx: EvalContext | None,
         is_filter: bool,
     ) -> t.Any:
         if is_filter:
@@ -556,10 +552,10 @@ class Environment:
         self,
         name: str,
         value: t.Any,
-        args: t.Optional[t.Sequence[t.Any]] = None,
-        kwargs: t.Optional[t.Mapping[str, t.Any]] = None,
-        context: t.Optional[Context] = None,
-        eval_ctx: t.Optional[EvalContext] = None,
+        args: t.Sequence[t.Any] | None = None,
+        kwargs: t.Mapping[str, t.Any] | None = None,
+        context: Context | None = None,
+        eval_ctx: EvalContext | None = None,
     ) -> t.Any:
         """Invoke a filter on a value the same way the compiler does.
 
@@ -577,10 +573,10 @@ class Environment:
         self,
         name: str,
         value: t.Any,
-        args: t.Optional[t.Sequence[t.Any]] = None,
-        kwargs: t.Optional[t.Mapping[str, t.Any]] = None,
-        context: t.Optional[Context] = None,
-        eval_ctx: t.Optional[EvalContext] = None,
+        args: t.Sequence[t.Any] | None = None,
+        kwargs: t.Mapping[str, t.Any] | None = None,
+        context: Context | None = None,
+        eval_ctx: EvalContext | None = None,
     ) -> t.Any:
         """Invoke a test on a value the same way the compiler does.
 
@@ -602,8 +598,8 @@ class Environment:
     def parse(
         self,
         source: str,
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        name: str | None = None,
+        filename: str | None = None,
     ) -> nodes.Template:
         """Parse the sourcecode and return the abstract syntax tree.  This
         tree of nodes is used by the compiler to convert the template into
@@ -619,7 +615,7 @@ class Environment:
             self.handle_exception(source=source)
 
     def _parse(
-        self, source: str, name: t.Optional[str], filename: t.Optional[str]
+        self, source: str, name: str | None, filename: str | None
     ) -> nodes.Template:
         """Internal parsing function used by `parse` and `compile`."""
         return Parser(self, source, name, filename).parse()
@@ -627,8 +623,8 @@ class Environment:
     def lex(
         self,
         source: str,
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        name: str | None = None,
+        filename: str | None = None,
     ) -> 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)``.
@@ -648,8 +644,8 @@ class Environment:
     def preprocess(
         self,
         source: str,
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        name: str | None = None,
+        filename: str | None = None,
     ) -> str:
         """Preprocesses the source with all extensions.  This is automatically
         called for all parsing and compiling methods but *not* for :meth:`lex`
@@ -664,9 +660,9 @@ class Environment:
     def _tokenize(
         self,
         source: str,
-        name: t.Optional[str],
-        filename: t.Optional[str] = None,
-        state: t.Optional[str] = None,
+        name: str | None,
+        filename: str | None = None,
+        state: str | None = None,
     ) -> TokenStream:
         """Called by the parser to do the preprocessing and filtering
         for all the extensions.  Returns a :class:`~jinja2.lexer.TokenStream`.
@@ -685,8 +681,8 @@ class Environment:
     def _generate(
         self,
         source: nodes.Template,
-        name: t.Optional[str],
-        filename: t.Optional[str],
+        name: str | None,
+        filename: str | None,
         defer_init: bool = False,
     ) -> str:
         """Internal hook that can be overridden to hook a different generate
@@ -714,9 +710,9 @@ class Environment:
     @typing.overload
     def compile(
         self,
-        source: t.Union[str, nodes.Template],
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        source: str | nodes.Template,
+        name: str | None = None,
+        filename: str | None = None,
         raw: "te.Literal[False]" = False,
         defer_init: bool = False,
     ) -> CodeType: ...
@@ -724,9 +720,9 @@ class Environment:
     @typing.overload
     def compile(
         self,
-        source: t.Union[str, nodes.Template],
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        source: str | nodes.Template,
+        name: str | None = None,
+        filename: str | None = None,
         raw: "te.Literal[True]" = ...,
         defer_init: bool = False,
     ) -> str: ...
@@ -734,12 +730,12 @@ class Environment:
     @internalcode
     def compile(
         self,
-        source: t.Union[str, nodes.Template],
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        source: str | nodes.Template,
+        name: str | None = None,
+        filename: str | None = None,
         raw: bool = False,
         defer_init: bool = False,
-    ) -> t.Union[str, CodeType]:
+    ) -> str | CodeType:
         """Compile a node or template source code.  The `name` parameter is
         the load name of the template after it was joined using
         :meth:`join_path` if necessary, not the filename on the file system.
@@ -821,10 +817,10 @@ class Environment:
     def compile_templates(
         self,
         target: t.Union[str, "os.PathLike[str]"],
-        extensions: t.Optional[t.Collection[str]] = None,
-        filter_func: t.Optional[t.Callable[[str], bool]] = None,
-        zip: t.Optional[str] = "deflated",
-        log_function: t.Optional[t.Callable[[str], None]] = None,
+        extensions: t.Collection[str] | None = None,
+        filter_func: t.Callable[[str], bool] | None = None,
+        zip: str | None = "deflated",
+        log_function: t.Callable[[str], None] | None = None,
         ignore_errors: bool = True,
     ) -> None:
         """Finds all the templates the loader can find, compiles them
@@ -901,8 +897,8 @@ class Environment:
 
     def list_templates(
         self,
-        extensions: t.Optional[t.Collection[str]] = None,
-        filter_func: t.Optional[t.Callable[[str], bool]] = None,
+        extensions: t.Collection[str] | None = None,
+        filter_func: t.Callable[[str], bool] | None = None,
     ) -> list[str]:
         """Returns a list of templates for this environment.  This requires
         that the loader supports the loader's
@@ -936,7 +932,7 @@ class Environment:
 
         return names
 
-    def handle_exception(self, source: t.Optional[str] = None) -> "te.NoReturn":
+    def handle_exception(self, source: str | None = None) -> "te.NoReturn":
         """Exception handling helper.  This is used internally to either raise
         rewritten exceptions or return a rendered traceback for the template.
         """
@@ -958,7 +954,7 @@ class Environment:
 
     @internalcode
     def _load_template(
-        self, name: str, globals: t.Optional[t.MutableMapping[str, t.Any]]
+        self, name: str, globals: t.MutableMapping[str, t.Any] | None
     ) -> "Template":
         if self.loader is None:
             raise TypeError("no loader for this environment specified")
@@ -985,8 +981,8 @@ class Environment:
     def get_template(
         self,
         name: t.Union[str, "Template"],
-        parent: t.Optional[str] = None,
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
+        parent: str | None = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ) -> "Template":
         """Load a template by name with :attr:`loader` and return a
         :class:`Template`. If the template does not exist a
@@ -1022,8 +1018,8 @@ class Environment:
     def select_template(
         self,
         names: t.Iterable[t.Union[str, "Template"]],
-        parent: t.Optional[str] = None,
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
+        parent: str | None = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ) -> "Template":
         """Like :meth:`get_template`, but tries loading multiple names.
         If none of the names can be loaded a :exc:`TemplatesNotFound`
@@ -1076,8 +1072,8 @@ class Environment:
     def get_or_select_template(
         self,
         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,
+        parent: str | None = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ) -> "Template":
         """Use :meth:`select_template` if an iterable of template names
         is given, or :meth:`get_template` if one name is given.
@@ -1092,9 +1088,9 @@ class Environment:
 
     def from_string(
         self,
-        source: t.Union[str, nodes.Template],
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
-        template_class: t.Optional[type["Template"]] = None,
+        source: str | nodes.Template,
+        globals: t.MutableMapping[str, t.Any] | None = None,
+        template_class: type["Template"] | None = None,
     ) -> "Template":
         """Load a template from a source string without using
         :attr:`loader`.
@@ -1112,7 +1108,7 @@ class Environment:
         return cls.from_code(self, self.compile(source), gs, None)
 
     def make_globals(
-        self, d: t.Optional[t.MutableMapping[str, t.Any]]
+        self, d: t.MutableMapping[str, t.Any] | None
     ) -> t.MutableMapping[str, t.Any]:
         """Make the globals map for a template. Any given template
         globals overlay the environment :attr:`globals`.
@@ -1157,34 +1153,34 @@ class Template:
 
     environment: Environment
     globals: t.MutableMapping[str, t.Any]
-    name: t.Optional[str]
-    filename: t.Optional[str]
+    name: str | None
+    filename: str | None
     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
-    _uptodate: t.Optional[t.Callable[[], bool]]
+    _uptodate: t.Callable[[], bool] | None
 
     def __new__(
         cls,
-        source: t.Union[str, nodes.Template],
+        source: str | nodes.Template,
         block_start_string: str = BLOCK_START_STRING,
         block_end_string: str = BLOCK_END_STRING,
         variable_start_string: str = VARIABLE_START_STRING,
         variable_end_string: str = VARIABLE_END_STRING,
         comment_start_string: str = COMMENT_START_STRING,
         comment_end_string: str = COMMENT_END_STRING,
-        line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX,
-        line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX,
+        line_statement_prefix: str | None = LINE_STATEMENT_PREFIX,
+        line_comment_prefix: str | None = LINE_COMMENT_PREFIX,
         trim_blocks: bool = TRIM_BLOCKS,
         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, type["Extension"]]] = (),
+        extensions: t.Sequence[str | type["Extension"]] = (),
         optimized: bool = True,
         undefined: type[Undefined] = Undefined,
-        finalize: t.Optional[t.Callable[..., t.Any]] = None,
-        autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False,
+        finalize: t.Callable[..., t.Any] | None = None,
+        autoescape: bool | t.Callable[[str | None], bool] = False,
         enable_async: bool = False,
     ) -> t.Any:  # it returns a `Template`, but this breaks the sphinx build...
         env = get_spontaneous_environment(
@@ -1220,7 +1216,7 @@ class Template:
         environment: Environment,
         code: CodeType,
         globals: t.MutableMapping[str, t.Any],
-        uptodate: t.Optional[t.Callable[[], bool]] = None,
+        uptodate: t.Callable[[], bool] | None = None,
     ) -> "Template":
         """Creates a template object from compiled code and the globals.  This
         is used by the loaders and environment to create a template object.
@@ -1372,9 +1368,9 @@ class Template:
 
     def new_context(
         self,
-        vars: t.Optional[dict[str, t.Any]] = None,
+        vars: dict[str, t.Any] | None = None,
         shared: bool = False,
-        locals: t.Optional[t.Mapping[str, t.Any]] = None,
+        locals: t.Mapping[str, t.Any] | None = None,
     ) -> Context:
         """Create a new :class:`Context` for this template.  The vars
         provided will be passed to the template.  Per default the globals
@@ -1389,9 +1385,9 @@ class Template:
 
     def make_module(
         self,
-        vars: t.Optional[dict[str, t.Any]] = None,
+        vars: dict[str, t.Any] | None = None,
         shared: bool = False,
-        locals: t.Optional[t.Mapping[str, t.Any]] = None,
+        locals: t.Mapping[str, t.Any] | None = None,
     ) -> "TemplateModule":
         """This method works like the :attr:`module` attribute when called
         without arguments but it will evaluate the template on every call
@@ -1404,9 +1400,9 @@ class Template:
 
     async def make_module_async(
         self,
-        vars: t.Optional[dict[str, t.Any]] = None,
+        vars: dict[str, t.Any] | None = None,
         shared: bool = False,
-        locals: t.Optional[t.Mapping[str, t.Any]] = None,
+        locals: t.Mapping[str, t.Any] | None = None,
     ) -> "TemplateModule":
         """As template module creation can invoke template code for
         asynchronous executions this method must be used instead of the
@@ -1421,7 +1417,7 @@ class Template:
         )
 
     @internalcode
-    def _get_default_module(self, ctx: t.Optional[Context] = None) -> "TemplateModule":
+    def _get_default_module(self, ctx: Context | None = None) -> "TemplateModule":
         """If a context is passed in, this means that the template was
         imported. Imported templates have access to the current
         template's globals by default, but they can only be accessed via
@@ -1448,7 +1444,7 @@ class Template:
         return self._module
 
     async def _get_default_module_async(
-        self, ctx: t.Optional[Context] = None
+        self, ctx: Context | None = None
     ) -> "TemplateModule":
         if ctx is not None:
             keys = ctx.globals_keys - self.globals.keys()
@@ -1522,7 +1518,7 @@ class TemplateModule:
         self,
         template: Template,
         context: Context,
-        body_stream: t.Optional[t.Iterable[str]] = None,
+        body_stream: t.Iterable[str] | None = None,
     ) -> None:
         if body_stream is None:
             if context.environment.is_async:
@@ -1562,7 +1558,7 @@ class TemplateExpression:
         self._template = template
         self._undefined_to_none = undefined_to_none
 
-    def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Optional[t.Any]:
+    def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any | None:
         context = self._template.new_context(dict(*args, **kwargs))
         consume(self._template.root_render_func(context))
         rv = context.vars["result"]
@@ -1588,9 +1584,9 @@ class TemplateStream:
 
     def dump(
         self,
-        fp: t.Union[str, t.IO[bytes]],
-        encoding: t.Optional[str] = None,
-        errors: t.Optional[str] = "strict",
+        fp: str | t.IO[bytes],
+        encoding: str | None = None,
+        errors: str | None = "strict",
     ) -> None:
         """Dump the complete stream into a file or file-like object.
         Per default strings are written, if you want to encode
index 082ebe8f221d4e7e980e4d321c0a0c5da033b124..a161a2f07120e020156c0d621f1a12ff8957f534 100644 (file)
@@ -7,11 +7,11 @@ if t.TYPE_CHECKING:
 class TemplateError(Exception):
     """Baseclass for all template errors."""
 
-    def __init__(self, message: t.Optional[str] = None) -> None:
+    def __init__(self, message: str | None = None) -> None:
         super().__init__(message)
 
     @property
-    def message(self) -> t.Optional[str]:
+    def message(self) -> str | None:
         return self.args[0] if self.args else None
 
 
@@ -25,12 +25,12 @@ class TemplateNotFound(IOError, LookupError, TemplateError):
 
     # Silence the Python warning about message being deprecated since
     # it's not valid here.
-    message: t.Optional[str] = None
+    message: str | None = None
 
     def __init__(
         self,
-        name: t.Optional[t.Union[str, "Undefined"]],
-        message: t.Optional[str] = None,
+        name: t.Union[str, "Undefined"] | None,
+        message: str | None = None,
     ) -> None:
         IOError.__init__(self, name)
 
@@ -65,7 +65,7 @@ class TemplatesNotFound(TemplateNotFound):
     def __init__(
         self,
         names: t.Sequence[t.Union[str, "Undefined"]] = (),
-        message: t.Optional[str] = None,
+        message: str | None = None,
     ) -> None:
         if message is None:
             from .runtime import Undefined
@@ -92,14 +92,14 @@ class TemplateSyntaxError(TemplateError):
         self,
         message: str,
         lineno: int,
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        name: str | None = None,
+        filename: str | None = None,
     ) -> None:
         super().__init__(message)
         self.lineno = lineno
         self.name = name
         self.filename = filename
-        self.source: t.Optional[str] = None
+        self.source: str | None = None
 
         # this is set to True if the debug.translate_syntax_error
         # function translated the syntax error into a new traceback
index 1c27df94ba247db2417d249c18654f5a065618cb..dbb0aeb41980b01792d8c6572d57975f3a03a4bb 100644 (file)
@@ -37,7 +37,7 @@ if t.TYPE_CHECKING:
             self, context: str, singular: str, plural: str, n: int
         ) -> str: ...
 
-    _SupportedTranslations = t.Union[_TranslationsBasic, _TranslationsContext]
+    _SupportedTranslations = _TranslationsBasic | _TranslationsContext
 
 
 # I18N functions available in Jinja templates. If the I18N library
@@ -97,7 +97,7 @@ class Extension:
         return rv
 
     def preprocess(
-        self, source: str, name: t.Optional[str], filename: t.Optional[str] = None
+        self, source: str, name: str | None, filename: str | None = None
     ) -> str:
         """This method is called before the actual lexing and can be used to
         preprocess the source.  The `filename` is optional.  The return value
@@ -115,7 +115,7 @@ class Extension:
         """
         return stream
 
-    def parse(self, parser: "Parser") -> t.Union[nodes.Node, list[nodes.Node]]:
+    def parse(self, parser: "Parser") -> 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
@@ -123,9 +123,7 @@ class Extension:
         """
         raise NotImplementedError()
 
-    def attr(
-        self, name: str, lineno: t.Optional[int] = None
-    ) -> nodes.ExtensionAttribute:
+    def attr(self, name: str, lineno: int | None = None) -> nodes.ExtensionAttribute:
         """Return an attribute node for the current extension.  This is useful
         to pass constants on extensions to generated template code.
 
@@ -138,11 +136,11 @@ class Extension:
     def call_method(
         self,
         name: str,
-        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,
+        args: list[nodes.Expr] | None = None,
+        kwargs: list[nodes.Keyword] | None = None,
+        dyn_args: nodes.Expr | None = None,
+        dyn_kwargs: nodes.Expr | None = None,
+        lineno: int | None = None,
     ) -> nodes.Call:
         """Call a method of the extension.  This is a shortcut for
         :meth:`attr` + :class:`jinja2.nodes.Call`.
@@ -164,7 +162,7 @@ class Extension:
 @pass_context
 def _gettext_alias(
     __context: Context, *args: t.Any, **kwargs: t.Any
-) -> t.Union[t.Any, Undefined]:
+) -> t.Any | Undefined:
     return __context.call(__context.resolve("gettext"), *args, **kwargs)
 
 
@@ -268,7 +266,7 @@ class InternationalizationExtension(Extension):
         )
 
     def _install(
-        self, translations: "_SupportedTranslations", newstyle: t.Optional[bool] = None
+        self, translations: "_SupportedTranslations", newstyle: bool | None = None
     ) -> None:
         # ugettext and ungettext are preferred in case the I18N library
         # is providing compatibility with older Python versions.
@@ -285,7 +283,7 @@ class InternationalizationExtension(Extension):
             gettext, ngettext, newstyle=newstyle, pgettext=pgettext, npgettext=npgettext
         )
 
-    def _install_null(self, newstyle: t.Optional[bool] = None) -> None:
+    def _install_null(self, newstyle: bool | None = None) -> None:
         import gettext
 
         translations = gettext.NullTranslations()
@@ -301,9 +299,9 @@ class InternationalizationExtension(Extension):
         self,
         gettext: t.Callable[[str], str],
         ngettext: t.Callable[[str, str, int], str],
-        newstyle: t.Optional[bool] = None,
-        pgettext: t.Optional[t.Callable[[str, str], str]] = None,
-        npgettext: t.Optional[t.Callable[[str, str, str, int], str]] = None,
+        newstyle: bool | None = None,
+        pgettext: t.Callable[[str, str], str] | None = None,
+        npgettext: t.Callable[[str, str, str, int], str] | None = None,
     ) -> None:
         if newstyle is not None:
             self.environment.newstyle_gettext = newstyle  # type: ignore
@@ -327,16 +325,14 @@ class InternationalizationExtension(Extension):
 
     def _extract(
         self,
-        source: t.Union[str, nodes.Template],
+        source: str | nodes.Template,
         gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS,
-    ) -> t.Iterator[
-        tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]]]
-    ]:
+    ) -> t.Iterator[tuple[int, str, str | None | tuple[str | None, ...]]]:
         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, list[nodes.Node]]:
+    def parse(self, parser: "Parser") -> nodes.Node | list[nodes.Node]:
         """Parse a translatable tag."""
         lineno = next(parser.stream).lineno
 
@@ -349,8 +345,8 @@ class InternationalizationExtension(Extension):
         # find all the variables referenced.  Additionally a variable can be
         # defined in the body of the trans block too, but this is checked at
         # a later state.
-        plural_expr: t.Optional[nodes.Expr] = None
-        plural_expr_assignment: t.Optional[nodes.Assign] = None
+        plural_expr: nodes.Expr | None = None
+        plural_expr_assignment: nodes.Assign | None = None
         num_called_num = False
         variables: dict[str, nodes.Expr] = {}
         trimmed = None
@@ -511,10 +507,10 @@ class InternationalizationExtension(Extension):
     def _make_node(
         self,
         singular: str,
-        plural: t.Optional[str],
-        context: t.Optional[str],
+        plural: str | None,
+        context: str | None,
         variables: dict[str, nodes.Expr],
-        plural_expr: t.Optional[nodes.Expr],
+        plural_expr: nodes.Expr | None,
         vars_referenced: bool,
         num_called_num: bool,
     ) -> nodes.Output:
@@ -589,7 +585,7 @@ class LoopControlExtension(Extension):
 
     tags = {"break", "continue"}
 
-    def parse(self, parser: "Parser") -> t.Union[nodes.Break, nodes.Continue]:
+    def parse(self, parser: "Parser") -> nodes.Break | nodes.Continue:
         token = next(parser.stream)
         if token.value == "break":
             return nodes.Break(lineno=token.lineno)
@@ -640,7 +636,7 @@ def extract_from_ast(
     ast: nodes.Template,
     gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS,
     babel_style: bool = True,
-) -> t.Iterator[tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]]]]:
+) -> t.Iterator[tuple[int, str, str | None | tuple[str | None, ...]]]:
     """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
@@ -675,7 +671,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], tuple[t.Optional[str], ...]]
+    out: str | None | tuple[str | None, ...]
 
     for node in ast.find_all(nodes.Call):
         if (
@@ -684,7 +680,7 @@ def extract_from_ast(
         ):
             continue
 
-        strings: list[t.Optional[str]] = []
+        strings: list[str | None] = []
 
         for arg in node.args:
             if isinstance(arg, nodes.Const) and isinstance(arg.value, str):
@@ -758,9 +754,7 @@ def babel_extract(
     keywords: t.Sequence[str],
     comment_tags: t.Sequence[str],
     options: dict[str, t.Any],
-) -> t.Iterator[
-    tuple[int, str, t.Union[t.Optional[str], tuple[t.Optional[str], ...]], list[str]]
-]:
+) -> t.Iterator[tuple[int, str, str | None | tuple[str | None, ...], list[str]]]:
     """Babel extraction method for Jinja templates.
 
     .. versionchanged:: 2.3
index 73a0cdcefc6e198f9a4299ad9bd65638cdd56765..c46e20c100a25edb912f96b949c2ce4bbbc0ec81 100644 (file)
@@ -57,9 +57,9 @@ def ignore_case(value: V) -> V:
 
 def make_attrgetter(
     environment: "Environment",
-    attribute: t.Optional[t.Union[str, int]],
-    postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None,
-    default: t.Optional[t.Any] = None,
+    attribute: str | int | None,
+    postprocess: t.Callable[[t.Any], t.Any] | None = None,
+    default: t.Any | None = None,
 ) -> t.Callable[[t.Any], t.Any]:
     """Returns a callable that looks up the given attribute from a
     passed object with the rules of the environment.  Dots are allowed
@@ -85,8 +85,8 @@ def make_attrgetter(
 
 def make_multi_attrgetter(
     environment: "Environment",
-    attribute: t.Optional[t.Union[str, int]],
-    postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None,
+    attribute: str | int | None,
+    postprocess: t.Callable[[t.Any], t.Any] | None = None,
 ) -> 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.
@@ -99,7 +99,7 @@ def make_multi_attrgetter(
     Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc.
     """
     if isinstance(attribute, str):
-        split: t.Sequence[t.Union[str, int, None]] = attribute.split(",")
+        split: t.Sequence[str | int | None] = attribute.split(",")
     else:
         split = [attribute]
 
@@ -125,8 +125,8 @@ def make_multi_attrgetter(
 
 
 def _prepare_attribute_parts(
-    attr: t.Optional[t.Union[str, int]],
-) -> list[t.Union[str, int]]:
+    attr: str | int | None,
+) -> list[str | int]:
     if attr is None:
         return []
 
@@ -136,7 +136,7 @@ def _prepare_attribute_parts(
     return [attr]
 
 
-def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup:
+def do_forceescape(value: "str | HasHTML") -> Markup:
     """Enforce HTML escaping.  This will probably double escape variables."""
     if hasattr(value, "__html__"):
         value = t.cast("HasHTML", value).__html__()
@@ -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[tuple[str, t.Any]]],
+    value: 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.
 
@@ -177,7 +177,7 @@ def do_urlencode(
 
 @pass_eval_context
 def do_replace(
-    eval_ctx: "EvalContext", s: str, old: str, new: str, count: t.Optional[int] = None
+    eval_ctx: "EvalContext", s: str, old: str, new: str, count: int | None = None
 ) -> str:
     """Return a copy of the value with all occurrences of a substring
     replaced with a new one. The first argument is the substring
@@ -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[tuple[K, V]]:
+def do_items(value: 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
@@ -388,7 +388,7 @@ def do_sort(
     value: "t.Iterable[V]",
     reverse: bool = False,
     case_sensitive: bool = False,
-    attribute: t.Optional[t.Union[str, int]] = None,
+    attribute: str | int | None = None,
 ) -> "list[V]":
     """Sort an iterable using Python's :func:`sorted`.
 
@@ -443,7 +443,7 @@ def sync_do_unique(
     environment: "Environment",
     value: "t.Iterable[V]",
     case_sensitive: bool = False,
-    attribute: t.Optional[t.Union[str, int]] = None,
+    attribute: str | int | None = None,
 ) -> "t.Iterator[V]":
     """Returns a list of unique items from the given iterable.
 
@@ -474,9 +474,9 @@ def sync_do_unique(
 @async_variant(sync_do_unique)  # type: ignore
 async def do_unique(
     environment: "Environment",
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
     case_sensitive: bool = False,
-    attribute: t.Optional[t.Union[str, int]] = None,
+    attribute: str | int | None = None,
 ) -> "t.Iterator[V]":
     return sync_do_unique(
         environment, await auto_to_list(value), case_sensitive, attribute
@@ -488,8 +488,8 @@ def _min_or_max(
     value: "t.Iterable[V]",
     func: "t.Callable[..., V]",
     case_sensitive: bool,
-    attribute: t.Optional[t.Union[str, int]],
-) -> "t.Union[V, Undefined]":
+    attribute: str | int | None,
+) -> "V | Undefined":
     it = iter(value)
 
     try:
@@ -508,8 +508,8 @@ def do_min(
     environment: "Environment",
     value: "t.Iterable[V]",
     case_sensitive: bool = False,
-    attribute: t.Optional[t.Union[str, int]] = None,
-) -> "t.Union[V, Undefined]":
+    attribute: str | int | None = None,
+) -> "V | Undefined":
     """Return the smallest item from the sequence.
 
     .. sourcecode:: jinja
@@ -528,8 +528,8 @@ def do_max(
     environment: "Environment",
     value: "t.Iterable[V]",
     case_sensitive: bool = False,
-    attribute: t.Optional[t.Union[str, int]] = None,
-) -> "t.Union[V, Undefined]":
+    attribute: str | int | None = None,
+) -> "V | Undefined":
     """Return the largest item from the sequence.
 
     .. sourcecode:: jinja
@@ -581,7 +581,7 @@ def sync_do_join(
     eval_ctx: "EvalContext",
     value: t.Iterable[t.Any],
     d: str = "",
-    attribute: t.Optional[t.Union[str, int]] = None,
+    attribute: str | int | None = None,
 ) -> str:
     """Return a string which is the concatenation of the strings in the
     sequence. The separator between elements is an empty string per
@@ -637,9 +637,9 @@ def sync_do_join(
 @async_variant(sync_do_join)  # type: ignore
 async def do_join(
     eval_ctx: "EvalContext",
-    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
+    value: t.AsyncIterable[t.Any] | t.Iterable[t.Any],
     d: str = "",
-    attribute: t.Optional[t.Union[str, int]] = None,
+    attribute: str | int | None = None,
 ) -> str:
     return sync_do_join(eval_ctx, await auto_to_list(value), d, attribute)
 
@@ -650,9 +650,7 @@ def do_center(value: str, width: int = 80) -> str:
 
 
 @pass_environment
-def sync_do_first(
-    environment: "Environment", seq: "t.Iterable[V]"
-) -> "t.Union[V, Undefined]":
+def sync_do_first(environment: "Environment", seq: "t.Iterable[V]") -> "V | Undefined":
     """Return the first item of a sequence."""
     try:
         return next(iter(seq))
@@ -662,8 +660,8 @@ def sync_do_first(
 
 @async_variant(sync_do_first)  # type: ignore
 async def do_first(
-    environment: "Environment", seq: "t.Union[t.AsyncIterable[V], t.Iterable[V]]"
-) -> "t.Union[V, Undefined]":
+    environment: "Environment", seq: "t.AsyncIterable[V] | t.Iterable[V]"
+) -> "V | Undefined":
     try:
         return await auto_aiter(seq).__anext__()
     except StopAsyncIteration:
@@ -671,9 +669,7 @@ async def do_first(
 
 
 @pass_environment
-def do_last(
-    environment: "Environment", seq: "t.Reversible[V]"
-) -> "t.Union[V, Undefined]":
+def do_last(environment: "Environment", seq: "t.Reversible[V]") -> "V | Undefined":
     """Return the last item of a sequence.
 
     Note: Does not work with generators. You may want to explicitly
@@ -693,7 +689,7 @@ def do_last(
 
 
 @pass_context
-def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]":
+def do_random(context: "Context", seq: "t.Sequence[V]") -> "V | Undefined":
     """Return a random item from the sequence."""
     try:
         return random.choice(seq)
@@ -701,7 +697,7 @@ def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined
         return context.environment.undefined("No random item, sequence was empty.")
 
 
-def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str:
+def do_filesizeformat(value: str | float | int, binary: bool = False) -> str:
     """Format the value like a 'human-readable' file size (i.e. 13 kB,
     4.1 MB, 102 Bytes, etc).  Per default decimal prefixes are used (Mega,
     Giga, etc.), if the second parameter is set to `True` the binary
@@ -746,11 +742,11 @@ _uri_scheme_re = re.compile(r"^([\w.+-]{2,}:(/){0,2})$")
 def do_urlize(
     eval_ctx: "EvalContext",
     value: str,
-    trim_url_limit: t.Optional[int] = None,
+    trim_url_limit: int | None = None,
     nofollow: bool = False,
-    target: t.Optional[str] = None,
-    rel: t.Optional[str] = None,
-    extra_schemes: t.Optional[t.Iterable[str]] = None,
+    target: str | None = None,
+    rel: str | None = None,
+    extra_schemes: t.Iterable[str] | None = None,
 ) -> str:
     """Convert URLs in text into clickable links.
 
@@ -823,7 +819,7 @@ def do_urlize(
 
 
 def do_indent(
-    s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False
+    s: str, width: int | str = 4, first: bool = False, blank: bool = False
 ) -> str:
     """Return a copy of the string with each line indented by 4 spaces. The
     first line and blank lines are not indented by default.
@@ -877,7 +873,7 @@ def do_truncate(
     length: int = 255,
     killwords: bool = False,
     end: str = "...",
-    leeway: t.Optional[int] = None,
+    leeway: int | None = None,
 ) -> str:
     """Return a truncated copy of the string. The length is specified
     with the first parameter which defaults to ``255``. If the second
@@ -924,7 +920,7 @@ def do_wordwrap(
     s: str,
     width: int = 79,
     break_long_words: bool = True,
-    wrapstring: t.Optional[str] = None,
+    wrapstring: str | None = None,
     break_on_hyphens: bool = True,
 ) -> str:
     """Wrap a string to the given width. Existing newlines are treated
@@ -1043,12 +1039,12 @@ def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str:
     return soft_str(value) % (kwargs or args)
 
 
-def do_trim(value: str, chars: t.Optional[str] = None) -> str:
+def do_trim(value: str, chars: str | None = None) -> str:
     """Strip leading and trailing characters, by default whitespace."""
     return soft_str(value).strip(chars)
 
 
-def do_striptags(value: "t.Union[str, HasHTML]") -> str:
+def do_striptags(value: "str | HasHTML") -> str:
     """Strip SGML/XML tags and replace adjacent whitespace by one space."""
     if hasattr(value, "__html__"):
         value = t.cast("HasHTML", value).__html__()
@@ -1057,7 +1053,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
+    value: "t.Collection[V]", slices: int, fill_with: "V | None" = None
 ) -> "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
@@ -1101,15 +1097,15 @@ def sync_do_slice(
 
 @async_variant(sync_do_slice)  # type: ignore
 async def do_slice(
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
     slices: int,
-    fill_with: t.Optional[t.Any] = None,
+    fill_with: t.Any | None = None,
 ) -> "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
+    value: "t.Iterable[V]", linecount: int, fill_with: "V | None" = None
 ) -> "t.Iterator[list[V]]":
     """
     A filter that batches items. It works pretty much like `slice`
@@ -1202,8 +1198,8 @@ class _GroupTuple(t.NamedTuple):
 def sync_do_groupby(
     environment: "Environment",
     value: "t.Iterable[V]",
-    attribute: t.Union[str, int],
-    default: t.Optional[t.Any] = None,
+    attribute: str | int,
+    default: t.Any | None = None,
     case_sensitive: bool = False,
 ) -> "list[_GroupTuple]":
     """Group a sequence of objects by an attribute using Python's
@@ -1285,9 +1281,9 @@ def sync_do_groupby(
 @async_variant(sync_do_groupby)  # type: ignore
 async def do_groupby(
     environment: "Environment",
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
-    attribute: t.Union[str, int],
-    default: t.Optional[t.Any] = None,
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
+    attribute: str | int,
+    default: t.Any | None = None,
     case_sensitive: bool = False,
 ) -> "list[_GroupTuple]":
     expr = make_attrgetter(
@@ -1313,7 +1309,7 @@ async def do_groupby(
 def sync_do_sum(
     environment: "Environment",
     iterable: "t.Iterable[V]",
-    attribute: t.Optional[t.Union[str, int]] = None,
+    attribute: str | int | None = None,
     start: V = 0,  # type: ignore
 ) -> V:
     """Returns the sum of a sequence of numbers plus the value of parameter
@@ -1339,8 +1335,8 @@ def sync_do_sum(
 @async_variant(sync_do_sum)  # type: ignore
 async def do_sum(
     environment: "Environment",
-    iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
-    attribute: t.Optional[t.Union[str, int]] = None,
+    iterable: "t.AsyncIterable[V] | t.Iterable[V]",
+    attribute: str | int | None = None,
     start: V = 0,  # type: ignore
 ) -> V:
     rv = start
@@ -1366,7 +1362,7 @@ def sync_do_list(value: "t.Iterable[V]") -> "list[V]":
 
 
 @async_variant(sync_do_list)  # type: ignore
-async def do_list(value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "list[V]":
+async def do_list(value: "t.AsyncIterable[V] | t.Iterable[V]") -> "list[V]":
     return await auto_to_list(value)
 
 
@@ -1390,7 +1386,7 @@ def do_reverse(value: str) -> str: ...
 def do_reverse(value: "t.Iterable[V]") -> "t.Iterable[V]": ...
 
 
-def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]:
+def do_reverse(value: str | t.Iterable[V]) -> str | t.Iterable[V]:
     """Reverse the object or return an iterator that iterates over it the other
     way round.
     """
@@ -1409,9 +1405,7 @@ def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]
 
 
 @pass_environment
-def do_attr(
-    environment: "Environment", obj: t.Any, name: str
-) -> t.Union[Undefined, t.Any]:
+def do_attr(environment: "Environment", obj: t.Any, name: str) -> Undefined | t.Any:
     """Get an attribute of an object. ``foo|attr("bar")`` works like
     ``foo.bar``, but returns undefined instead of falling back to ``foo["bar"]``
     if the attribute doesn't exist.
@@ -1449,7 +1443,7 @@ def sync_do_map(
     value: t.Iterable[t.Any],
     *,
     attribute: str = ...,
-    default: t.Optional[t.Any] = None,
+    default: t.Any | None = None,
 ) -> t.Iterable[t.Any]: ...
 
 
@@ -1506,7 +1500,7 @@ def sync_do_map(
 @typing.overload
 def do_map(
     context: "Context",
-    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
+    value: t.AsyncIterable[t.Any] | t.Iterable[t.Any],
     name: str,
     *args: t.Any,
     **kwargs: t.Any,
@@ -1516,17 +1510,17 @@ def do_map(
 @typing.overload
 def do_map(
     context: "Context",
-    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
+    value: t.AsyncIterable[t.Any] | t.Iterable[t.Any],
     *,
     attribute: str = ...,
-    default: t.Optional[t.Any] = None,
+    default: t.Any | None = None,
 ) -> t.Iterable[t.Any]: ...
 
 
 @async_variant(sync_do_map)  # type: ignore
 async def do_map(
     context: "Context",
-    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
+    value: t.AsyncIterable[t.Any] | t.Iterable[t.Any],
     *args: t.Any,
     **kwargs: t.Any,
 ) -> t.AsyncIterable[t.Any]:
@@ -1571,7 +1565,7 @@ def sync_do_select(
 @async_variant(sync_do_select)  # type: ignore
 async def do_select(
     context: "Context",
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
     *args: t.Any,
     **kwargs: t.Any,
 ) -> "t.AsyncIterator[V]":
@@ -1607,7 +1601,7 @@ def sync_do_reject(
 @async_variant(sync_do_reject)  # type: ignore
 async def do_reject(
     context: "Context",
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
     *args: t.Any,
     **kwargs: t.Any,
 ) -> "t.AsyncIterator[V]":
@@ -1647,7 +1641,7 @@ def sync_do_selectattr(
 @async_variant(sync_do_selectattr)  # type: ignore
 async def do_selectattr(
     context: "Context",
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
     *args: t.Any,
     **kwargs: t.Any,
 ) -> "t.AsyncIterator[V]":
@@ -1685,7 +1679,7 @@ def sync_do_rejectattr(
 @async_variant(sync_do_rejectattr)  # type: ignore
 async def do_rejectattr(
     context: "Context",
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
     *args: t.Any,
     **kwargs: t.Any,
 ) -> "t.AsyncIterator[V]":
@@ -1694,7 +1688,7 @@ async def do_rejectattr(
 
 @pass_eval_context
 def do_tojson(
-    eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None
+    eval_ctx: "EvalContext", value: t.Any, indent: int | None = None
 ) -> Markup:
     """Serialize an object to a string of JSON, and mark it safe to
     render in HTML. This filter is only for use in HTML documents.
@@ -1801,7 +1795,7 @@ def select_or_reject(
 
 async def async_select_or_reject(
     context: "Context",
-    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
+    value: "t.AsyncIterable[V] | t.Iterable[V]",
     args: tuple[t.Any, ...],
     kwargs: dict[str, t.Any],
     modfunc: t.Callable[[t.Any], t.Any],
index d04c6d7f06584e4a30492ea7682389ec90017bf6..d380083623276b45cc35cd0530e9863d05fde818 100644 (file)
@@ -32,7 +32,7 @@ def symbols_for_node(
 
 class Symbols:
     def __init__(
-        self, parent: t.Optional["Symbols"] = None, level: t.Optional[int] = None
+        self, parent: t.Optional["Symbols"] = None, level: int | None = None
     ) -> None:
         if level is None:
             if parent is None:
@@ -50,16 +50,14 @@ class Symbols:
         visitor = RootVisitor(self)
         visitor.visit(node, **kwargs)
 
-    def _define_ref(
-        self, name: str, load: t.Optional[tuple[str, t.Optional[str]]] = None
-    ) -> str:
+    def _define_ref(self, name: str, load: tuple[str, str | None] | None = None) -> str:
         ident = f"l_{self.level}_{name}"
         self.refs[name] = ident
         if load is not None:
             self.loads[ident] = load
         return ident
 
-    def find_load(self, target: str) -> t.Optional[t.Any]:
+    def find_load(self, target: str) -> t.Any | None:
         if target in self.loads:
             return self.loads[target]
 
@@ -68,7 +66,7 @@ class Symbols:
 
         return None
 
-    def find_ref(self, name: str) -> t.Optional[str]:
+    def find_ref(self, name: str) -> str | None:
         if name in self.refs:
             return self.refs[name]
 
@@ -146,7 +144,7 @@ class Symbols:
 
     def dump_stores(self) -> dict[str, str]:
         rv: dict[str, str] = {}
-        node: t.Optional[Symbols] = self
+        node: Symbols | None = self
 
         while node is not None:
             for name in sorted(node.stores):
@@ -159,7 +157,7 @@ class Symbols:
 
     def dump_param_targets(self) -> set[str]:
         rv = set()
-        node: t.Optional[Symbols] = self
+        node: Symbols | None = self
 
         while node is not None:
             for target, (instr, _) in self.loads.items():
index d96e9a08790db310727b3813a61925e1a8529c61..e35cd471e98f516221759ef4345867d71d28230a 100644 (file)
@@ -262,7 +262,7 @@ class Failure:
         self.message = message
         self.error_class = cls
 
-    def __call__(self, lineno: int, filename: t.Optional[str]) -> "te.NoReturn":
+    def __call__(self, lineno: int, filename: str | None) -> "te.NoReturn":
         raise self.error_class(self.message, lineno, filename)
 
 
@@ -325,8 +325,8 @@ class TokenStream:
     def __init__(
         self,
         generator: t.Iterable[Token],
-        name: t.Optional[str],
-        filename: t.Optional[str],
+        name: str | None,
+        filename: str | None,
     ):
         self._iter = iter(generator)
         self._pushed: deque[Token] = deque()
@@ -364,7 +364,7 @@ class TokenStream:
         for _ in range(n):
             next(self)
 
-    def next_if(self, expr: str) -> t.Optional[Token]:
+    def next_if(self, expr: str) -> Token | None:
         """Perform the token test and return the token if it matched.
         Otherwise the return value is `None`.
         """
@@ -464,8 +464,8 @@ class OptionalLStrip(tuple):  # type: ignore[type-arg]
 
 class _Rule(t.NamedTuple):
     pattern: t.Pattern[str]
-    tokens: t.Union[str, tuple[str, ...], tuple[Failure]]
-    command: t.Optional[str]
+    tokens: str | tuple[str, ...] | tuple[Failure]
+    command: str | None
 
 
 class Lexer:
@@ -604,9 +604,9 @@ class Lexer:
     def tokenize(
         self,
         source: str,
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
-        state: t.Optional[str] = None,
+        name: str | None = None,
+        filename: str | None = None,
+        state: str | None = None,
     ) -> TokenStream:
         """Calls tokeniter + tokenize and wraps it in a token stream."""
         stream = self.tokeniter(source, name, filename, state)
@@ -615,8 +615,8 @@ class Lexer:
     def wrap(
         self,
         stream: t.Iterable[tuple[int, str, str]],
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
+        name: str | None = None,
+        filename: str | None = None,
     ) -> t.Iterator[Token]:
         """This is called with the stream as returned by `tokenize` and wraps
         every token in a :class:`Token` and converts the value.
@@ -669,9 +669,9 @@ class Lexer:
     def tokeniter(
         self,
         source: str,
-        name: t.Optional[str],
-        filename: t.Optional[str] = None,
-        state: t.Optional[str] = None,
+        name: str | None,
+        filename: str | None = None,
+        state: str | None = None,
     ) -> 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.
index e14613f7cc9808370e4b434bfb8952342f1bc53c..b4b84cc0ef87afcd1ce98ab099ec458b92170222 100644 (file)
@@ -74,7 +74,7 @@ class BaseLoader:
 
     def get_source(
         self, environment: "Environment", template: str
-    ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:
         """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
@@ -109,7 +109,7 @@ class BaseLoader:
         self,
         environment: "Environment",
         name: str,
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ) -> "Template":
         """Loads a template.  This method looks up the template in the cache
         or loads one by calling :meth:`get_source`.  Subclasses should not
@@ -364,14 +364,14 @@ class PackageLoader(BaseLoader):
 
     def get_source(
         self, environment: "Environment", template: str
-    ) -> tuple[str, str, t.Optional[t.Callable[[], bool]]]:
+    ) -> tuple[str, str, t.Callable[[], bool] | None]:
         # 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.
         p = os.path.normpath(
             posixpath.join(self._template_root, *split_template_path(template))
         )
-        up_to_date: t.Optional[t.Callable[[], bool]]
+        up_to_date: t.Callable[[], bool] | None
 
         if self._archive is None:
             # Package is a directory.
@@ -475,18 +475,14 @@ class FunctionLoader(BaseLoader):
         self,
         load_func: t.Callable[
             [str],
-            t.Optional[
-                t.Union[
-                    str, tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]
-                ]
-            ],
+            str | tuple[str, str | None, t.Callable[[], bool] | None] | None,
         ],
     ) -> None:
         self.load_func = load_func
 
     def get_source(
         self, environment: "Environment", template: str
-    ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:
         rv = self.load_func(template)
 
         if rv is None:
@@ -529,7 +525,7 @@ class PrefixLoader(BaseLoader):
 
     def get_source(
         self, environment: "Environment", template: str
-    ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:
         loader, name = self.get_loader(template)
         try:
             return loader.get_source(environment, name)
@@ -543,7 +539,7 @@ class PrefixLoader(BaseLoader):
         self,
         environment: "Environment",
         name: str,
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ) -> "Template":
         loader, local_name = self.get_loader(name)
         try:
@@ -580,7 +576,7 @@ class ChoiceLoader(BaseLoader):
 
     def get_source(
         self, environment: "Environment", template: str
-    ) -> tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
+    ) -> tuple[str, str | None, t.Callable[[], bool] | None]:
         for loader in self.loaders:
             try:
                 return loader.get_source(environment, template)
@@ -593,7 +589,7 @@ class ChoiceLoader(BaseLoader):
         self,
         environment: "Environment",
         name: str,
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ) -> "Template":
         for loader in self.loaders:
             try:
@@ -665,7 +661,7 @@ class ModuleLoader(BaseLoader):
         self,
         environment: "Environment",
         name: str,
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ) -> "Template":
         key = self.get_template_key(name)
         module = f"{self.package_name}.{key}"
index 33094812415aec6a47f639795d598eaaf126a3c0..ec2f1c6fe61b23548a4518fd29bf9974a71bd94a 100644 (file)
@@ -56,10 +56,10 @@ def find_undeclared_variables(ast: nodes.Template) -> set[str]:
 
 
 _ref_types = (nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include)
-_RefType = t.Union[nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include]
+_RefType = nodes.Extends | nodes.FromImport | nodes.Import | nodes.Include
 
 
-def find_referenced_templates(ast: nodes.Template) -> t.Iterator[t.Optional[str]]:
+def find_referenced_templates(ast: nodes.Template) -> t.Iterator[str | None]:
     """Finds all the referenced templates from the AST.  This will return an
     iterator over all the hardcoded template extensions, inclusions and
     imports.  If dynamic inheritance or inclusion is used, `None` will be
index 71db8cc31f45efee11eaad9d8807da389470cf15..91070b19b96f21f87152a097e13682d24f149558 100644 (file)
@@ -13,7 +13,7 @@ from .environment import Environment
 from .environment import Template
 
 
-def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]:
+def native_concat(values: t.Iterable[t.Any]) -> t.Any | None:
     """Return a native Python type from the list of compiled nodes. If
     the result is a single node, its value is returned. Otherwise, the
     nodes are concatenated as strings. If the result can be parsed with
index dc8d72ba18bfe0848ffd33799997749a616b7442..1e08d3c59fad62e80bf3ba777fae56d4e356cd7e 100644 (file)
@@ -74,7 +74,7 @@ class EvalContext:
     """
 
     def __init__(
-        self, environment: "Environment", template_name: t.Optional[str] = None
+        self, environment: "Environment", template_name: str | None = None
     ) -> None:
         self.environment = environment
         if callable(environment.autoescape):
@@ -91,7 +91,7 @@ class EvalContext:
         self.__dict__.update(old)
 
 
-def get_eval_context(node: "Node", ctx: t.Optional[EvalContext]) -> EvalContext:
+def get_eval_context(node: "Node", ctx: EvalContext | None) -> EvalContext:
     if ctx is None:
         if node.environment is None:
             raise RuntimeError(
@@ -137,7 +137,7 @@ class Node(metaclass=NodeType):
                     f"{type(self).__name__!r} takes 0 or {len(self.fields)}"
                     f" argument{'s' if len(self.fields) != 1 else ''}"
                 )
-            for name, arg in zip(self.fields, fields):
+            for name, arg in zip(self.fields, fields, strict=False):
                 setattr(self, name, arg)
         for attr in self.attributes:
             setattr(self, attr, attributes.pop(attr, None))
@@ -146,8 +146,8 @@ class Node(metaclass=NodeType):
 
     def iter_fields(
         self,
-        exclude: t.Optional[t.Container[str]] = None,
-        only: t.Optional[t.Container[str]] = None,
+        exclude: t.Container[str] | None = None,
+        only: t.Container[str] | None = None,
     ) -> 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
@@ -168,8 +168,8 @@ class Node(metaclass=NodeType):
 
     def iter_child_nodes(
         self,
-        exclude: t.Optional[t.Container[str]] = None,
-        only: t.Optional[t.Container[str]] = None,
+        exclude: t.Container[str] | None = None,
+        only: t.Container[str] | None = None,
     ) -> t.Iterator["Node"]:
         """Iterates over all direct child nodes of the node.  This iterates
         over all fields and yields the values of they are nodes.  If the value
@@ -183,7 +183,7 @@ class Node(metaclass=NodeType):
             elif isinstance(item, Node):
                 yield item
 
-    def find(self, node_type: type[_NodeBound]) -> t.Optional[_NodeBound]:
+    def find(self, node_type: type[_NodeBound]) -> _NodeBound | None:
         """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[type[_NodeBound], tuple[type[_NodeBound], ...]]
+        self, node_type: 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.
@@ -250,7 +250,7 @@ class Node(metaclass=NodeType):
         return f"{type(self).__name__}({args_str})"
 
     def dump(self) -> str:
-        def _dump(node: t.Union[Node, t.Any]) -> None:
+        def _dump(node: Node | t.Any) -> None:
             if not isinstance(node, Node):
                 buf.append(repr(node))
                 return
@@ -330,7 +330,7 @@ class For(Stmt):
     iter: Node
     body: list[Node]
     else_: list[Node]
-    test: t.Optional[Node]
+    test: Node | None
     recursive: bool
 
 
@@ -436,7 +436,7 @@ class FromImport(Stmt):
 
     fields = ("template", "names", "with_context")
     template: "Expr"
-    names: list[t.Union[str, tuple[str, str]]]
+    names: list[str | tuple[str, str]]
     with_context: bool
 
 
@@ -469,7 +469,7 @@ class Expr(Node):
 
     abstract = True
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         """Return the value of the expression as constant or raise
         :exc:`Impossible` if this was not possible.
 
@@ -496,7 +496,7 @@ class BinExpr(Expr):
     operator: str
     abstract = True
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
 
         # intercepted operators cannot be folded at compile time
@@ -520,7 +520,7 @@ class UnaryExpr(Expr):
     operator: str
     abstract = True
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
 
         # intercepted operators cannot be folded at compile time
@@ -584,15 +584,15 @@ class Const(Literal):
     fields = ("value",)
     value: t.Any
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         return self.value
 
     @classmethod
     def from_untrusted(
         cls,
         value: t.Any,
-        lineno: t.Optional[int] = None,
-        environment: "t.Optional[Environment]" = None,
+        lineno: int | None = None,
+        environment: "Environment | None" = None,
     ) -> "Const":
         """Return a const object if the value is representable as
         constant value in the generated code, otherwise it will raise
@@ -611,7 +611,7 @@ class TemplateData(Literal):
     fields = ("data",)
     data: str
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> str:
         eval_ctx = get_eval_context(self, eval_ctx)
         if eval_ctx.volatile:
             raise Impossible()
@@ -630,7 +630,7 @@ class Tuple(Literal):
     items: list[Expr]
     ctx: str
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[t.Any, ...]:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> tuple[t.Any, ...]:
         eval_ctx = get_eval_context(self, eval_ctx)
         return tuple(x.as_const(eval_ctx) for x in self.items)
 
@@ -647,7 +647,7 @@ class List(Literal):
     fields = ("items",)
     items: list[Expr]
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> list[t.Any]:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> list[t.Any]:
         eval_ctx = get_eval_context(self, eval_ctx)
         return [x.as_const(eval_ctx) for x in self.items]
 
@@ -660,7 +660,7 @@ class Dict(Literal):
     fields = ("items",)
     items: list["Pair"]
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> dict[t.Any, t.Any]:
+    def as_const(self, eval_ctx: EvalContext | None = 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)
 
@@ -672,7 +672,7 @@ class Pair(Helper):
     key: Expr
     value: Expr
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[t.Any, t.Any]:
+    def as_const(self, eval_ctx: EvalContext | None = 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)
 
@@ -684,7 +684,7 @@ class Keyword(Helper):
     key: str
     value: Expr
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> tuple[str, t.Any]:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> tuple[str, t.Any]:
         eval_ctx = get_eval_context(self, eval_ctx)
         return self.key, self.value.as_const(eval_ctx)
 
@@ -697,9 +697,9 @@ class CondExpr(Expr):
     fields = ("test", "expr1", "expr2")
     test: Expr
     expr1: Expr
-    expr2: t.Optional[Expr]
+    expr2: Expr | None
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
         if self.test.as_const(eval_ctx):
             return self.expr1.as_const(eval_ctx)
@@ -712,7 +712,7 @@ class CondExpr(Expr):
 
 
 def args_as_const(
-    node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext]
+    node: t.Union["_FilterTestCommon", "Call"], eval_ctx: EvalContext | None
 ) -> 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)
@@ -738,12 +738,12 @@ class _FilterTestCommon(Expr):
     name: str
     args: list[Expr]
     kwargs: list[Pair]
-    dyn_args: t.Optional[Expr]
-    dyn_kwargs: t.Optional[Expr]
+    dyn_args: Expr | None
+    dyn_kwargs: Expr | None
     abstract = True
     _is_filter = True
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
 
         if eval_ctx.volatile:
@@ -788,9 +788,9 @@ class Filter(_FilterTestCommon):
     and is applied to the content of the block.
     """
 
-    node: t.Optional[Expr]  # type: ignore
+    node: Expr | None  # type: ignore
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         if self.node is None:
             raise Impossible()
 
@@ -822,8 +822,8 @@ class Call(Expr):
     node: Expr
     args: list[Expr]
     kwargs: list[Keyword]
-    dyn_args: t.Optional[Expr]
-    dyn_kwargs: t.Optional[Expr]
+    dyn_args: Expr | None
+    dyn_kwargs: Expr | None
 
 
 class Getitem(Expr):
@@ -834,7 +834,7 @@ class Getitem(Expr):
     arg: Expr
     ctx: str
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         if self.ctx != "load":
             raise Impossible()
 
@@ -858,7 +858,7 @@ class Getattr(Expr):
     attr: str
     ctx: str
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         if self.ctx != "load":
             raise Impossible()
 
@@ -876,14 +876,14 @@ class Slice(Expr):
     """
 
     fields = ("start", "stop", "step")
-    start: t.Optional[Expr]
-    stop: t.Optional[Expr]
-    step: t.Optional[Expr]
+    start: Expr | None
+    stop: Expr | None
+    step: Expr | None
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> slice:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> slice:
         eval_ctx = get_eval_context(self, eval_ctx)
 
-        def const(obj: t.Optional[Expr]) -> t.Optional[t.Any]:
+        def const(obj: Expr | None) -> t.Any | None:
             if obj is None:
                 return None
             return obj.as_const(eval_ctx)
@@ -899,7 +899,7 @@ class Concat(Expr):
     fields = ("nodes",)
     nodes: list[Expr]
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> str:
         eval_ctx = get_eval_context(self, eval_ctx)
         return "".join(str(x.as_const(eval_ctx)) for x in self.nodes)
 
@@ -913,7 +913,7 @@ class Compare(Expr):
     expr: Expr
     ops: list["Operand"]
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
         result = value = self.expr.as_const(eval_ctx)
 
@@ -989,7 +989,7 @@ class And(BinExpr):
 
     operator = "and"
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
         return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
 
@@ -999,7 +999,7 @@ class Or(BinExpr):
 
     operator = "or"
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
         return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
 
@@ -1082,7 +1082,7 @@ class MarkSafe(Expr):
     fields = ("expr",)
     expr: Expr
 
-    def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> Markup:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> Markup:
         eval_ctx = get_eval_context(self, eval_ctx)
         return Markup(self.expr.as_const(eval_ctx))
 
@@ -1097,9 +1097,7 @@ class MarkSafeIfAutoescape(Expr):
     fields = ("expr",)
     expr: Expr
 
-    def as_const(
-        self, eval_ctx: t.Optional[EvalContext] = None
-    ) -> t.Union[Markup, t.Any]:
+    def as_const(self, eval_ctx: EvalContext | None = None) -> Markup | t.Any:
         eval_ctx = get_eval_context(self, eval_ctx)
         if eval_ctx.volatile:
             raise Impossible()
index 32d1c717b3859530a6addf6204afd3c724b529ee..d411fc36b16fc7f79e0c28c039dcc39455d9a112 100644 (file)
@@ -25,7 +25,7 @@ def optimize(node: nodes.Node, environment: "Environment") -> nodes.Node:
 
 
 class Optimizer(NodeTransformer):
-    def __init__(self, environment: "t.Optional[Environment]") -> None:
+    def __init__(self, environment: "Environment | None") -> None:
         self.environment = environment
 
     def generic_visit(
index d119507d62a0b24ed9b410ef1d090e7aaaff3ee8..3ae857ebe2a937c1362c44f38e5c436bfd3c84b0 100644 (file)
@@ -54,9 +54,9 @@ class Parser:
         self,
         environment: "Environment",
         source: str,
-        name: t.Optional[str] = None,
-        filename: t.Optional[str] = None,
-        state: t.Optional[str] = None,
+        name: str | None = None,
+        filename: str | None = None,
+        state: str | None = None,
     ) -> None:
         self.environment = environment
         self.stream = environment._tokenize(source, name, filename, state)
@@ -64,7 +64,7 @@ class Parser:
         self.filename = filename
         self.closed = False
         self.extensions: dict[
-            str, t.Callable[[Parser], t.Union[nodes.Node, list[nodes.Node]]]
+            str, t.Callable[[Parser], nodes.Node | list[nodes.Node]]
         ] = {}
         for extension in environment.iter_extensions():
             for tag in extension.tags:
@@ -76,7 +76,7 @@ class Parser:
     def fail(
         self,
         msg: str,
-        lineno: t.Optional[int] = None,
+        lineno: int | None = None,
         exc: type[TemplateSyntaxError] = TemplateSyntaxError,
     ) -> "te.NoReturn":
         """Convenience method that raises `exc` with the message, passed
@@ -89,15 +89,15 @@ class Parser:
 
     def _fail_ut_eof(
         self,
-        name: t.Optional[str],
+        name: str | None,
         end_token_stack: list[tuple[str, ...]],
-        lineno: t.Optional[int],
+        lineno: int | None,
     ) -> "te.NoReturn":
         expected: set[str] = set()
         for exprs in end_token_stack:
             expected.update(map(describe_token_expr, exprs))
         if end_token_stack:
-            currently_looking: t.Optional[str] = " or ".join(
+            currently_looking: str | None = " or ".join(
                 map(repr, map(describe_token_expr, end_token_stack[-1]))
             )
         else:
@@ -127,9 +127,7 @@ class Parser:
 
         self.fail(" ".join(message), lineno)
 
-    def fail_unknown_tag(
-        self, name: str, lineno: t.Optional[int] = None
-    ) -> "te.NoReturn":
+    def fail_unknown_tag(self, name: str, lineno: int | None = None) -> "te.NoReturn":
         """Called if the parser encounters an unknown tag.  Tries to fail
         with a human readable error message that could help to identify
         the problem.
@@ -138,8 +136,8 @@ class Parser:
 
     def fail_eof(
         self,
-        end_tokens: t.Optional[tuple[str, ...]] = None,
-        lineno: t.Optional[int] = None,
+        end_tokens: tuple[str, ...] | None = None,
+        lineno: int | None = None,
     ) -> "te.NoReturn":
         """Like fail_unknown_tag but for end of template situations."""
         stack = list(self._end_token_stack)
@@ -147,7 +145,7 @@ class Parser:
             stack.append(end_tokens)
         self._fail_ut_eof(None, stack, lineno)
 
-    def is_tuple_end(self, extra_end_rules: t.Optional[tuple[str, ...]] = None) -> bool:
+    def is_tuple_end(self, extra_end_rules: tuple[str, ...] | None = None) -> bool:
         """Are we at the end of a tuple?"""
         if self.stream.current.type in ("variable_end", "block_end", "rparen"):
             return True
@@ -155,14 +153,14 @@ class Parser:
             return self.stream.current.test_any(extra_end_rules)  # type: ignore
         return False
 
-    def free_identifier(self, lineno: t.Optional[int] = None) -> nodes.InternalName:
+    def free_identifier(self, lineno: int | None = None) -> nodes.InternalName:
         """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
         self._last_identifier += 1
         rv = object.__new__(nodes.InternalName)
         nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno)
         return rv
 
-    def parse_statement(self) -> t.Union[nodes.Node, list[nodes.Node]]:
+    def parse_statement(self) -> nodes.Node | list[nodes.Node]:
         """Parse a single statement."""
         token = self.stream.current
         if token.type != "name":
@@ -220,7 +218,7 @@ class Parser:
             next(self.stream)
         return result
 
-    def parse_set(self) -> t.Union[nodes.Assign, nodes.AssignBlock]:
+    def parse_set(self) -> nodes.Assign | nodes.AssignBlock:
         """Parse an assign statement."""
         lineno = next(self.stream).lineno
         target = self.parse_assign_target(with_namespace=True)
@@ -464,17 +462,17 @@ class Parser:
         self,
         with_tuple: bool = True,
         name_only: bool = False,
-        extra_end_rules: t.Optional[tuple[str, ...]] = None,
+        extra_end_rules: tuple[str, ...] | None = None,
         with_namespace: bool = False,
-    ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: ...
+    ) -> nodes.NSRef | nodes.Name | nodes.Tuple: ...
 
     def parse_assign_target(
         self,
         with_tuple: bool = True,
         name_only: bool = False,
-        extra_end_rules: t.Optional[tuple[str, ...]] = None,
+        extra_end_rules: tuple[str, ...] | None = None,
         with_namespace: bool = False,
-    ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]:
+    ) -> nodes.NSRef | nodes.Name | nodes.Tuple:
         """Parse an assignment target.  As Jinja allows assignments to
         tuples, this function can parse all allowed assignment targets.  Per
         default assignments to tuples are parsed, that can be disable however
@@ -519,7 +517,7 @@ class Parser:
     def parse_condexpr(self) -> nodes.Expr:
         lineno = self.stream.current.lineno
         expr1 = self.parse_or()
-        expr3: t.Optional[nodes.Expr]
+        expr3: nodes.Expr | None
 
         while self.stream.skip_if("name:if"):
             expr2 = self.parse_or()
@@ -684,10 +682,10 @@ class Parser:
         self,
         simplified: bool = False,
         with_condexpr: bool = True,
-        extra_end_rules: t.Optional[tuple[str, ...]] = None,
+        extra_end_rules: tuple[str, ...] | None = None,
         explicit_parentheses: bool = False,
         with_namespace: bool = False,
-    ) -> t.Union[nodes.Tuple, nodes.Expr]:
+    ) -> nodes.Tuple | nodes.Expr:
         """Works like `parse_expression` but if multiple expressions are
         delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
         This method could also return a regular expression instead of a tuple
@@ -804,9 +802,7 @@ class Parser:
                 break
         return node
 
-    def parse_subscript(
-        self, node: nodes.Expr
-    ) -> t.Union[nodes.Getattr, nodes.Getitem]:
+    def parse_subscript(self, node: nodes.Expr) -> nodes.Getattr | nodes.Getitem:
         token = next(self.stream)
         arg: nodes.Expr
 
@@ -837,7 +833,7 @@ class Parser:
 
     def parse_subscribed(self) -> nodes.Expr:
         lineno = self.stream.current.lineno
-        args: list[t.Optional[nodes.Expr]]
+        args: list[nodes.Expr | None]
 
         if self.stream.current.type == "colon":
             next(self.stream)
@@ -872,8 +868,8 @@ class Parser:
     ) -> tuple[
         list[nodes.Expr],
         list[nodes.Keyword],
-        t.Union[nodes.Expr, None],
-        t.Union[nodes.Expr, None],
+        nodes.Expr | None,
+        nodes.Expr | None,
     ]:
         token = self.stream.expect("lparen")
         args = []
@@ -931,8 +927,8 @@ class Parser:
         return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
 
     def parse_filter(
-        self, node: t.Optional[nodes.Expr], start_inline: bool = False
-    ) -> t.Optional[nodes.Expr]:
+        self, node: nodes.Expr | None, start_inline: bool = False
+    ) -> nodes.Expr | None:
         while self.stream.current.type == "pipe" or start_inline:
             if not start_inline:
                 next(self.stream)
@@ -991,9 +987,7 @@ class Parser:
             node = nodes.Not(node, lineno=token.lineno)
         return node
 
-    def subparse(
-        self, end_tokens: t.Optional[tuple[str, ...]] = None
-    ) -> list[nodes.Node]:
+    def subparse(self, end_tokens: tuple[str, ...] | None = None) -> list[nodes.Node]:
         body: list[nodes.Node] = []
         data_buffer: list[nodes.Node] = []
         add_data = data_buffer.append
index 00b81e288db669667a0d76342b762d813c814835..667c0416dd6a524dbee6853df7efec67a463d667 100644 (file)
@@ -92,12 +92,12 @@ def str_join(seq: t.Iterable[t.Any]) -> str:
 
 def new_context(
     environment: "Environment",
-    template_name: t.Optional[str],
+    template_name: str | None,
     blocks: dict[str, t.Callable[["Context"], t.Iterator[str]]],
-    vars: t.Optional[dict[str, t.Any]] = None,
+    vars: dict[str, t.Any] | None = None,
     shared: bool = False,
-    globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
-    locals: t.Optional[t.Mapping[str, t.Any]] = None,
+    globals: t.MutableMapping[str, t.Any] | None = None,
+    locals: t.Mapping[str, t.Any] | None = None,
 ) -> "Context":
     """Internal helper for context creation."""
     if vars is None:
@@ -166,9 +166,9 @@ class Context:
         self,
         environment: "Environment",
         parent: dict[str, t.Any],
-        name: t.Optional[str],
+        name: str | None,
         blocks: dict[str, t.Callable[["Context"], t.Iterator[str]]],
-        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
+        globals: t.MutableMapping[str, t.Any] | None = None,
     ):
         self.parent = parent
         self.vars: dict[str, t.Any] = {}
@@ -307,7 +307,7 @@ class Context:
                 " StopIteration exception"
             )
 
-    def derived(self, locals: t.Optional[dict[str, t.Any]] = None) -> "Context":
+    def derived(self, locals: dict[str, t.Any] | None = 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.
@@ -399,7 +399,7 @@ class LoopContext:
     #: Current iteration of the loop, starting at 0.
     index0 = -1
 
-    _length: t.Optional[int] = None
+    _length: int | None = None
     _after: t.Any = missing
     _current: t.Any = missing
     _before: t.Any = missing
@@ -593,7 +593,7 @@ class AsyncLoopContext(LoopContext):
 
     @staticmethod
     def _to_iterator(  # type: ignore
-        iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]],
+        iterable: t.Iterable[V] | t.AsyncIterable[V],
     ) -> t.AsyncIterator[V]:
         return auto_aiter(iterable)
 
@@ -671,7 +671,7 @@ class Macro:
         catch_kwargs: bool,
         catch_varargs: bool,
         caller: bool,
-        default_autoescape: t.Optional[bool] = None,
+        default_autoescape: bool | None = None,
     ):
         self._environment = environment
         self._func = func
@@ -817,9 +817,9 @@ class Undefined:
 
     def __init__(
         self,
-        hint: t.Optional[str] = None,
+        hint: str | None = None,
         obj: t.Any = missing,
-        name: t.Optional[str] = None,
+        name: str | None = None,
         exc: type[TemplateRuntimeError] = UndefinedError,
     ) -> None:
         self._undefined_hint = hint
index 1e221a83fb80bbc8f1bcfe3130711517d00667ce..05b3950b88da747a087d53afcfa36dce1f617d91 100644 (file)
@@ -285,9 +285,7 @@ class SandboxedEnvironment(Environment):
         """
         return self.unop_table[operator](arg)
 
-    def getitem(
-        self, obj: t.Any, argument: t.Union[str, t.Any]
-    ) -> t.Union[t.Any, Undefined]:
+    def getitem(self, obj: t.Any, argument: str | t.Any) -> t.Any | Undefined:
         """Subscribe an object from sandboxed code."""
         try:
             return obj[argument]
@@ -311,7 +309,7 @@ class SandboxedEnvironment(Environment):
                         return self.unsafe_undefined(obj, argument)
         return self.undefined(obj=obj, name=argument)
 
-    def getattr(self, obj: t.Any, attribute: str) -> t.Union[t.Any, Undefined]:
+    def getattr(self, obj: t.Any, attribute: str) -> t.Any | Undefined:
         """Subscribe an object from sandboxed code and prefer the
         attribute.  The attribute passed *must* be a bytestring.
         """
@@ -341,7 +339,7 @@ class SandboxedEnvironment(Environment):
             exc=SecurityError,
         )
 
-    def wrap_str_format(self, value: t.Any) -> t.Optional[t.Callable[..., str]]:
+    def wrap_str_format(self, value: t.Any) -> t.Callable[..., str] | None:
         """If the given value is a ``str.format`` or ``str.format_map`` method,
         return a new function than handles sandboxing. This is done at access
         rather than in :meth:`call`, so that calls made without ``call`` are
index 875300f5bb9214dae348335ed662ef820eda551a..b4034cbc80e755cee3cf50243d45d07a44b6b821 100644 (file)
@@ -161,7 +161,7 @@ def import_string(import_name: str, silent: bool = False) -> t.Any:
             raise
 
 
-def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO[t.Any]]:
+def open_if_exists(filename: str, mode: str = "rb") -> t.IO[t.Any] | None:
     """Returns a file descriptor for the filename if that file exists,
     otherwise ``None``.
     """
@@ -229,10 +229,10 @@ _email_re = re.compile(r"^\S+@\w[\w.-]*\.\w+$")
 
 def urlize(
     text: str,
-    trim_url_limit: t.Optional[int] = None,
-    rel: t.Optional[str] = None,
-    target: t.Optional[str] = None,
-    extra_schemes: t.Optional[t.Iterable[str]] = None,
+    trim_url_limit: int | None = None,
+    rel: str | None = None,
+    target: str | None = None,
+    extra_schemes: t.Iterable[str] | None = None,
 ) -> str:
     """Convert URLs in text into clickable links.
 
@@ -583,7 +583,7 @@ def select_autoescape(
     disabled_extensions: t.Collection[str] = (),
     default_for_string: bool = True,
     default: bool = False,
-) -> t.Callable[[t.Optional[str]], bool]:
+) -> t.Callable[[str | None], bool]:
     """Intelligently sets the initial value of autoescaping based on the
     filename of the template.  This is the recommended way to configure
     autoescaping if you do not want to write a custom function yourself.
@@ -621,7 +621,7 @@ def select_autoescape(
     enabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in enabled_extensions)
     disabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in disabled_extensions)
 
-    def autoescape(template_name: t.Optional[str]) -> bool:
+    def autoescape(template_name: str | None) -> bool:
         if template_name is None:
             return default_for_string
         template_name = template_name.lower()
@@ -635,7 +635,7 @@ def select_autoescape(
 
 
 def htmlsafe_json_dumps(
-    obj: t.Any, dumps: t.Optional[t.Callable[..., str]] = None, **kwargs: t.Any
+    obj: t.Any, dumps: t.Callable[..., str] | None = None, **kwargs: t.Any
 ) -> markupsafe.Markup:
     """Serialize an object to a string of JSON with :func:`json.dumps`,
     then replace HTML-unsafe characters with Unicode escapes and mark
index f25912e1ddd4d1d6a5f9dd5be87e87a1adee1ecc..edfa024512d31f4c93c2f742232cf18771658620 100644 (file)
@@ -25,7 +25,7 @@ class NodeVisitor:
     (return value `None`) the `generic_visit` visitor is used instead.
     """
 
-    def get_visitor(self, node: Node) -> "t.Optional[VisitCallable]":
+    def get_visitor(self, node: Node) -> "VisitCallable | None":
         """Return the visitor function for this node or `None` if no visitor
         exists for this node.  In that case the generic visit function is
         used instead.