]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
*: Update type annotations with py3.8 features
authorBen Darnell <ben@bendarnell.com>
Thu, 19 Mar 2026 14:06:12 +0000 (10:06 -0400)
committerBen Darnell <ben@bendarnell.com>
Thu, 19 Mar 2026 14:11:43 +0000 (10:11 -0400)
Automated change with pyupgrade (restricted to the typing plugins),
followed by manual removal of unused imports.

tornado/httputil.py
tornado/ioloop.py
tornado/locale.py
tornado/queues.py
tornado/util.py

index 7d40c23e4eee79d1f26e15de964889690d875c02..509245f74e2faec81c896575c98e91ba74c46a1e 100644 (file)
@@ -45,14 +45,9 @@ responses
 
 import typing
 from typing import (
-    Tuple,
     Iterable,
-    List,
     Mapping,
     Iterator,
-    Dict,
-    Union,
-    Optional,
     Awaitable,
     Generator,
     AnyStr,
@@ -167,7 +162,7 @@ class HTTPHeaders(collections.abc.MutableMapping[str, str]):
     """
 
     @typing.overload
-    def __init__(self, __arg: Mapping[str, List[str]]) -> None:
+    def __init__(self, __arg: Mapping[str, list[str]]) -> None:
         pass
 
     @typing.overload  # noqa: F811
@@ -175,7 +170,7 @@ class HTTPHeaders(collections.abc.MutableMapping[str, str]):
         pass
 
     @typing.overload  # noqa: F811
-    def __init__(self, *args: Tuple[str, str]) -> None:
+    def __init__(self, *args: tuple[str, str]) -> None:
         pass
 
     @typing.overload  # noqa: F811
@@ -191,7 +186,7 @@ class HTTPHeaders(collections.abc.MutableMapping[str, str]):
         # on demand (and cleared whenever the list is modified).
         self._as_list: dict[str, list[str]] = {}
         self._combined_cache: dict[str, str] = {}
-        self._last_key: Optional[str] = None
+        self._last_key: str | None = None
         if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], HTTPHeaders):
             # Copy constructor
             for k, v in args[0].get_all():
@@ -222,12 +217,12 @@ class HTTPHeaders(collections.abc.MutableMapping[str, str]):
         else:
             self[norm_name] = value
 
-    def get_list(self, name: str) -> List[str]:
+    def get_list(self, name: str) -> list[str]:
         """Returns all values for the given header as a list."""
         norm_name = _normalize_header(name)
         return self._as_list.get(norm_name, [])
 
-    def get_all(self) -> Iterable[Tuple[str, str]]:
+    def get_all(self) -> Iterable[tuple[str, str]]:
         """Returns an iterable of all (name, value) pairs.
 
         If a header has multiple values, multiple pairs will be
@@ -289,7 +284,7 @@ class HTTPHeaders(collections.abc.MutableMapping[str, str]):
             )
 
     @classmethod
-    def parse(cls, headers: str, *, _chars_are_bytes: bool = True) -> "HTTPHeaders":
+    def parse(cls, headers: str, *, _chars_are_bytes: bool = True) -> HTTPHeaders:
         """Returns a dictionary from HTTP header text.
 
         >>> h = HTTPHeaders.parse("Content-Type: text/html\\r\\nContent-Length: 42\\r\\n")
@@ -361,7 +356,7 @@ class HTTPHeaders(collections.abc.MutableMapping[str, str]):
     def __iter__(self) -> Iterator[typing.Any]:
         return iter(self._as_list)
 
-    def copy(self) -> "HTTPHeaders":
+    def copy(self) -> HTTPHeaders:
         # defined in dict but not in MutableMapping.
         return HTTPHeaders(self)
 
@@ -481,20 +476,20 @@ class HTTPServerRequest:
     query: str
 
     # HACK: Used for stream_request_body
-    _body_future: "Future[None]"
+    _body_future: Future[None]
 
     def __init__(
         self,
-        method: Optional[str] = None,
-        uri: Optional[str] = None,
+        method: str | None = None,
+        uri: str | None = None,
         version: str = "HTTP/1.0",
-        headers: Optional[HTTPHeaders] = None,
-        body: Optional[bytes] = None,
-        host: Optional[str] = None,
-        files: Optional[Dict[str, List["HTTPFile"]]] = None,
-        connection: Optional["HTTPConnection"] = None,
-        start_line: Optional["RequestStartLine"] = None,
-        server_connection: Optional[object] = None,
+        headers: HTTPHeaders | None = None,
+        body: bytes | None = None,
+        host: str | None = None,
+        files: dict[str, list[HTTPFile]] | None = None,
+        connection: HTTPConnection | None = None,
+        start_line: RequestStartLine | None = None,
+        server_connection: object | None = None,
     ) -> None:
         if start_line is not None:
             method, uri, version = start_line
@@ -550,10 +545,10 @@ class HTTPServerRequest:
             self.path, sep, self.query = uri.partition("?")
         self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)
         self.query_arguments = copy.deepcopy(self.arguments)
-        self.body_arguments: Dict[str, List[bytes]] = {}
+        self.body_arguments: dict[str, list[bytes]] = {}
 
     @property
-    def cookies(self) -> Dict[str, http.cookies.Morsel]:
+    def cookies(self) -> dict[str, http.cookies.Morsel]:
         """A dictionary of ``http.cookies.Morsel`` objects."""
         if not hasattr(self, "_cookies"):
             self._cookies: http.cookies.SimpleCookie = http.cookies.SimpleCookie()
@@ -584,9 +579,7 @@ class HTTPServerRequest:
         else:
             return self._finish_time - self._start_time
 
-    def get_ssl_certificate(
-        self, binary_form: bool = False
-    ) -> Union[None, Dict, bytes]:
+    def get_ssl_certificate(self, binary_form: bool = False) -> None | dict | bytes:
         """Returns the client's SSL certificate, if any.
 
         To use client certificates, the HTTPServer's
@@ -659,8 +652,8 @@ class HTTPServerConnectionDelegate:
     """
 
     def start_request(
-        self, server_conn: object, request_conn: "HTTPConnection"
-    ) -> "HTTPMessageDelegate":
+        self, server_conn: object, request_conn: HTTPConnection
+    ) -> HTTPMessageDelegate:
         """This method is called by the server when a new request has started.
 
         :arg server_conn: is an opaque object representing the long-lived
@@ -690,9 +683,9 @@ class HTTPMessageDelegate:
     # TODO: genericize this class to avoid exposing the Union.
     def headers_received(
         self,
-        start_line: Union["RequestStartLine", "ResponseStartLine"],
+        start_line: RequestStartLine | ResponseStartLine,
         headers: HTTPHeaders,
-    ) -> Optional[Awaitable[None]]:
+    ) -> Awaitable[None] | None:
         """Called when the HTTP headers have been received and parsed.
 
         :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`
@@ -707,7 +700,7 @@ class HTTPMessageDelegate:
         """
         pass
 
-    def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]:
+    def data_received(self, chunk: bytes) -> Awaitable[None] | None:
         """Called when a chunk of data has been received.
 
         May return a `.Future` for flow control.
@@ -735,10 +728,10 @@ class HTTPConnection:
 
     def write_headers(
         self,
-        start_line: Union["RequestStartLine", "ResponseStartLine"],
+        start_line: RequestStartLine | ResponseStartLine,
         headers: HTTPHeaders,
-        chunk: Optional[bytes] = None,
-    ) -> "Future[None]":
+        chunk: bytes | None = None,
+    ) -> Future[None]:
         """Write an HTTP header block.
 
         :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`.
@@ -757,7 +750,7 @@ class HTTPConnection:
         """
         raise NotImplementedError()
 
-    def write(self, chunk: bytes) -> "Future[None]":
+    def write(self, chunk: bytes) -> Future[None]:
         """Writes a chunk of body data.
 
         Returns a future for flow control.
@@ -775,9 +768,7 @@ class HTTPConnection:
 
 def url_concat(
     url: str,
-    args: Union[
-        None, Dict[str, str], List[Tuple[str, str]], Tuple[Tuple[str, str], ...]
-    ],
+    args: None | dict[str, str] | list[tuple[str, str]] | tuple[tuple[str, str], ...],
 ) -> str:
     """Concatenate url and arguments regardless of whether
     url has existing query parameters.
@@ -838,7 +829,7 @@ class HTTPFile(ObjectDict):
 
 def _parse_request_range(
     range_header: str,
-) -> Optional[Tuple[Optional[int], Optional[int]]]:
+) -> tuple[int | None, int | None] | None:
     """Parses a Range header.
 
     Returns either ``None`` or tuple ``(start, end)``.
@@ -887,7 +878,7 @@ def _parse_request_range(
     return (start, end)
 
 
-def _get_content_range(start: Optional[int], end: Optional[int], total: int) -> str:
+def _get_content_range(start: int | None, end: int | None, total: int) -> str:
     """Returns a suitable Content-Range header:
 
     >>> print(_get_content_range(None, 1, 4))
@@ -902,7 +893,7 @@ def _get_content_range(start: Optional[int], end: Optional[int], total: int) ->
     return f"bytes {start}-{end}/{total}"
 
 
-def _int_or_none(val: str) -> Optional[int]:
+def _int_or_none(val: str) -> int | None:
     val = val.strip()
     if val == "":
         return None
@@ -988,11 +979,11 @@ def set_parse_body_config(config: ParseBodyConfig) -> None:
 def parse_body_arguments(
     content_type: str,
     body: bytes,
-    arguments: Dict[str, List[bytes]],
-    files: Dict[str, List[HTTPFile]],
-    headers: Optional[HTTPHeaders] = None,
+    arguments: dict[str, list[bytes]],
+    files: dict[str, list[HTTPFile]],
+    headers: HTTPHeaders | None = None,
     *,
-    config: Optional[ParseBodyConfig] = None,
+    config: ParseBodyConfig | None = None,
 ) -> None:
     """Parses a form request body.
 
@@ -1043,10 +1034,10 @@ def parse_body_arguments(
 def parse_multipart_form_data(
     boundary: bytes,
     data: bytes,
-    arguments: Dict[str, List[bytes]],
-    files: Dict[str, List[HTTPFile]],
+    arguments: dict[str, list[bytes]],
+    files: dict[str, list[HTTPFile]],
     *,
-    config: Optional[ParseMultipartConfig] = None,
+    config: ParseMultipartConfig | None = None,
 ) -> None:
     """Parses a ``multipart/form-data`` body.
 
@@ -1105,7 +1096,7 @@ def parse_multipart_form_data(
 
 
 def format_timestamp(
-    ts: Union[int, float, tuple, time.struct_time, datetime.datetime],
+    ts: int | float | tuple | time.struct_time | datetime.datetime,
 ) -> str:
     """Formats a timestamp in the format used by HTTP.
 
@@ -1198,7 +1189,7 @@ def parse_response_start_line(line: str) -> ResponseStartLine:
 # RFCs for multipart/form-data) before making this change.
 
 
-def _parseparam(s: str) -> Generator[str, None, None]:
+def _parseparam(s: str) -> Generator[str]:
     start = 0
     while s.find(";", start) == start:
         start += 1
@@ -1216,7 +1207,7 @@ def _parseparam(s: str) -> Generator[str, None, None]:
         start = end
 
 
-def _parse_header(line: str) -> Tuple[str, Dict[str, str]]:
+def _parse_header(line: str) -> tuple[str, dict[str, str]]:
     r"""Parse a Content-type like header.
 
     Return the main content-type and a dictionary of options.
@@ -1251,7 +1242,7 @@ def _parse_header(line: str) -> Tuple[str, Dict[str, str]]:
     return key, pdict
 
 
-def _encode_header(key: str, pdict: Dict[str, str]) -> str:
+def _encode_header(key: str, pdict: dict[str, str]) -> str:
     """Inverse of _parse_header.
 
     >>> _encode_header('permessage-deflate',
@@ -1271,9 +1262,7 @@ def _encode_header(key: str, pdict: Dict[str, str]) -> str:
     return "; ".join(out)
 
 
-def encode_username_password(
-    username: Union[str, bytes], password: Union[str, bytes]
-) -> bytes:
+def encode_username_password(username: str | bytes, password: str | bytes) -> bytes:
     """Encodes a username/password pair in the format used by HTTP auth.
 
     The return value is a byte string in the form ``username:password``.
@@ -1296,7 +1285,7 @@ def doctests() -> unittest.TestSuite:
 _netloc_re = re.compile(r"^(.+):(\d+)$")
 
 
-def split_host_and_port(netloc: str) -> Tuple[str, Optional[int]]:
+def split_host_and_port(netloc: str) -> tuple[str, int | None]:
     """Returns ``(host, port)`` tuple from ``netloc``.
 
     Returned ``port`` will be ``None`` if not present.
@@ -1306,14 +1295,14 @@ def split_host_and_port(netloc: str) -> Tuple[str, Optional[int]]:
     match = _netloc_re.match(netloc)
     if match:
         host = match.group(1)
-        port: Optional[int] = int(match.group(2))
+        port: int | None = int(match.group(2))
     else:
         host = netloc
         port = None
     return (host, port)
 
 
-def qs_to_qsl(qs: Dict[str, List[AnyStr]]) -> Iterable[Tuple[str, AnyStr]]:
+def qs_to_qsl(qs: dict[str, list[AnyStr]]) -> Iterable[tuple[str, AnyStr]]:
     """Generator converting a result of ``parse_qs`` back to name-value pairs.
 
     .. versionadded:: 5.0
@@ -1360,7 +1349,7 @@ def _unquote_cookie(s: str) -> str:
     return _unquote_sub(_unquote_replace, s)
 
 
-def parse_cookie(cookie: str) -> Dict[str, str]:
+def parse_cookie(cookie: str) -> dict[str, str]:
     """Parse a ``Cookie`` HTTP header into a dict of name/value pairs.
 
     This function attempts to mimic browser cookie parsing behavior;
index 34bb3942ea7f8361507134ab4620ba1ffb7b6b00..60dd3e9beff1a2379e0b0a9e126c6e73c4848285 100644 (file)
@@ -49,7 +49,7 @@ from tornado.log import app_log
 from tornado.util import Configurable, TimeoutError, import_object
 
 import typing
-from typing import Union, Any, Type, Optional, Callable, TypeVar, Tuple, Awaitable
+from typing import Union, Any, Type, Optional, Callable, TypeVar, Awaitable
 
 if typing.TYPE_CHECKING:
     from typing import Dict, List, Set, TypedDict  # noqa: F401
@@ -156,7 +156,7 @@ class IOLoop(Configurable):
     ERROR = 0x018
 
     # In Python 3, _ioloop_for_asyncio maps from asyncio loops to IOLoops.
-    _ioloop_for_asyncio: Dict[asyncio.AbstractEventLoop, IOLoop] = dict()
+    _ioloop_for_asyncio: dict[asyncio.AbstractEventLoop, IOLoop] = dict()
 
     # Maintain a set of all pending tasks to follow the warning in the docs
     # of asyncio.create_tasks:
@@ -168,11 +168,11 @@ class IOLoop(Configurable):
     # https://github.com/python/cpython/issues/91887
     # If that change is accepted, this can eventually be removed.
     # If it is not, we will consider the rationale and may remove this.
-    _pending_tasks: Set[Future] = set()
+    _pending_tasks: set[Future] = set()
 
     @classmethod
     def configure(
-        cls, impl: "Union[None, str, Type[Configurable]]", **kwargs: Any
+        cls, impl: Union[None, str, Type[Configurable]], **kwargs: Any
     ) -> None:
         from tornado.platform.asyncio import BaseAsyncIOLoop
 
@@ -183,7 +183,7 @@ class IOLoop(Configurable):
         super().configure(impl, **kwargs)
 
     @staticmethod
-    def instance() -> "IOLoop":
+    def instance() -> IOLoop:
         """Deprecated alias for `IOLoop.current()`.
 
         .. versionchanged:: 5.0
@@ -236,16 +236,16 @@ class IOLoop(Configurable):
 
     @typing.overload
     @staticmethod
-    def current() -> "IOLoop":
+    def current() -> IOLoop:
         pass
 
     @typing.overload
     @staticmethod
-    def current(instance: bool = True) -> Optional["IOLoop"]:  # noqa: F811
+    def current(instance: bool = True) -> IOLoop | None:  # noqa: F811
         pass
 
     @staticmethod
-    def current(instance: bool = True) -> Optional["IOLoop"]:  # noqa: F811
+    def current(instance: bool = True) -> IOLoop | None:  # noqa: F811
         """Returns the current thread's `IOLoop`.
 
         If an `IOLoop` is currently running or has been marked as
@@ -284,7 +284,7 @@ class IOLoop(Configurable):
             if instance:
                 from tornado.platform.asyncio import AsyncIOMainLoop
 
-                current: Optional[IOLoop] = AsyncIOMainLoop()
+                current: IOLoop | None = AsyncIOMainLoop()
             else:
                 current = None
         return current
@@ -351,11 +351,11 @@ class IOLoop(Configurable):
         pass
 
     @classmethod
-    def configurable_base(cls) -> Type[Configurable]:
+    def configurable_base(cls) -> type[Configurable]:
         return IOLoop
 
     @classmethod
-    def configurable_default(cls) -> Type[Configurable]:
+    def configurable_default(cls) -> type[Configurable]:
         from tornado.platform.asyncio import AsyncIOLoop
 
         return AsyncIOLoop
@@ -404,7 +404,7 @@ class IOLoop(Configurable):
         pass
 
     def add_handler(  # noqa: F811
-        self, fd: Union[int, _Selectable], handler: Callable[..., None], events: int
+        self, fd: int | _Selectable, handler: Callable[..., None], events: int
     ) -> None:
         """Registers the given handler to receive the given events for ``fd``.
 
@@ -422,7 +422,7 @@ class IOLoop(Configurable):
         """
         raise NotImplementedError()
 
-    def update_handler(self, fd: Union[int, _Selectable], events: int) -> None:
+    def update_handler(self, fd: int | _Selectable, events: int) -> None:
         """Changes the events we listen for ``fd``.
 
         .. versionchanged:: 4.0
@@ -431,7 +431,7 @@ class IOLoop(Configurable):
         """
         raise NotImplementedError()
 
-    def remove_handler(self, fd: Union[int, _Selectable]) -> None:
+    def remove_handler(self, fd: int | _Selectable) -> None:
         """Stop listening for events on ``fd``.
 
         .. versionchanged:: 4.0
@@ -461,7 +461,7 @@ class IOLoop(Configurable):
         """
         raise NotImplementedError()
 
-    def run_sync(self, func: Callable, timeout: Optional[float] = None) -> Any:
+    def run_sync(self, func: Callable, timeout: float | None = None) -> Any:
         """Starts the `IOLoop`, runs the given function, and stops the loop.
 
         The function must return either an awaitable object or
@@ -494,9 +494,12 @@ class IOLoop(Configurable):
            ``tornado.util.TimeoutError`` is now an alias to ``asyncio.TimeoutError``.
         """
         if typing.TYPE_CHECKING:
-            FutureCell = TypedDict(  # noqa: F841
-                "FutureCell", {"future": Optional[Future], "timeout_called": bool}
-            )
+
+            class FutureCell(TypedDict):
+                # noqa: F841
+                future: Optional[Future]
+                timeout_called: bool
+
         future_cell: FutureCell = {"future": None, "timeout_called": False}
 
         def run() -> None:
@@ -564,7 +567,7 @@ class IOLoop(Configurable):
 
     def add_timeout(
         self,
-        deadline: Union[float, datetime.timedelta],
+        deadline: float | datetime.timedelta,
         callback: Callable,
         *args: Any,
         **kwargs: Any,
@@ -683,8 +686,8 @@ class IOLoop(Configurable):
 
     def add_future(
         self,
-        future: "Union[Future[_T], concurrent.futures.Future[_T]]",
-        callback: Callable[["Future[_T]"], None],
+        future: Union[Future[_T], concurrent.futures.Future[_T]],
+        callback: Callable[[Future[_T]], None],
     ) -> None:
         """Schedules a callback on the ``IOLoop`` when the given
         `.Future` is finished.
@@ -716,10 +719,10 @@ class IOLoop(Configurable):
 
     def run_in_executor(
         self,
-        executor: Optional[concurrent.futures.Executor],
+        executor: concurrent.futures.Executor | None,
         func: Callable[..., _T],
         *args: Any,
-    ) -> "Future[_T]":
+    ) -> Future[_T]:
         """Runs a function in a ``concurrent.futures.Executor``. If
         ``executor`` is ``None``, the IO loop's default executor will be used.
 
@@ -783,9 +786,7 @@ class IOLoop(Configurable):
         """Avoid unhandled-exception warnings from spawned coroutines."""
         future.result()
 
-    def split_fd(
-        self, fd: Union[int, _Selectable]
-    ) -> Tuple[int, Union[int, _Selectable]]:
+    def split_fd(self, fd: int | _Selectable) -> tuple[int, int | _Selectable]:
         # """Returns an (fd, obj) pair from an ``fd`` parameter.
 
         # We accept both raw file descriptors and file-like objects as
@@ -805,7 +806,7 @@ class IOLoop(Configurable):
             return fd, fd
         return fd.fileno(), fd
 
-    def close_fd(self, fd: Union[int, _Selectable]) -> None:
+    def close_fd(self, fd: int | _Selectable) -> None:
         # """Utility method to close an ``fd``.
 
         # If ``fd`` is a file-like object, we close it directly; otherwise
@@ -845,7 +846,7 @@ class _Timeout:
             raise TypeError("Unsupported deadline %r" % deadline)
         self.deadline = deadline
         self.callback = callback
-        self.tdeadline: Tuple[float, int] = (
+        self.tdeadline: tuple[float, int] = (
             deadline,
             next(io_loop._timeout_counter),
         )
@@ -854,10 +855,10 @@ class _Timeout:
     # to guarantee a consistent ordering.  The heapq module uses __le__
     # in python2.5, and __lt__ in 2.6+ (sort() and most other comparisons
     # use __lt__).
-    def __lt__(self, other: "_Timeout") -> bool:
+    def __lt__(self, other: _Timeout) -> bool:
         return self.tdeadline < other.tdeadline
 
-    def __le__(self, other: "_Timeout") -> bool:
+    def __le__(self, other: _Timeout) -> bool:
         return self.tdeadline <= other.tdeadline
 
 
@@ -901,8 +902,8 @@ class PeriodicCallback:
 
     def __init__(
         self,
-        callback: Callable[[], Optional[Awaitable]],
-        callback_time: Union[datetime.timedelta, float],
+        callback: Callable[[], Awaitable | None],
+        callback_time: datetime.timedelta | float,
         jitter: float = 0,
     ) -> None:
         self.callback = callback
index 4db81578c20daeccdccd7031703083d50925b67d..ed071926d5ef4207ac2928c28e9cf73c5c8c8ff1 100644 (file)
@@ -52,16 +52,16 @@ from tornado.log import gen_log
 
 from tornado._locale_data import LOCALE_NAMES
 
-from typing import Iterable, Any, Union, Dict, Optional
+from typing import Iterable, Any
 
 _default_locale = "en_US"
-_translations: Dict[str, Any] = {}
+_translations: dict[str, Any] = {}
 _supported_locales = frozenset([_default_locale])
 _use_gettext = False
 CONTEXT_SEPARATOR = "\x04"
 
 
-def get(*locale_codes: str) -> "Locale":
+def get(*locale_codes: str) -> Locale:
     """Returns the closest match for the given locale codes.
 
     We iterate over all given locale codes in order. If we have a tight
@@ -89,7 +89,7 @@ def set_default_locale(code: str) -> None:
     _supported_locales = frozenset(list(_translations.keys()) + [_default_locale])
 
 
-def load_translations(directory: str, encoding: Optional[str] = None) -> None:
+def load_translations(directory: str, encoding: str | None = None) -> None:
     """Loads translations from CSV files in a directory.
 
     Translations are strings with optional Python-style named placeholders
@@ -230,10 +230,10 @@ class Locale:
     call `get` or `get_closest` to get a Locale object.
     """
 
-    _cache: Dict[str, Locale] = {}
+    _cache: dict[str, Locale] = {}
 
     @classmethod
-    def get_closest(cls, *locale_codes: str) -> "Locale":
+    def get_closest(cls, *locale_codes: str) -> Locale:
         """Returns the closest match for the given locale code."""
         for code in locale_codes:
             if not code:
@@ -251,7 +251,7 @@ class Locale:
         return cls.get(_default_locale)
 
     @classmethod
-    def get(cls, code: str) -> "Locale":
+    def get(cls, code: str) -> Locale:
         """Returns the Locale for the given locale code.
 
         If it is not supported, we raise an exception.
@@ -306,8 +306,8 @@ class Locale:
     def translate(
         self,
         message: str,
-        plural_message: Optional[str] = None,
-        count: Optional[int] = None,
+        plural_message: str | None = None,
+        count: int | None = None,
     ) -> str:
         """Returns the translation for the given message for this locale.
 
@@ -322,14 +322,14 @@ class Locale:
         self,
         context: str,
         message: str,
-        plural_message: Optional[str] = None,
-        count: Optional[int] = None,
+        plural_message: str | None = None,
+        count: int | None = None,
     ) -> str:
         raise NotImplementedError()
 
     def format_date(
         self,
-        date: Union[int, float, datetime.datetime],
+        date: int | float | datetime.datetime,
         gmt_offset: int = 0,
         relative: bool = True,
         shorter: bool = False,
@@ -487,15 +487,15 @@ class Locale:
 class CSVLocale(Locale):
     """Locale implementation using tornado's CSV translation format."""
 
-    def __init__(self, code: str, translations: Dict[str, Dict[str, str]]) -> None:
+    def __init__(self, code: str, translations: dict[str, dict[str, str]]) -> None:
         self.translations = translations
         super().__init__(code)
 
     def translate(
         self,
         message: str,
-        plural_message: Optional[str] = None,
-        count: Optional[int] = None,
+        plural_message: str | None = None,
+        count: int | None = None,
     ) -> str:
         if plural_message is not None:
             assert count is not None
@@ -512,8 +512,8 @@ class CSVLocale(Locale):
         self,
         context: str,
         message: str,
-        plural_message: Optional[str] = None,
-        count: Optional[int] = None,
+        plural_message: str | None = None,
+        count: int | None = None,
     ) -> str:
         if self.translations:
             gen_log.warning("pgettext is not supported by CSVLocale")
@@ -533,8 +533,8 @@ class GettextLocale(Locale):
     def translate(
         self,
         message: str,
-        plural_message: Optional[str] = None,
-        count: Optional[int] = None,
+        plural_message: str | None = None,
+        count: int | None = None,
     ) -> str:
         if plural_message is not None:
             assert count is not None
@@ -546,8 +546,8 @@ class GettextLocale(Locale):
         self,
         context: str,
         message: str,
-        plural_message: Optional[str] = None,
-        count: Optional[int] = None,
+        plural_message: str | None = None,
+        count: int | None = None,
     ) -> str:
         """Allows to set context for translation, accepts plural forms.
 
index 1fee1c3203b3f871ba3e64f513eb6d87b0352a29..86eb27e8ecebb0b9a2d37997feece8e52df7ca77 100644 (file)
@@ -35,7 +35,7 @@ from tornado import gen, ioloop
 from tornado.concurrent import Future, future_set_result_unless_cancelled
 from tornado.locks import Event
 
-from typing import Union, TypeVar, Generic, Awaitable, Optional
+from typing import TypeVar, Generic, Awaitable
 import typing
 
 if typing.TYPE_CHECKING:
@@ -58,9 +58,7 @@ class QueueFull(Exception):
     pass
 
 
-def _set_timeout(
-    future: Future, timeout: Union[None, float, datetime.timedelta]
-) -> None:
+def _set_timeout(future: Future, timeout: None | float | datetime.timedelta) -> None:
     if timeout:
 
         def on_timeout() -> None:
@@ -73,7 +71,7 @@ def _set_timeout(
 
 
 class _QueueIterator(Generic[_T]):
-    def __init__(self, q: "Queue[_T]") -> None:
+    def __init__(self, q: Queue[_T]) -> None:
         self.q = q
 
     def __anext__(self) -> Awaitable[_T]:
@@ -162,7 +160,7 @@ class Queue(Generic[_T]):
         self._maxsize = maxsize
         self._init()
         self._getters: Deque[Future[_T]] = collections.deque([])
-        self._putters: Deque[Tuple[_T, Future[None]]] = collections.deque([])
+        self._putters: Deque[tuple[_T, Future[None]]] = collections.deque([])
         self._unfinished_tasks = 0
         self._finished = Event()
         self._finished.set()
@@ -186,8 +184,8 @@ class Queue(Generic[_T]):
             return self.qsize() >= self.maxsize
 
     def put(
-        self, item: _T, timeout: Optional[Union[float, datetime.timedelta]] = None
-    ) -> "Future[None]":
+        self, item: _T, timeout: float | datetime.timedelta | None = None
+    ) -> Future[None]:
         """Put an item into the queue, perhaps waiting until there is room.
 
         Returns a Future, which raises `tornado.util.TimeoutError` after a
@@ -224,9 +222,7 @@ class Queue(Generic[_T]):
         else:
             self.__put_internal(item)
 
-    def get(
-        self, timeout: Optional[Union[float, datetime.timedelta]] = None
-    ) -> Awaitable[_T]:
+    def get(self, timeout: float | datetime.timedelta | None = None) -> Awaitable[_T]:
         """Remove and return an item from the queue.
 
         Returns an awaitable which resolves once an item is available, or raises
@@ -292,7 +288,7 @@ class Queue(Generic[_T]):
             self._finished.set()
 
     def join(
-        self, timeout: Optional[Union[float, datetime.timedelta]] = None
+        self, timeout: float | datetime.timedelta | None = None
     ) -> Awaitable[None]:
         """Block until all items in the queue are processed.
 
index 8925f7fe326d8605e537f39be874170eb595dd78..78a3276d1731b6a2602c7d0f23858ed52efefe56 100644 (file)
@@ -22,11 +22,8 @@ import zlib
 
 from typing import (
     Any,
-    Optional,
     Dict,
     Mapping,
-    List,
-    Tuple,
     Match,
     Callable,
     Type,
@@ -137,7 +134,7 @@ def import_object(name: str) -> Any:
 
 
 def exec_in(
-    code: Any, glob: Dict[str, Any], loc: Optional[Optional[Mapping[str, Any]]] = None
+    code: Any, glob: dict[str, Any], loc: Mapping[str, Any] | None | None = None
 ) -> None:
     if isinstance(code, str):
         # exec(string) inherits the caller's future imports; compile
@@ -147,7 +144,7 @@ def exec_in(
 
 
 def raise_exc_info(
-    exc_info: Tuple[Optional[type], Optional[BaseException], Optional["TracebackType"]],
+    exc_info: tuple[type | None, BaseException | None, TracebackType | None],
 ) -> typing.NoReturn:
     try:
         if exc_info[1] is not None:
@@ -160,7 +157,7 @@ def raise_exc_info(
         exc_info = (None, None, None)
 
 
-def errno_from_exception(e: BaseException) -> Optional[int]:
+def errno_from_exception(e: BaseException) -> int | None:
     """Provides the errno from an Exception object.
 
     There are cases that the errno attribute was not set so we pull
@@ -238,12 +235,12 @@ class Configurable:
     # There may be a clever way to use generics here to get more
     # precise types (i.e. for a particular Configurable subclass T,
     # all the types are subclasses of T, not just Configurable).
-    __impl_class: Optional[Type["Configurable"]] = None
-    __impl_kwargs: Optional[Dict[str, Any]] = None
+    __impl_class: type[Configurable] | None = None
+    __impl_kwargs: dict[str, Any] | None = None
 
     def __new__(cls, *args: Any, **kwargs: Any) -> Any:
         base = cls.configurable_base()
-        init_kwargs: Dict[str, Any] = {}
+        init_kwargs: dict[str, Any] = {}
         if cls is base:
             impl = cls.configured_class()
             if base.__impl_kwargs:
@@ -262,7 +259,7 @@ class Configurable:
         return instance
 
     @classmethod
-    def configurable_base(cls) -> Type[Configurable]:
+    def configurable_base(cls) -> type[Configurable]:
         """Returns the base class of a configurable hierarchy.
 
         This will normally return the class in which it is defined.
@@ -273,7 +270,7 @@ class Configurable:
         raise NotImplementedError()
 
     @classmethod
-    def configurable_default(cls) -> Type[Configurable]:
+    def configurable_default(cls) -> type[Configurable]:
         """Returns the implementation class to be used if none is configured."""
         raise NotImplementedError()
 
@@ -290,9 +287,7 @@ class Configurable:
     """
 
     @classmethod
-    def configure(
-        cls, impl: Union[None, str, Type[Configurable]], **kwargs: Any
-    ) -> None:
+    def configure(cls, impl: None | str | type[Configurable], **kwargs: Any) -> None:
         """Sets the class to use when the base class is instantiated.
 
         Keyword arguments will be saved and added to the arguments passed
@@ -308,7 +303,7 @@ class Configurable:
         base.__impl_kwargs = kwargs
 
     @classmethod
-    def configured_class(cls) -> Type[Configurable]:
+    def configured_class(cls) -> type[Configurable]:
         """Returns the currently configured class."""
         base = cls.configurable_base()
         # Manually mangle the private name to see whether this base
@@ -325,13 +320,13 @@ class Configurable:
     @classmethod
     def _save_configuration(
         cls,
-    ) -> Tuple[Optional[Type[Configurable]], Optional[Dict[str, Any]]]:
+    ) -> tuple[type[Configurable] | None, dict[str, Any] | None]:
         base = cls.configurable_base()
         return (base.__impl_class, base.__impl_kwargs)
 
     @classmethod
     def _restore_configuration(
-        cls, saved: Tuple[Optional[Type[Configurable]], Optional[Dict[str, Any]]]
+        cls, saved: tuple[type[Configurable] | None, dict[str, Any] | None]
     ) -> None:
         base = cls.configurable_base()
         base.__impl_class = saved[0]
@@ -349,12 +344,12 @@ class ArgReplacer:
     def __init__(self, func: Callable, name: str) -> None:
         self.name = name
         try:
-            self.arg_pos: Optional[int] = self._getargnames(func).index(name)
+            self.arg_pos: int | None = self._getargnames(func).index(name)
         except ValueError:
             # Not a positional parameter
             self.arg_pos = None
 
-    def _getargnames(self, func: Callable) -> List[str]:
+    def _getargnames(self, func: Callable) -> list[str]:
         try:
             return getfullargspec(func).args
         except TypeError:
@@ -370,7 +365,7 @@ class ArgReplacer:
             raise
 
     def get_old_value(
-        self, args: Sequence[Any], kwargs: Dict[str, Any], default: Any = None
+        self, args: Sequence[Any], kwargs: dict[str, Any], default: Any = None
     ) -> Any:
         """Returns the old value of the named argument without replacing it.
 
@@ -382,8 +377,8 @@ class ArgReplacer:
             return kwargs.get(self.name, default)
 
     def replace(
-        self, new_value: Any, args: Sequence[Any], kwargs: Dict[str, Any]
-    ) -> Tuple[Any, Sequence[Any], Dict[str, Any]]:
+        self, new_value: Any, args: Sequence[Any], kwargs: dict[str, Any]
+    ) -> tuple[Any, Sequence[Any], dict[str, Any]]:
         """Replace the named argument in ``args, kwargs`` with ``new_value``.
 
         Returns ``(old_value, args, kwargs)``.  The returned ``args`` and