]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
Use `__future__.annotations` (#3068)
authorKar Petrosyan <92274156+karpetrosyan@users.noreply.github.com>
Wed, 24 Jan 2024 14:30:22 +0000 (06:30 -0800)
committerGitHub <noreply@github.com>
Wed, 24 Jan 2024 14:30:22 +0000 (14:30 +0000)
* Switch to new typing style

* lint

25 files changed:
httpx/_api.py
httpx/_auth.py
httpx/_client.py
httpx/_config.py
httpx/_content.py
httpx/_decoders.py
httpx/_exceptions.py
httpx/_main.py
httpx/_models.py
httpx/_multipart.py
httpx/_status_codes.py
httpx/_transports/asgi.py
httpx/_transports/base.py
httpx/_transports/default.py
httpx/_transports/mock.py
httpx/_transports/wsgi.py
httpx/_urlparse.py
httpx/_urls.py
httpx/_utils.py
tests/client/test_async_client.py
tests/client/test_client.py
tests/test_decoders.py
tests/test_exceptions.py
tests/test_multipart.py
tests/test_wsgi.py

index c7af947218af727229b5d77e4918113f894a6d99..b5821cc49e6cc48e1f2c2711fb2ef5ae18f68b78 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 from contextlib import contextmanager
 
@@ -25,20 +27,20 @@ def request(
     method: str,
     url: URLTypes,
     *,
-    params: typing.Optional[QueryParamTypes] = None,
-    content: typing.Optional[RequestContent] = None,
-    data: typing.Optional[RequestData] = None,
-    files: typing.Optional[RequestFiles] = None,
-    json: typing.Optional[typing.Any] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    params: QueryParamTypes | None = None,
+    content: RequestContent | None = None,
+    data: RequestData | None = None,
+    files: RequestFiles | None = None,
+    json: typing.Any | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     follow_redirects: bool = False,
     verify: VerifyTypes = True,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     trust_env: bool = True,
 ) -> Response:
     """
@@ -120,20 +122,20 @@ def stream(
     method: str,
     url: URLTypes,
     *,
-    params: typing.Optional[QueryParamTypes] = None,
-    content: typing.Optional[RequestContent] = None,
-    data: typing.Optional[RequestData] = None,
-    files: typing.Optional[RequestFiles] = None,
-    json: typing.Optional[typing.Any] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    params: QueryParamTypes | None = None,
+    content: RequestContent | None = None,
+    data: RequestData | None = None,
+    files: RequestFiles | None = None,
+    json: typing.Any | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     follow_redirects: bool = False,
     verify: VerifyTypes = True,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     trust_env: bool = True,
 ) -> typing.Iterator[Response]:
     """
@@ -173,14 +175,14 @@ def stream(
 def get(
     url: URLTypes,
     *,
-    params: typing.Optional[QueryParamTypes] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    params: QueryParamTypes | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     follow_redirects: bool = False,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     trust_env: bool = True,
@@ -213,14 +215,14 @@ def get(
 def options(
     url: URLTypes,
     *,
-    params: typing.Optional[QueryParamTypes] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    params: QueryParamTypes | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     follow_redirects: bool = False,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     trust_env: bool = True,
@@ -253,14 +255,14 @@ def options(
 def head(
     url: URLTypes,
     *,
-    params: typing.Optional[QueryParamTypes] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    params: QueryParamTypes | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     follow_redirects: bool = False,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     trust_env: bool = True,
@@ -293,18 +295,18 @@ def head(
 def post(
     url: URLTypes,
     *,
-    content: typing.Optional[RequestContent] = None,
-    data: typing.Optional[RequestData] = None,
-    files: typing.Optional[RequestFiles] = None,
-    json: typing.Optional[typing.Any] = None,
-    params: typing.Optional[QueryParamTypes] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    content: RequestContent | None = None,
+    data: RequestData | None = None,
+    files: RequestFiles | None = None,
+    json: typing.Any | None = None,
+    params: QueryParamTypes | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     follow_redirects: bool = False,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     trust_env: bool = True,
@@ -338,18 +340,18 @@ def post(
 def put(
     url: URLTypes,
     *,
-    content: typing.Optional[RequestContent] = None,
-    data: typing.Optional[RequestData] = None,
-    files: typing.Optional[RequestFiles] = None,
-    json: typing.Optional[typing.Any] = None,
-    params: typing.Optional[QueryParamTypes] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    content: RequestContent | None = None,
+    data: RequestData | None = None,
+    files: RequestFiles | None = None,
+    json: typing.Any | None = None,
+    params: QueryParamTypes | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     follow_redirects: bool = False,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     trust_env: bool = True,
@@ -383,18 +385,18 @@ def put(
 def patch(
     url: URLTypes,
     *,
-    content: typing.Optional[RequestContent] = None,
-    data: typing.Optional[RequestData] = None,
-    files: typing.Optional[RequestFiles] = None,
-    json: typing.Optional[typing.Any] = None,
-    params: typing.Optional[QueryParamTypes] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    content: RequestContent | None = None,
+    data: RequestData | None = None,
+    files: RequestFiles | None = None,
+    json: typing.Any | None = None,
+    params: QueryParamTypes | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     follow_redirects: bool = False,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     trust_env: bool = True,
@@ -428,14 +430,14 @@ def patch(
 def delete(
     url: URLTypes,
     *,
-    params: typing.Optional[QueryParamTypes] = None,
-    headers: typing.Optional[HeaderTypes] = None,
-    cookies: typing.Optional[CookieTypes] = None,
-    auth: typing.Optional[AuthTypes] = None,
-    proxy: typing.Optional[ProxyTypes] = None,
-    proxies: typing.Optional[ProxiesTypes] = None,
+    params: QueryParamTypes | None = None,
+    headers: HeaderTypes | None = None,
+    cookies: CookieTypes | None = None,
+    auth: AuthTypes | None = None,
+    proxy: ProxyTypes | None = None,
+    proxies: ProxiesTypes | None = None,
     follow_redirects: bool = False,
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
     trust_env: bool = True,
index e8bc0cd961074a5da2b623eca4c6b996387d67b9..903e39961740940faf79872da9347f3bf9624983 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import hashlib
 import os
 import re
@@ -124,18 +126,14 @@ class BasicAuth(Auth):
     and uses HTTP Basic authentication.
     """
 
-    def __init__(
-        self, username: typing.Union[str, bytes], password: typing.Union[str, bytes]
-    ) -> None:
+    def __init__(self, username: str | bytes, password: str | bytes) -> None:
         self._auth_header = self._build_auth_header(username, password)
 
     def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]:
         request.headers["Authorization"] = self._auth_header
         yield request
 
-    def _build_auth_header(
-        self, username: typing.Union[str, bytes], password: typing.Union[str, bytes]
-    ) -> str:
+    def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str:
         userpass = b":".join((to_bytes(username), to_bytes(password)))
         token = b64encode(userpass).decode()
         return f"Basic {token}"
@@ -146,7 +144,7 @@ class NetRCAuth(Auth):
     Use a 'netrc' file to lookup basic auth credentials based on the url host.
     """
 
-    def __init__(self, file: typing.Optional[str] = None) -> None:
+    def __init__(self, file: str | None = None) -> None:
         # Lazily import 'netrc'.
         # There's no need for us to load this module unless 'NetRCAuth' is being used.
         import netrc
@@ -165,16 +163,14 @@ class NetRCAuth(Auth):
             )
             yield request
 
-    def _build_auth_header(
-        self, username: typing.Union[str, bytes], password: typing.Union[str, bytes]
-    ) -> str:
+    def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str:
         userpass = b":".join((to_bytes(username), to_bytes(password)))
         token = b64encode(userpass).decode()
         return f"Basic {token}"
 
 
 class DigestAuth(Auth):
-    _ALGORITHM_TO_HASH_FUNCTION: typing.Dict[str, typing.Callable[[bytes], "_Hash"]] = {
+    _ALGORITHM_TO_HASH_FUNCTION: dict[str, typing.Callable[[bytes], _Hash]] = {
         "MD5": hashlib.md5,
         "MD5-SESS": hashlib.md5,
         "SHA": hashlib.sha1,
@@ -185,12 +181,10 @@ class DigestAuth(Auth):
         "SHA-512-SESS": hashlib.sha512,
     }
 
-    def __init__(
-        self, username: typing.Union[str, bytes], password: typing.Union[str, bytes]
-    ) -> None:
+    def __init__(self, username: str | bytes, password: str | bytes) -> None:
         self._username = to_bytes(username)
         self._password = to_bytes(password)
-        self._last_challenge: typing.Optional[_DigestAuthChallenge] = None
+        self._last_challenge: _DigestAuthChallenge | None = None
         self._nonce_count = 1
 
     def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]:
@@ -226,7 +220,7 @@ class DigestAuth(Auth):
 
     def _parse_challenge(
         self, request: Request, response: Response, auth_header: str
-    ) -> "_DigestAuthChallenge":
+    ) -> _DigestAuthChallenge:
         """
         Returns a challenge from a Digest WWW-Authenticate header.
         These take the form of:
@@ -237,7 +231,7 @@ class DigestAuth(Auth):
         # This method should only ever have been called with a Digest auth header.
         assert scheme.lower() == "digest"
 
-        header_dict: typing.Dict[str, str] = {}
+        header_dict: dict[str, str] = {}
         for field in parse_http_list(fields):
             key, value = field.strip().split("=", 1)
             header_dict[key] = unquote(value)
@@ -256,7 +250,7 @@ class DigestAuth(Auth):
             raise ProtocolError(message, request=request) from exc
 
     def _build_auth_header(
-        self, request: Request, challenge: "_DigestAuthChallenge"
+        self, request: Request, challenge: _DigestAuthChallenge
     ) -> str:
         hash_func = self._ALGORITHM_TO_HASH_FUNCTION[challenge.algorithm.upper()]
 
@@ -311,7 +305,7 @@ class DigestAuth(Auth):
 
         return hashlib.sha1(s).hexdigest()[:16].encode()
 
-    def _get_header_value(self, header_fields: typing.Dict[str, bytes]) -> str:
+    def _get_header_value(self, header_fields: dict[str, bytes]) -> str:
         NON_QUOTED_FIELDS = ("algorithm", "qop", "nc")
         QUOTED_TEMPLATE = '{}="{}"'
         NON_QUOTED_TEMPLATE = "{}={}"
@@ -329,9 +323,7 @@ class DigestAuth(Auth):
 
         return header_value
 
-    def _resolve_qop(
-        self, qop: typing.Optional[bytes], request: Request
-    ) -> typing.Optional[bytes]:
+    def _resolve_qop(self, qop: bytes | None, request: Request) -> bytes | None:
         if qop is None:
             return None
         qops = re.split(b", ?", qop)
@@ -349,5 +341,5 @@ class _DigestAuthChallenge(typing.NamedTuple):
     realm: bytes
     nonce: bytes
     algorithm: str
-    opaque: typing.Optional[bytes]
-    qop: typing.Optional[bytes]
+    opaque: bytes | None
+    qop: bytes | None
index a0b4209c46c29a805475e96dfbac19b9f6e64992..1f2145d12ed902f33510af679fb1b385e9626a50 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import datetime
 import enum
 import logging
@@ -160,19 +162,17 @@ class BaseClient:
     def __init__(
         self,
         *,
-        auth: typing.Optional[AuthTypes] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
+        auth: AuthTypes | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
         timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
         follow_redirects: bool = False,
         max_redirects: int = DEFAULT_MAX_REDIRECTS,
-        event_hooks: typing.Optional[
-            typing.Mapping[str, typing.List[EventHook]]
-        ] = None,
+        event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None,
         base_url: URLTypes = "",
         trust_env: bool = True,
-        default_encoding: typing.Union[str, typing.Callable[[bytes], str]] = "utf-8",
+        default_encoding: str | typing.Callable[[bytes], str] = "utf-8",
     ) -> None:
         event_hooks = {} if event_hooks is None else event_hooks
 
@@ -210,8 +210,8 @@ class BaseClient:
         return url.copy_with(raw_path=url.raw_path + b"/")
 
     def _get_proxy_map(
-        self, proxies: typing.Optional[ProxiesTypes], allow_env_proxies: bool
-    ) -> typing.Dict[str, typing.Optional[Proxy]]:
+        self, proxies: ProxiesTypes | None, allow_env_proxies: bool
+    ) -> dict[str, Proxy | None]:
         if proxies is None:
             if allow_env_proxies:
                 return {
@@ -238,20 +238,18 @@ class BaseClient:
         self._timeout = Timeout(timeout)
 
     @property
-    def event_hooks(self) -> typing.Dict[str, typing.List[EventHook]]:
+    def event_hooks(self) -> dict[str, list[EventHook]]:
         return self._event_hooks
 
     @event_hooks.setter
-    def event_hooks(
-        self, event_hooks: typing.Dict[str, typing.List[EventHook]]
-    ) -> None:
+    def event_hooks(self, event_hooks: dict[str, list[EventHook]]) -> None:
         self._event_hooks = {
             "request": list(event_hooks.get("request", [])),
             "response": list(event_hooks.get("response", [])),
         }
 
     @property
-    def auth(self) -> typing.Optional[Auth]:
+    def auth(self) -> Auth | None:
         """
         Authentication class used when none is passed at the request-level.
 
@@ -323,15 +321,15 @@ class BaseClient:
         method: str,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Request:
         """
         Build and return a request instance.
@@ -391,9 +389,7 @@ class BaseClient:
             return self.base_url.copy_with(raw_path=merge_raw_path)
         return merge_url
 
-    def _merge_cookies(
-        self, cookies: typing.Optional[CookieTypes] = None
-    ) -> typing.Optional[CookieTypes]:
+    def _merge_cookies(self, cookies: CookieTypes | None = None) -> CookieTypes | None:
         """
         Merge a cookies argument together with any cookies on the client,
         to create the cookies used for the outgoing request.
@@ -404,9 +400,7 @@ class BaseClient:
             return merged_cookies
         return cookies
 
-    def _merge_headers(
-        self, headers: typing.Optional[HeaderTypes] = None
-    ) -> typing.Optional[HeaderTypes]:
+    def _merge_headers(self, headers: HeaderTypes | None = None) -> HeaderTypes | None:
         """
         Merge a headers argument together with any headers on the client,
         to create the headers used for the outgoing request.
@@ -416,8 +410,8 @@ class BaseClient:
         return merged_headers
 
     def _merge_queryparams(
-        self, params: typing.Optional[QueryParamTypes] = None
-    ) -> typing.Optional[QueryParamTypes]:
+        self, params: QueryParamTypes | None = None
+    ) -> QueryParamTypes | None:
         """
         Merge a queryparams argument together with any queryparams on the client,
         to create the queryparams used for the outgoing request.
@@ -427,7 +421,7 @@ class BaseClient:
             return merged_queryparams.merge(params)
         return params
 
-    def _build_auth(self, auth: typing.Optional[AuthTypes]) -> typing.Optional[Auth]:
+    def _build_auth(self, auth: AuthTypes | None) -> Auth | None:
         if auth is None:
             return None
         elif isinstance(auth, tuple):
@@ -442,7 +436,7 @@ class BaseClient:
     def _build_request_auth(
         self,
         request: Request,
-        auth: typing.Union[AuthTypes, UseClientDefault, None] = USE_CLIENT_DEFAULT,
+        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
     ) -> Auth:
         auth = (
             self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth)
@@ -557,7 +551,7 @@ class BaseClient:
 
     def _redirect_stream(
         self, request: Request, method: str
-    ) -> typing.Optional[typing.Union[SyncByteStream, AsyncByteStream]]:
+    ) -> SyncByteStream | AsyncByteStream | None:
         """
         Return the body that should be used for the redirect request.
         """
@@ -624,31 +618,27 @@ class Client(BaseClient):
     def __init__(
         self,
         *,
-        auth: typing.Optional[AuthTypes] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
+        auth: AuthTypes | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
-        proxy: typing.Optional[ProxyTypes] = None,
-        proxies: typing.Optional[ProxiesTypes] = None,
-        mounts: typing.Optional[
-            typing.Mapping[str, typing.Optional[BaseTransport]]
-        ] = None,
+        proxy: ProxyTypes | None = None,
+        proxies: ProxiesTypes | None = None,
+        mounts: None | (typing.Mapping[str, BaseTransport | None]) = None,
         timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
         follow_redirects: bool = False,
         limits: Limits = DEFAULT_LIMITS,
         max_redirects: int = DEFAULT_MAX_REDIRECTS,
-        event_hooks: typing.Optional[
-            typing.Mapping[str, typing.List[EventHook]]
-        ] = None,
+        event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None,
         base_url: URLTypes = "",
-        transport: typing.Optional[BaseTransport] = None,
-        app: typing.Optional[typing.Callable[..., typing.Any]] = None,
+        transport: BaseTransport | None = None,
+        app: typing.Callable[..., typing.Any] | None = None,
         trust_env: bool = True,
-        default_encoding: typing.Union[str, typing.Callable[[bytes], str]] = "utf-8",
+        default_encoding: str | typing.Callable[[bytes], str] = "utf-8",
     ) -> None:
         super().__init__(
             auth=auth,
@@ -695,7 +685,7 @@ class Client(BaseClient):
             app=app,
             trust_env=trust_env,
         )
-        self._mounts: typing.Dict[URLPattern, typing.Optional[BaseTransport]] = {
+        self._mounts: dict[URLPattern, BaseTransport | None] = {
             URLPattern(key): None
             if proxy is None
             else self._init_proxy_transport(
@@ -719,12 +709,12 @@ class Client(BaseClient):
     def _init_transport(
         self,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
         limits: Limits = DEFAULT_LIMITS,
-        transport: typing.Optional[BaseTransport] = None,
-        app: typing.Optional[typing.Callable[..., typing.Any]] = None,
+        transport: BaseTransport | None = None,
+        app: typing.Callable[..., typing.Any] | None = None,
         trust_env: bool = True,
     ) -> BaseTransport:
         if transport is not None:
@@ -746,7 +736,7 @@ class Client(BaseClient):
         self,
         proxy: Proxy,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
         limits: Limits = DEFAULT_LIMITS,
@@ -778,17 +768,17 @@ class Client(BaseClient):
         method: str,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault, None] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Build and send a request.
@@ -835,17 +825,17 @@ class Client(BaseClient):
         method: str,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault, None] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> typing.Iterator[Response]:
         """
         Alternative to `httpx.request()` that streams the response body
@@ -886,8 +876,8 @@ class Client(BaseClient):
         request: Request,
         *,
         stream: bool = False,
-        auth: typing.Union[AuthTypes, UseClientDefault, None] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
+        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
     ) -> Response:
         """
         Send a request.
@@ -935,7 +925,7 @@ class Client(BaseClient):
         request: Request,
         auth: Auth,
         follow_redirects: bool,
-        history: typing.List[Response],
+        history: list[Response],
     ) -> Response:
         auth_flow = auth.sync_auth_flow(request)
         try:
@@ -968,7 +958,7 @@ class Client(BaseClient):
         self,
         request: Request,
         follow_redirects: bool,
-        history: typing.List[Response],
+        history: list[Response],
     ) -> Response:
         while True:
             if len(history) > self.max_redirects:
@@ -1041,13 +1031,13 @@ class Client(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `GET` request.
@@ -1070,13 +1060,13 @@ class Client(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send an `OPTIONS` request.
@@ -1099,13 +1089,13 @@ class Client(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `HEAD` request.
@@ -1128,17 +1118,17 @@ class Client(BaseClient):
         self,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `POST` request.
@@ -1165,17 +1155,17 @@ class Client(BaseClient):
         self,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `PUT` request.
@@ -1202,17 +1192,17 @@ class Client(BaseClient):
         self,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `PATCH` request.
@@ -1239,13 +1229,13 @@ class Client(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `DELETE` request.
@@ -1296,9 +1286,9 @@ class Client(BaseClient):
 
     def __exit__(
         self,
-        exc_type: typing.Optional[typing.Type[BaseException]] = None,
-        exc_value: typing.Optional[BaseException] = None,
-        traceback: typing.Optional[TracebackType] = None,
+        exc_type: type[BaseException] | None = None,
+        exc_value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         self._state = ClientState.CLOSED
 
@@ -1366,31 +1356,28 @@ class AsyncClient(BaseClient):
     def __init__(
         self,
         *,
-        auth: typing.Optional[AuthTypes] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
+        auth: AuthTypes | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
-        proxy: typing.Optional[ProxyTypes] = None,
-        proxies: typing.Optional[ProxiesTypes] = None,
-        mounts: typing.Optional[
-            typing.Mapping[str, typing.Optional[AsyncBaseTransport]]
-        ] = None,
+        proxy: ProxyTypes | None = None,
+        proxies: ProxiesTypes | None = None,
+        mounts: None | (typing.Mapping[str, AsyncBaseTransport | None]) = None,
         timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
         follow_redirects: bool = False,
         limits: Limits = DEFAULT_LIMITS,
         max_redirects: int = DEFAULT_MAX_REDIRECTS,
-        event_hooks: typing.Optional[
-            typing.Mapping[str, typing.List[typing.Callable[..., typing.Any]]]
-        ] = None,
+        event_hooks: None
+        | (typing.Mapping[str, list[typing.Callable[..., typing.Any]]]) = None,
         base_url: URLTypes = "",
-        transport: typing.Optional[AsyncBaseTransport] = None,
-        app: typing.Optional[typing.Callable[..., typing.Any]] = None,
+        transport: AsyncBaseTransport | None = None,
+        app: typing.Callable[..., typing.Any] | None = None,
         trust_env: bool = True,
-        default_encoding: typing.Union[str, typing.Callable[[bytes], str]] = "utf-8",
+        default_encoding: str | typing.Callable[[bytes], str] = "utf-8",
     ) -> None:
         super().__init__(
             auth=auth,
@@ -1438,7 +1425,7 @@ class AsyncClient(BaseClient):
             trust_env=trust_env,
         )
 
-        self._mounts: typing.Dict[URLPattern, typing.Optional[AsyncBaseTransport]] = {
+        self._mounts: dict[URLPattern, AsyncBaseTransport | None] = {
             URLPattern(key): None
             if proxy is None
             else self._init_proxy_transport(
@@ -1461,12 +1448,12 @@ class AsyncClient(BaseClient):
     def _init_transport(
         self,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
         limits: Limits = DEFAULT_LIMITS,
-        transport: typing.Optional[AsyncBaseTransport] = None,
-        app: typing.Optional[typing.Callable[..., typing.Any]] = None,
+        transport: AsyncBaseTransport | None = None,
+        app: typing.Callable[..., typing.Any] | None = None,
         trust_env: bool = True,
     ) -> AsyncBaseTransport:
         if transport is not None:
@@ -1488,7 +1475,7 @@ class AsyncClient(BaseClient):
         self,
         proxy: Proxy,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
         limits: Limits = DEFAULT_LIMITS,
@@ -1520,17 +1507,17 @@ class AsyncClient(BaseClient):
         method: str,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault, None] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Build and send a request.
@@ -1578,17 +1565,17 @@ class AsyncClient(BaseClient):
         method: str,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> typing.AsyncIterator[Response]:
         """
         Alternative to `httpx.request()` that streams the response body
@@ -1629,8 +1616,8 @@ class AsyncClient(BaseClient):
         request: Request,
         *,
         stream: bool = False,
-        auth: typing.Union[AuthTypes, UseClientDefault, None] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
+        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
     ) -> Response:
         """
         Send a request.
@@ -1678,7 +1665,7 @@ class AsyncClient(BaseClient):
         request: Request,
         auth: Auth,
         follow_redirects: bool,
-        history: typing.List[Response],
+        history: list[Response],
     ) -> Response:
         auth_flow = auth.async_auth_flow(request)
         try:
@@ -1711,7 +1698,7 @@ class AsyncClient(BaseClient):
         self,
         request: Request,
         follow_redirects: bool,
-        history: typing.List[Response],
+        history: list[Response],
     ) -> Response:
         while True:
             if len(history) > self.max_redirects:
@@ -1784,13 +1771,13 @@ class AsyncClient(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault, None] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `GET` request.
@@ -1813,13 +1800,13 @@ class AsyncClient(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send an `OPTIONS` request.
@@ -1842,13 +1829,13 @@ class AsyncClient(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `HEAD` request.
@@ -1871,17 +1858,17 @@ class AsyncClient(BaseClient):
         self,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `POST` request.
@@ -1908,17 +1895,17 @@ class AsyncClient(BaseClient):
         self,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `PUT` request.
@@ -1945,17 +1932,17 @@ class AsyncClient(BaseClient):
         self,
         url: URLTypes,
         *,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `PATCH` request.
@@ -1982,13 +1969,13 @@ class AsyncClient(BaseClient):
         self,
         url: URLTypes,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        auth: typing.Union[AuthTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        follow_redirects: typing.Union[bool, UseClientDefault] = USE_CLIENT_DEFAULT,
-        timeout: typing.Union[TimeoutTypes, UseClientDefault] = USE_CLIENT_DEFAULT,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
+        timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
+        extensions: RequestExtensions | None = None,
     ) -> Response:
         """
         Send a `DELETE` request.
@@ -2039,9 +2026,9 @@ class AsyncClient(BaseClient):
 
     async def __aexit__(
         self,
-        exc_type: typing.Optional[typing.Type[BaseException]] = None,
-        exc_value: typing.Optional[BaseException] = None,
-        traceback: typing.Optional[TracebackType] = None,
+        exc_type: type[BaseException] | None = None,
+        exc_value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         self._state = ClientState.CLOSED
 
index 0cfd552e49b9c510fcf5c7466118dcd4ed574d5f..7636a5dcc5802ff44ca02a0bd0b1fcb51c0bc2c0 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import logging
 import os
 import ssl
@@ -43,7 +45,7 @@ UNSET = UnsetType()
 
 
 def create_ssl_context(
-    cert: typing.Optional[CertTypes] = None,
+    cert: CertTypes | None = None,
     verify: VerifyTypes = True,
     trust_env: bool = True,
     http2: bool = False,
@@ -63,7 +65,7 @@ class SSLConfig:
     def __init__(
         self,
         *,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         verify: VerifyTypes = True,
         trust_env: bool = True,
         http2: bool = False,
@@ -205,12 +207,12 @@ class Timeout:
 
     def __init__(
         self,
-        timeout: typing.Union[TimeoutTypes, UnsetType] = UNSET,
+        timeout: TimeoutTypes | UnsetType = UNSET,
         *,
-        connect: typing.Union[None, float, UnsetType] = UNSET,
-        read: typing.Union[None, float, UnsetType] = UNSET,
-        write: typing.Union[None, float, UnsetType] = UNSET,
-        pool: typing.Union[None, float, UnsetType] = UNSET,
+        connect: None | float | UnsetType = UNSET,
+        read: None | float | UnsetType = UNSET,
+        write: None | float | UnsetType = UNSET,
+        pool: None | float | UnsetType = UNSET,
     ) -> None:
         if isinstance(timeout, Timeout):
             # Passed as a single explicit Timeout.
@@ -249,7 +251,7 @@ class Timeout:
             self.write = timeout if isinstance(write, UnsetType) else write
             self.pool = timeout if isinstance(pool, UnsetType) else pool
 
-    def as_dict(self) -> typing.Dict[str, typing.Optional[float]]:
+    def as_dict(self) -> dict[str, float | None]:
         return {
             "connect": self.connect,
             "read": self.read,
@@ -293,9 +295,9 @@ class Limits:
     def __init__(
         self,
         *,
-        max_connections: typing.Optional[int] = None,
-        max_keepalive_connections: typing.Optional[int] = None,
-        keepalive_expiry: typing.Optional[float] = 5.0,
+        max_connections: int | None = None,
+        max_keepalive_connections: int | None = None,
+        keepalive_expiry: float | None = 5.0,
     ) -> None:
         self.max_connections = max_connections
         self.max_keepalive_connections = max_keepalive_connections
@@ -323,9 +325,9 @@ class Proxy:
         self,
         url: URLTypes,
         *,
-        ssl_context: typing.Optional[ssl.SSLContext] = None,
-        auth: typing.Optional[typing.Tuple[str, str]] = None,
-        headers: typing.Optional[HeaderTypes] = None,
+        ssl_context: ssl.SSLContext | None = None,
+        auth: tuple[str, str] | None = None,
+        headers: HeaderTypes | None = None,
     ) -> None:
         url = URL(url)
         headers = Headers(headers)
@@ -344,7 +346,7 @@ class Proxy:
         self.ssl_context = ssl_context
 
     @property
-    def raw_auth(self) -> typing.Optional[typing.Tuple[bytes, bytes]]:
+    def raw_auth(self) -> tuple[bytes, bytes] | None:
         # The proxy authentication as raw bytes.
         return (
             None
index cd0d17f17111df6df83d043bc93fd06e69ca299a..10b574bb3d7d8dfc62057407426d4b2a962c300c 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import inspect
 import warnings
 from json import dumps as json_dumps
@@ -5,13 +7,9 @@ from typing import (
     Any,
     AsyncIterable,
     AsyncIterator,
-    Dict,
     Iterable,
     Iterator,
     Mapping,
-    Optional,
-    Tuple,
-    Union,
 )
 from urllib.parse import urlencode
 
@@ -105,8 +103,8 @@ class UnattachedStream(AsyncByteStream, SyncByteStream):
 
 
 def encode_content(
-    content: Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]],
-) -> Tuple[Dict[str, str], Union[SyncByteStream, AsyncByteStream]]:
+    content: str | bytes | Iterable[bytes] | AsyncIterable[bytes],
+) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]:
     if isinstance(content, (bytes, str)):
         body = content.encode("utf-8") if isinstance(content, str) else content
         content_length = len(body)
@@ -135,7 +133,7 @@ def encode_content(
 
 def encode_urlencoded_data(
     data: RequestData,
-) -> Tuple[Dict[str, str], ByteStream]:
+) -> tuple[dict[str, str], ByteStream]:
     plain_data = []
     for key, value in data.items():
         if isinstance(value, (list, tuple)):
@@ -150,14 +148,14 @@ def encode_urlencoded_data(
 
 
 def encode_multipart_data(
-    data: RequestData, files: RequestFiles, boundary: Optional[bytes]
-) -> Tuple[Dict[str, str], MultipartStream]:
+    data: RequestData, files: RequestFiles, boundary: bytes | None
+) -> tuple[dict[str, str], MultipartStream]:
     multipart = MultipartStream(data=data, files=files, boundary=boundary)
     headers = multipart.get_headers()
     return headers, multipart
 
 
-def encode_text(text: str) -> Tuple[Dict[str, str], ByteStream]:
+def encode_text(text: str) -> tuple[dict[str, str], ByteStream]:
     body = text.encode("utf-8")
     content_length = str(len(body))
     content_type = "text/plain; charset=utf-8"
@@ -165,7 +163,7 @@ def encode_text(text: str) -> Tuple[Dict[str, str], ByteStream]:
     return headers, ByteStream(body)
 
 
-def encode_html(html: str) -> Tuple[Dict[str, str], ByteStream]:
+def encode_html(html: str) -> tuple[dict[str, str], ByteStream]:
     body = html.encode("utf-8")
     content_length = str(len(body))
     content_type = "text/html; charset=utf-8"
@@ -173,7 +171,7 @@ def encode_html(html: str) -> Tuple[Dict[str, str], ByteStream]:
     return headers, ByteStream(body)
 
 
-def encode_json(json: Any) -> Tuple[Dict[str, str], ByteStream]:
+def encode_json(json: Any) -> tuple[dict[str, str], ByteStream]:
     body = json_dumps(json).encode("utf-8")
     content_length = str(len(body))
     content_type = "application/json"
@@ -182,12 +180,12 @@ def encode_json(json: Any) -> Tuple[Dict[str, str], ByteStream]:
 
 
 def encode_request(
-    content: Optional[RequestContent] = None,
-    data: Optional[RequestData] = None,
-    files: Optional[RequestFiles] = None,
-    json: Optional[Any] = None,
-    boundary: Optional[bytes] = None,
-) -> Tuple[Dict[str, str], Union[SyncByteStream, AsyncByteStream]]:
+    content: RequestContent | None = None,
+    data: RequestData | None = None,
+    files: RequestFiles | None = None,
+    json: Any | None = None,
+    boundary: bytes | None = None,
+) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]:
     """
     Handles encoding the given `content`, `data`, `files`, and `json`,
     returning a two-tuple of (<headers>, <stream>).
@@ -217,11 +215,11 @@ def encode_request(
 
 
 def encode_response(
-    content: Optional[ResponseContent] = None,
-    text: Optional[str] = None,
-    html: Optional[str] = None,
-    json: Optional[Any] = None,
-) -> Tuple[Dict[str, str], Union[SyncByteStream, AsyncByteStream]]:
+    content: ResponseContent | None = None,
+    text: str | None = None,
+    html: str | None = None,
+    json: Any | None = None,
+) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]:
     """
     Handles encoding the given `content`, returning a two-tuple of
     (<headers>, <stream>).
index 3f507c8e040c6e6d192bbd798556315fb0fcff68..31c72c7f7a3c75cc356709c5faa532df5361e3e0 100644 (file)
@@ -3,6 +3,8 @@ Handlers for Content-Encoding.
 
 See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
 """
+from __future__ import annotations
+
 import codecs
 import io
 import typing
@@ -167,11 +169,11 @@ class ByteChunker:
     Handles returning byte content in fixed-size chunks.
     """
 
-    def __init__(self, chunk_size: typing.Optional[int] = None) -> None:
+    def __init__(self, chunk_size: int | None = None) -> None:
         self._buffer = io.BytesIO()
         self._chunk_size = chunk_size
 
-    def decode(self, content: bytes) -> typing.List[bytes]:
+    def decode(self, content: bytes) -> list[bytes]:
         if self._chunk_size is None:
             return [content] if content else []
 
@@ -194,7 +196,7 @@ class ByteChunker:
         else:
             return []
 
-    def flush(self) -> typing.List[bytes]:
+    def flush(self) -> list[bytes]:
         value = self._buffer.getvalue()
         self._buffer.seek(0)
         self._buffer.truncate()
@@ -206,11 +208,11 @@ class TextChunker:
     Handles returning text content in fixed-size chunks.
     """
 
-    def __init__(self, chunk_size: typing.Optional[int] = None) -> None:
+    def __init__(self, chunk_size: int | None = None) -> None:
         self._buffer = io.StringIO()
         self._chunk_size = chunk_size
 
-    def decode(self, content: str) -> typing.List[str]:
+    def decode(self, content: str) -> list[str]:
         if self._chunk_size is None:
             return [content] if content else []
 
@@ -233,7 +235,7 @@ class TextChunker:
         else:
             return []
 
-    def flush(self) -> typing.List[str]:
+    def flush(self) -> list[str]:
         value = self._buffer.getvalue()
         self._buffer.seek(0)
         self._buffer.truncate()
@@ -264,10 +266,10 @@ class LineDecoder:
     """
 
     def __init__(self) -> None:
-        self.buffer: typing.List[str] = []
+        self.buffer: list[str] = []
         self.trailing_cr: bool = False
 
-    def decode(self, text: str) -> typing.List[str]:
+    def decode(self, text: str) -> list[str]:
         # See https://docs.python.org/3/library/stdtypes.html#str.splitlines
         NEWLINE_CHARS = "\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029"
 
@@ -305,7 +307,7 @@ class LineDecoder:
 
         return lines
 
-    def flush(self) -> typing.List[str]:
+    def flush(self) -> list[str]:
         if not self.buffer and not self.trailing_cr:
             return []
 
index 123692955b10426a8d45cfb45b7c6ff2d7578417..11424621c044057c849a950c6b3bfdfb0f2801fe 100644 (file)
@@ -30,6 +30,8 @@ Our exception hierarchy:
   x ResponseNotRead
   x RequestNotRead
 """
+from __future__ import annotations
+
 import contextlib
 import typing
 
@@ -57,16 +59,16 @@ class HTTPError(Exception):
 
     def __init__(self, message: str) -> None:
         super().__init__(message)
-        self._request: typing.Optional["Request"] = None
+        self._request: Request | None = None
 
     @property
-    def request(self) -> "Request":
+    def request(self) -> Request:
         if self._request is None:
             raise RuntimeError("The .request property has not been set.")
         return self._request
 
     @request.setter
-    def request(self, request: "Request") -> None:
+    def request(self, request: Request) -> None:
         self._request = request
 
 
@@ -75,9 +77,7 @@ class RequestError(HTTPError):
     Base class for all exceptions that may occur when issuing a `.request()`.
     """
 
-    def __init__(
-        self, message: str, *, request: typing.Optional["Request"] = None
-    ) -> None:
+    def __init__(self, message: str, *, request: Request | None = None) -> None:
         super().__init__(message)
         # At the point an exception is raised we won't typically have a request
         # instance to associate it with.
@@ -230,9 +230,7 @@ class HTTPStatusError(HTTPError):
     May be raised when calling `response.raise_for_status()`
     """
 
-    def __init__(
-        self, message: str, *, request: "Request", response: "Response"
-    ) -> None:
+    def __init__(self, message: str, *, request: Request, response: Response) -> None:
         super().__init__(message)
         self.request = request
         self.response = response
@@ -335,7 +333,7 @@ class RequestNotRead(StreamError):
 
 @contextlib.contextmanager
 def request_context(
-    request: typing.Optional["Request"] = None,
+    request: Request | None = None,
 ) -> typing.Iterator[None]:
     """
     A context manager that can be used to attach the given request context
index adb57d5fc0a14b79d501a1ecf47ccff047ea01db..72657f8ca3cd882249aa5c85fbcd42685ff2da74 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import functools
 import json
 import sys
@@ -125,8 +127,8 @@ def format_request_headers(request: httpcore.Request, http2: bool = False) -> st
 def format_response_headers(
     http_version: bytes,
     status: int,
-    reason_phrase: typing.Optional[bytes],
-    headers: typing.List[typing.Tuple[bytes, bytes]],
+    reason_phrase: bytes | None,
+    headers: list[tuple[bytes, bytes]],
 ) -> str:
     version = http_version.decode("ascii")
     reason = (
@@ -152,8 +154,8 @@ def print_request_headers(request: httpcore.Request, http2: bool = False) -> Non
 def print_response_headers(
     http_version: bytes,
     status: int,
-    reason_phrase: typing.Optional[bytes],
-    headers: typing.List[typing.Tuple[bytes, bytes]],
+    reason_phrase: bytes | None,
+    headers: list[tuple[bytes, bytes]],
 ) -> None:
     console = rich.console.Console()
     http_text = format_response_headers(http_version, status, reason_phrase, headers)
@@ -268,7 +270,7 @@ def download_response(response: Response, download: typing.BinaryIO) -> None:
 
 def validate_json(
     ctx: click.Context,
-    param: typing.Union[click.Option, click.Parameter],
+    param: click.Option | click.Parameter,
     value: typing.Any,
 ) -> typing.Any:
     if value is None:
@@ -282,7 +284,7 @@ def validate_json(
 
 def validate_auth(
     ctx: click.Context,
-    param: typing.Union[click.Option, click.Parameter],
+    param: click.Option | click.Parameter,
     value: typing.Any,
 ) -> typing.Any:
     if value == (None, None):
@@ -296,7 +298,7 @@ def validate_auth(
 
 def handle_help(
     ctx: click.Context,
-    param: typing.Union[click.Option, click.Parameter],
+    param: click.Option | click.Parameter,
     value: typing.Any,
 ) -> None:
     if not value or ctx.resilient_parsing:
@@ -448,20 +450,20 @@ def handle_help(
 def main(
     url: str,
     method: str,
-    params: typing.List[typing.Tuple[str, str]],
+    params: list[tuple[str, str]],
     content: str,
-    data: typing.List[typing.Tuple[str, str]],
-    files: typing.List[typing.Tuple[str, click.File]],
+    data: list[tuple[str, str]],
+    files: list[tuple[str, click.File]],
     json: str,
-    headers: typing.List[typing.Tuple[str, str]],
-    cookies: typing.List[typing.Tuple[str, str]],
-    auth: typing.Optional[typing.Tuple[str, str]],
+    headers: list[tuple[str, str]],
+    cookies: list[tuple[str, str]],
+    auth: tuple[str, str] | None,
     proxy: str,
     timeout: float,
     follow_redirects: bool,
     verify: bool,
     http2: bool,
-    download: typing.Optional[typing.BinaryIO],
+    download: typing.BinaryIO | None,
     verbose: bool,
 ) -> None:
     """
index e08248a8d4110274494312f467df3f4f13b3619f..cd76705f1ab17a92052b8af55c56b7a1a33d9922 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import datetime
 import email.message
 import json as jsonlib
@@ -59,8 +61,8 @@ class Headers(typing.MutableMapping[str, str]):
 
     def __init__(
         self,
-        headers: typing.Optional[HeaderTypes] = None,
-        encoding: typing.Optional[str] = None,
+        headers: HeaderTypes | None = None,
+        encoding: str | None = None,
     ) -> None:
         if headers is None:
             self._list = []  # type: typing.List[typing.Tuple[bytes, bytes, bytes]]
@@ -117,7 +119,7 @@ class Headers(typing.MutableMapping[str, str]):
         self._encoding = value
 
     @property
-    def raw(self) -> typing.List[typing.Tuple[bytes, bytes]]:
+    def raw(self) -> list[tuple[bytes, bytes]]:
         """
         Returns a list of the raw header items, as byte pairs.
         """
@@ -127,7 +129,7 @@ class Headers(typing.MutableMapping[str, str]):
         return {key.decode(self.encoding): None for _, key, value in self._list}.keys()
 
     def values(self) -> typing.ValuesView[str]:
-        values_dict: typing.Dict[str, str] = {}
+        values_dict: dict[str, str] = {}
         for _, key, value in self._list:
             str_key = key.decode(self.encoding)
             str_value = value.decode(self.encoding)
@@ -142,7 +144,7 @@ class Headers(typing.MutableMapping[str, str]):
         Return `(key, value)` items of headers. Concatenate headers
         into a single comma separated value when a key occurs multiple times.
         """
-        values_dict: typing.Dict[str, str] = {}
+        values_dict: dict[str, str] = {}
         for _, key, value in self._list:
             str_key = key.decode(self.encoding)
             str_value = value.decode(self.encoding)
@@ -152,7 +154,7 @@ class Headers(typing.MutableMapping[str, str]):
                 values_dict[str_key] = str_value
         return values_dict.items()
 
-    def multi_items(self) -> typing.List[typing.Tuple[str, str]]:
+    def multi_items(self) -> list[tuple[str, str]]:
         """
         Return a list of `(key, value)` pairs of headers. Allow multiple
         occurrences of the same key without concatenating into a single
@@ -173,7 +175,7 @@ class Headers(typing.MutableMapping[str, str]):
         except KeyError:
             return default
 
-    def get_list(self, key: str, split_commas: bool = False) -> typing.List[str]:
+    def get_list(self, key: str, split_commas: bool = False) -> list[str]:
         """
         Return a list of all header values for a given key.
         If `split_commas=True` is passed, then any comma separated header
@@ -195,14 +197,14 @@ class Headers(typing.MutableMapping[str, str]):
             split_values.extend([item.strip() for item in value.split(",")])
         return split_values
 
-    def update(self, headers: typing.Optional[HeaderTypes] = None) -> None:  # type: ignore
+    def update(self, headers: HeaderTypes | None = None) -> None:  # type: ignore
         headers = Headers(headers)
         for key in headers.keys():
             if key in self:
                 self.pop(key)
         self._list.extend(headers._list)
 
-    def copy(self) -> "Headers":
+    def copy(self) -> Headers:
         return Headers(self, encoding=self.encoding)
 
     def __getitem__(self, key: str) -> str:
@@ -306,18 +308,18 @@ class Headers(typing.MutableMapping[str, str]):
 class Request:
     def __init__(
         self,
-        method: typing.Union[str, bytes],
-        url: typing.Union["URL", str],
+        method: str | bytes,
+        url: URL | str,
         *,
-        params: typing.Optional[QueryParamTypes] = None,
-        headers: typing.Optional[HeaderTypes] = None,
-        cookies: typing.Optional[CookieTypes] = None,
-        content: typing.Optional[RequestContent] = None,
-        data: typing.Optional[RequestData] = None,
-        files: typing.Optional[RequestFiles] = None,
-        json: typing.Optional[typing.Any] = None,
-        stream: typing.Union[SyncByteStream, AsyncByteStream, None] = None,
-        extensions: typing.Optional[RequestExtensions] = None,
+        params: QueryParamTypes | None = None,
+        headers: HeaderTypes | None = None,
+        cookies: CookieTypes | None = None,
+        content: RequestContent | None = None,
+        data: RequestData | None = None,
+        files: RequestFiles | None = None,
+        json: typing.Any | None = None,
+        stream: SyncByteStream | AsyncByteStream | None = None,
+        extensions: RequestExtensions | None = None,
     ) -> None:
         self.method = (
             method.decode("ascii").upper()
@@ -334,7 +336,7 @@ class Request:
             Cookies(cookies).set_cookie_header(self)
 
         if stream is None:
-            content_type: typing.Optional[str] = self.headers.get("content-type")
+            content_type: str | None = self.headers.get("content-type")
             headers, stream = encode_request(
                 content=content,
                 data=data,
@@ -368,14 +370,14 @@ class Request:
             # * Creating request instances on the *server-side* of the transport API.
             self.stream = stream
 
-    def _prepare(self, default_headers: typing.Dict[str, str]) -> None:
+    def _prepare(self, default_headers: dict[str, str]) -> None:
         for key, value in default_headers.items():
             # Ignore Transfer-Encoding if the Content-Length has been set explicitly.
             if key.lower() == "transfer-encoding" and "Content-Length" in self.headers:
                 continue
             self.headers.setdefault(key, value)
 
-        auto_headers: typing.List[typing.Tuple[bytes, bytes]] = []
+        auto_headers: list[tuple[bytes, bytes]] = []
 
         has_host = "Host" in self.headers
         has_content_length = (
@@ -428,14 +430,14 @@ class Request:
         url = str(self.url)
         return f"<{class_name}({self.method!r}, {url!r})>"
 
-    def __getstate__(self) -> typing.Dict[str, typing.Any]:
+    def __getstate__(self) -> dict[str, typing.Any]:
         return {
             name: value
             for name, value in self.__dict__.items()
             if name not in ["extensions", "stream"]
         }
 
-    def __setstate__(self, state: typing.Dict[str, typing.Any]) -> None:
+    def __setstate__(self, state: dict[str, typing.Any]) -> None:
         for name, value in state.items():
             setattr(self, name, value)
         self.extensions = {}
@@ -447,25 +449,25 @@ class Response:
         self,
         status_code: int,
         *,
-        headers: typing.Optional[HeaderTypes] = None,
-        content: typing.Optional[ResponseContent] = None,
-        text: typing.Optional[str] = None,
-        html: typing.Optional[str] = None,
+        headers: HeaderTypes | None = None,
+        content: ResponseContent | None = None,
+        text: str | None = None,
+        html: str | None = None,
         json: typing.Any = None,
-        stream: typing.Union[SyncByteStream, AsyncByteStream, None] = None,
-        request: typing.Optional[Request] = None,
-        extensions: typing.Optional[ResponseExtensions] = None,
-        history: typing.Optional[typing.List["Response"]] = None,
-        default_encoding: typing.Union[str, typing.Callable[[bytes], str]] = "utf-8",
+        stream: SyncByteStream | AsyncByteStream | None = None,
+        request: Request | None = None,
+        extensions: ResponseExtensions | None = None,
+        history: list[Response] | None = None,
+        default_encoding: str | typing.Callable[[bytes], str] = "utf-8",
     ) -> None:
         self.status_code = status_code
         self.headers = Headers(headers)
 
-        self._request: typing.Optional[Request] = request
+        self._request: Request | None = request
 
         # When follow_redirects=False and a redirect is received,
         # the client will set `response.next_request`.
-        self.next_request: typing.Optional[Request] = None
+        self.next_request: Request | None = None
 
         self.extensions: ResponseExtensions = {} if extensions is None else extensions
         self.history = [] if history is None else list(history)
@@ -498,7 +500,7 @@ class Response:
 
         self._num_bytes_downloaded = 0
 
-    def _prepare(self, default_headers: typing.Dict[str, str]) -> None:
+    def _prepare(self, default_headers: dict[str, str]) -> None:
         for key, value in default_headers.items():
             # Ignore Transfer-Encoding if the Content-Length has been set explicitly.
             if key.lower() == "transfer-encoding" and "content-length" in self.headers:
@@ -580,7 +582,7 @@ class Response:
         return self._text
 
     @property
-    def encoding(self) -> typing.Optional[str]:
+    def encoding(self) -> str | None:
         """
         Return an encoding to use for decoding the byte content into text.
         The priority for determining this is given by...
@@ -616,7 +618,7 @@ class Response:
         self._encoding = value
 
     @property
-    def charset_encoding(self) -> typing.Optional[str]:
+    def charset_encoding(self) -> str | None:
         """
         Return the encoding, as specified by the Content-Type header.
         """
@@ -632,7 +634,7 @@ class Response:
         content, depending on the Content-Encoding used in the response.
         """
         if not hasattr(self, "_decoder"):
-            decoders: typing.List[ContentDecoder] = []
+            decoders: list[ContentDecoder] = []
             values = self.headers.get_list("content-encoding", split_commas=True)
             for value in values:
                 value = value.strip().lower()
@@ -721,7 +723,7 @@ class Response:
             and "Location" in self.headers
         )
 
-    def raise_for_status(self) -> "Response":
+    def raise_for_status(self) -> Response:
         """
         Raise the `HTTPStatusError` if one occurred.
         """
@@ -762,14 +764,14 @@ class Response:
         return jsonlib.loads(self.content, **kwargs)
 
     @property
-    def cookies(self) -> "Cookies":
+    def cookies(self) -> Cookies:
         if not hasattr(self, "_cookies"):
             self._cookies = Cookies()
             self._cookies.extract_cookies(self)
         return self._cookies
 
     @property
-    def links(self) -> typing.Dict[typing.Optional[str], typing.Dict[str, str]]:
+    def links(self) -> dict[str | None, dict[str, str]]:
         """
         Returns the parsed header links of the response, if any
         """
@@ -789,14 +791,14 @@ class Response:
     def __repr__(self) -> str:
         return f"<Response [{self.status_code} {self.reason_phrase}]>"
 
-    def __getstate__(self) -> typing.Dict[str, typing.Any]:
+    def __getstate__(self) -> dict[str, typing.Any]:
         return {
             name: value
             for name, value in self.__dict__.items()
             if name not in ["extensions", "stream", "is_closed", "_decoder"]
         }
 
-    def __setstate__(self, state: typing.Dict[str, typing.Any]) -> None:
+    def __setstate__(self, state: dict[str, typing.Any]) -> None:
         for name, value in state.items():
             setattr(self, name, value)
         self.is_closed = True
@@ -811,9 +813,7 @@ class Response:
             self._content = b"".join(self.iter_bytes())
         return self._content
 
-    def iter_bytes(
-        self, chunk_size: typing.Optional[int] = None
-    ) -> typing.Iterator[bytes]:
+    def iter_bytes(self, chunk_size: int | None = None) -> typing.Iterator[bytes]:
         """
         A byte-iterator over the decoded response content.
         This allows us to handle gzip, deflate, and brotli encoded responses.
@@ -836,9 +836,7 @@ class Response:
                 for chunk in chunker.flush():
                     yield chunk
 
-    def iter_text(
-        self, chunk_size: typing.Optional[int] = None
-    ) -> typing.Iterator[str]:
+    def iter_text(self, chunk_size: int | None = None) -> typing.Iterator[str]:
         """
         A str-iterator over the decoded response content
         that handles both gzip, deflate, etc but also detects the content's
@@ -866,9 +864,7 @@ class Response:
             for line in decoder.flush():
                 yield line
 
-    def iter_raw(
-        self, chunk_size: typing.Optional[int] = None
-    ) -> typing.Iterator[bytes]:
+    def iter_raw(self, chunk_size: int | None = None) -> typing.Iterator[bytes]:
         """
         A byte-iterator over the raw response content.
         """
@@ -916,7 +912,7 @@ class Response:
         return self._content
 
     async def aiter_bytes(
-        self, chunk_size: typing.Optional[int] = None
+        self, chunk_size: int | None = None
     ) -> typing.AsyncIterator[bytes]:
         """
         A byte-iterator over the decoded response content.
@@ -941,7 +937,7 @@ class Response:
                     yield chunk
 
     async def aiter_text(
-        self, chunk_size: typing.Optional[int] = None
+        self, chunk_size: int | None = None
     ) -> typing.AsyncIterator[str]:
         """
         A str-iterator over the decoded response content
@@ -971,7 +967,7 @@ class Response:
                 yield line
 
     async def aiter_raw(
-        self, chunk_size: typing.Optional[int] = None
+        self, chunk_size: int | None = None
     ) -> typing.AsyncIterator[bytes]:
         """
         A byte-iterator over the raw response content.
@@ -1017,7 +1013,7 @@ class Cookies(typing.MutableMapping[str, str]):
     HTTP Cookies, as a mutable mapping.
     """
 
-    def __init__(self, cookies: typing.Optional[CookieTypes] = None) -> None:
+    def __init__(self, cookies: CookieTypes | None = None) -> None:
         if cookies is None or isinstance(cookies, dict):
             self.jar = CookieJar()
             if isinstance(cookies, dict):
@@ -1079,10 +1075,10 @@ class Cookies(typing.MutableMapping[str, str]):
     def get(  # type: ignore
         self,
         name: str,
-        default: typing.Optional[str] = None,
-        domain: typing.Optional[str] = None,
-        path: typing.Optional[str] = None,
-    ) -> typing.Optional[str]:
+        default: str | None = None,
+        domain: str | None = None,
+        path: str | None = None,
+    ) -> str | None:
         """
         Get a cookie by name. May optionally include domain and path
         in order to specify exactly which cookie to retrieve.
@@ -1104,8 +1100,8 @@ class Cookies(typing.MutableMapping[str, str]):
     def delete(
         self,
         name: str,
-        domain: typing.Optional[str] = None,
-        path: typing.Optional[str] = None,
+        domain: str | None = None,
+        path: str | None = None,
     ) -> None:
         """
         Delete a cookie by name. May optionally include domain and path
@@ -1125,9 +1121,7 @@ class Cookies(typing.MutableMapping[str, str]):
         for cookie in remove:
             self.jar.clear(cookie.domain, cookie.path, cookie.name)
 
-    def clear(
-        self, domain: typing.Optional[str] = None, path: typing.Optional[str] = None
-    ) -> None:
+    def clear(self, domain: str | None = None, path: str | None = None) -> None:
         """
         Delete all cookies. Optionally include a domain and path in
         order to only delete a subset of all the cookies.
@@ -1140,7 +1134,7 @@ class Cookies(typing.MutableMapping[str, str]):
             args.append(path)
         self.jar.clear(*args)
 
-    def update(self, cookies: typing.Optional[CookieTypes] = None) -> None:  # type: ignore
+    def update(self, cookies: CookieTypes | None = None) -> None:  # type: ignore
         cookies = Cookies(cookies)
         for cookie in cookies.jar:
             self.jar.set_cookie(cookie)
index 1d451c382b320c510081586262e5ff252dea134b..8edb622778afe1d1c832cc9857a8acd4bf2125f4 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import io
 import os
 import typing
@@ -21,8 +23,8 @@ from ._utils import (
 
 
 def get_multipart_boundary_from_content_type(
-    content_type: typing.Optional[bytes],
-) -> typing.Optional[bytes]:
+    content_type: bytes | None,
+) -> bytes | None:
     if not content_type or not content_type.startswith(b"multipart/form-data"):
         return None
     # parse boundary according to
@@ -39,9 +41,7 @@ class DataField:
     A single form field item, within a multipart form field.
     """
 
-    def __init__(
-        self, name: str, value: typing.Union[str, bytes, int, float, None]
-    ) -> None:
+    def __init__(self, name: str, value: str | bytes | int | float | None) -> None:
         if not isinstance(name, str):
             raise TypeError(
                 f"Invalid type for name. Expected str, got {type(name)}: {name!r}"
@@ -52,7 +52,7 @@ class DataField:
                 f" got {type(value)}: {value!r}"
             )
         self.name = name
-        self.value: typing.Union[str, bytes] = (
+        self.value: str | bytes = (
             value if isinstance(value, bytes) else primitive_value_to_str(value)
         )
 
@@ -93,8 +93,8 @@ class FileField:
 
         fileobj: FileContent
 
-        headers: typing.Dict[str, str] = {}
-        content_type: typing.Optional[str] = None
+        headers: dict[str, str] = {}
+        content_type: str | None = None
 
         # This large tuple based API largely mirror's requests' API
         # It would be good to think of better APIs for this that we could
@@ -137,7 +137,7 @@ class FileField:
         self.file = fileobj
         self.headers = headers
 
-    def get_length(self) -> typing.Optional[int]:
+    def get_length(self) -> int | None:
         headers = self.render_headers()
 
         if isinstance(self.file, (str, bytes)):
@@ -199,7 +199,7 @@ class MultipartStream(SyncByteStream, AsyncByteStream):
         self,
         data: RequestData,
         files: RequestFiles,
-        boundary: typing.Optional[bytes] = None,
+        boundary: bytes | None = None,
     ) -> None:
         if boundary is None:
             boundary = os.urandom(16).hex().encode("ascii")
@@ -212,7 +212,7 @@ class MultipartStream(SyncByteStream, AsyncByteStream):
 
     def _iter_fields(
         self, data: RequestData, files: RequestFiles
-    ) -> typing.Iterator[typing.Union[FileField, DataField]]:
+    ) -> typing.Iterator[FileField | DataField]:
         for name, value in data.items():
             if isinstance(value, (tuple, list)):
                 for item in value:
@@ -231,7 +231,7 @@ class MultipartStream(SyncByteStream, AsyncByteStream):
             yield b"\r\n"
         yield b"--%s--\r\n" % self.boundary
 
-    def get_content_length(self) -> typing.Optional[int]:
+    def get_content_length(self) -> int | None:
         """
         Return the length of the multipart encoded content, or `None` if
         any of the files have a length that cannot be determined upfront.
@@ -253,7 +253,7 @@ class MultipartStream(SyncByteStream, AsyncByteStream):
 
     # Content stream interface.
 
-    def get_headers(self) -> typing.Dict[str, str]:
+    def get_headers(self) -> dict[str, str]:
         content_length = self.get_content_length()
         content_type = self.content_type
         if content_length is None:
index 671c30e1b80f82adebc3018b1e53a90054d93bfb..4cde4e6845c4528cfda25a54cffcca5c8cd2858a 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from enum import IntEnum
 
 
@@ -21,7 +23,7 @@ class codes(IntEnum):
         * RFC 8470: Using Early Data in HTTP
     """
 
-    def __new__(cls, value: int, phrase: str = "") -> "codes":
+    def __new__(cls, value: int, phrase: str = "") -> codes:
         obj = int.__new__(cls, value)
         obj._value_ = value
 
index 08cd392f75c62b3d6aa9ee547ed9e6fc4fd702d0..9543a12861cf7f792e93aa839fb81112e6f9b031 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 
 import sniffio
@@ -24,7 +26,7 @@ _ASGIApp = typing.Callable[
 ]
 
 
-def create_event() -> "Event":
+def create_event() -> Event:
     if sniffio.current_async_library() == "trio":
         import trio
 
@@ -36,7 +38,7 @@ def create_event() -> "Event":
 
 
 class ASGIResponseStream(AsyncByteStream):
-    def __init__(self, body: typing.List[bytes]) -> None:
+    def __init__(self, body: list[bytes]) -> None:
         self._body = body
 
     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
@@ -81,7 +83,7 @@ class ASGITransport(AsyncBaseTransport):
         app: _ASGIApp,
         raise_app_exceptions: bool = True,
         root_path: str = "",
-        client: typing.Tuple[str, int] = ("127.0.0.1", 123),
+        client: tuple[str, int] = ("127.0.0.1", 123),
     ) -> None:
         self.app = app
         self.raise_app_exceptions = raise_app_exceptions
@@ -123,7 +125,7 @@ class ASGITransport(AsyncBaseTransport):
 
         # ASGI callables.
 
-        async def receive() -> typing.Dict[str, typing.Any]:
+        async def receive() -> dict[str, typing.Any]:
             nonlocal request_complete
 
             if request_complete:
@@ -137,7 +139,7 @@ class ASGITransport(AsyncBaseTransport):
                 return {"type": "http.request", "body": b"", "more_body": False}
             return {"type": "http.request", "body": body, "more_body": True}
 
-        async def send(message: typing.Dict[str, typing.Any]) -> None:
+        async def send(message: dict[str, typing.Any]) -> None:
             nonlocal status_code, response_headers, response_started
 
             if message["type"] == "http.response.start":
index f6fdfe694340ab00e0759c2cfb1a2ea53ed65736..8b6dc3c239151fa80fdc7b9605a63fa7f4915c61 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 from types import TracebackType
 
@@ -13,9 +15,9 @@ class BaseTransport:
 
     def __exit__(
         self,
-        exc_type: typing.Optional[typing.Type[BaseException]] = None,
-        exc_value: typing.Optional[BaseException] = None,
-        traceback: typing.Optional[TracebackType] = None,
+        exc_type: type[BaseException] | None = None,
+        exc_value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         self.close()
 
@@ -64,9 +66,9 @@ class AsyncBaseTransport:
 
     async def __aexit__(
         self,
-        exc_type: typing.Optional[typing.Type[BaseException]] = None,
-        exc_value: typing.Optional[BaseException] = None,
-        traceback: typing.Optional[TracebackType] = None,
+        exc_type: type[BaseException] | None = None,
+        exc_value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         await self.aclose()
 
index 14a087389a8ba910a6b4d88ef69527ba9eb335c0..14476a3ce3effdfa76bec5d47062a1f6242dc8bb 100644 (file)
@@ -23,6 +23,8 @@ client = httpx.Client(transport=transport)
 transport = httpx.HTTPTransport(uds="socket.uds")
 client = httpx.Client(transport=transport)
 """
+from __future__ import annotations
+
 import contextlib
 import typing
 from types import TracebackType
@@ -120,16 +122,16 @@ class HTTPTransport(BaseTransport):
     def __init__(
         self,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
         limits: Limits = DEFAULT_LIMITS,
         trust_env: bool = True,
-        proxy: typing.Optional[ProxyTypes] = None,
-        uds: typing.Optional[str] = None,
-        local_address: typing.Optional[str] = None,
+        proxy: ProxyTypes | None = None,
+        uds: str | None = None,
+        local_address: str | None = None,
         retries: int = 0,
-        socket_options: typing.Optional[typing.Iterable[SOCKET_OPTION]] = None,
+        socket_options: typing.Iterable[SOCKET_OPTION] | None = None,
     ) -> None:
         ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env)
         proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy
@@ -202,9 +204,9 @@ class HTTPTransport(BaseTransport):
 
     def __exit__(
         self,
-        exc_type: typing.Optional[typing.Type[BaseException]] = None,
-        exc_value: typing.Optional[BaseException] = None,
-        traceback: typing.Optional[TracebackType] = None,
+        exc_type: type[BaseException] | None = None,
+        exc_value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         with map_httpcore_exceptions():
             self._pool.__exit__(exc_type, exc_value, traceback)
@@ -261,16 +263,16 @@ class AsyncHTTPTransport(AsyncBaseTransport):
     def __init__(
         self,
         verify: VerifyTypes = True,
-        cert: typing.Optional[CertTypes] = None,
+        cert: CertTypes | None = None,
         http1: bool = True,
         http2: bool = False,
         limits: Limits = DEFAULT_LIMITS,
         trust_env: bool = True,
-        proxy: typing.Optional[ProxyTypes] = None,
-        uds: typing.Optional[str] = None,
-        local_address: typing.Optional[str] = None,
+        proxy: ProxyTypes | None = None,
+        uds: str | None = None,
+        local_address: str | None = None,
         retries: int = 0,
-        socket_options: typing.Optional[typing.Iterable[SOCKET_OPTION]] = None,
+        socket_options: typing.Iterable[SOCKET_OPTION] | None = None,
     ) -> None:
         ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env)
         proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy
@@ -342,9 +344,9 @@ class AsyncHTTPTransport(AsyncBaseTransport):
 
     async def __aexit__(
         self,
-        exc_type: typing.Optional[typing.Type[BaseException]] = None,
-        exc_value: typing.Optional[BaseException] = None,
-        traceback: typing.Optional[TracebackType] = None,
+        exc_type: type[BaseException] | None = None,
+        exc_value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         with map_httpcore_exceptions():
             await self._pool.__aexit__(exc_type, exc_value, traceback)
index 82043da2d908f7575097f14b08c1a8a60fa1f8a4..5abea837312b22f502ef18675e1a1f7b2b84a1dc 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 
 from .._models import Request, Response
@@ -8,7 +10,7 @@ AsyncHandler = typing.Callable[[Request], typing.Coroutine[None, None, Response]
 
 
 class MockTransport(AsyncBaseTransport, BaseTransport):
-    def __init__(self, handler: typing.Union[SyncHandler, AsyncHandler]) -> None:
+    def __init__(self, handler: SyncHandler | AsyncHandler) -> None:
         self.handler = handler
 
     def handle_request(
index a23d42c414e5481f2f6fb76fc53701f144c1ae91..cd03a9417baf8148369e9dc7e2809595ecdee47b 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import io
 import itertools
 import sys
@@ -71,11 +73,11 @@ class WSGITransport(BaseTransport):
 
     def __init__(
         self,
-        app: "WSGIApplication",
+        app: WSGIApplication,
         raise_app_exceptions: bool = True,
         script_name: str = "",
         remote_addr: str = "127.0.0.1",
-        wsgi_errors: typing.Optional[typing.TextIO] = None,
+        wsgi_errors: typing.TextIO | None = None,
     ) -> None:
         self.app = app
         self.raise_app_exceptions = raise_app_exceptions
@@ -117,8 +119,8 @@ class WSGITransport(BaseTransport):
 
         def start_response(
             status: str,
-            response_headers: typing.List[typing.Tuple[str, str]],
-            exc_info: typing.Optional["OptExcInfo"] = None,
+            response_headers: list[tuple[str, str]],
+            exc_info: OptExcInfo | None = None,
         ) -> typing.Callable[[bytes], typing.Any]:
             nonlocal seen_status, seen_response_headers, seen_exc_info
             seen_status = status
index 07bbea9070cc6451c33f8cec7bcb0e607f25b000..6a4b55b38c0780d6ab9e28b779076c91e880d598 100644 (file)
@@ -15,6 +15,8 @@ Previously we relied on the excellent `rfc3986` package to handle URL parsing an
 validation, but this module provides a simpler alternative, with less indirection
 required.
 """
+from __future__ import annotations
+
 import ipaddress
 import re
 import typing
@@ -95,10 +97,10 @@ class ParseResult(typing.NamedTuple):
     scheme: str
     userinfo: str
     host: str
-    port: typing.Optional[int]
+    port: int | None
     path: str
-    query: typing.Optional[str]
-    fragment: typing.Optional[str]
+    query: str | None
+    fragment: str | None
 
     @property
     def authority(self) -> str:
@@ -119,7 +121,7 @@ class ParseResult(typing.NamedTuple):
             ]
         )
 
-    def copy_with(self, **kwargs: typing.Optional[str]) -> "ParseResult":
+    def copy_with(self, **kwargs: str | None) -> ParseResult:
         if not kwargs:
             return self
 
@@ -146,7 +148,7 @@ class ParseResult(typing.NamedTuple):
         )
 
 
-def urlparse(url: str = "", **kwargs: typing.Optional[str]) -> ParseResult:
+def urlparse(url: str = "", **kwargs: str | None) -> ParseResult:
     # Initial basic checks on allowable URLs.
     # ---------------------------------------
 
@@ -243,7 +245,7 @@ def urlparse(url: str = "", **kwargs: typing.Optional[str]) -> ParseResult:
     parsed_scheme: str = scheme.lower()
     parsed_userinfo: str = quote(userinfo, safe=SUB_DELIMS + ":")
     parsed_host: str = encode_host(host)
-    parsed_port: typing.Optional[int] = normalize_port(port, scheme)
+    parsed_port: int | None = normalize_port(port, scheme)
 
     has_scheme = parsed_scheme != ""
     has_authority = (
@@ -260,11 +262,11 @@ def urlparse(url: str = "", **kwargs: typing.Optional[str]) -> ParseResult:
     # For 'path' we need to drop ? and # from the GEN_DELIMS set.
     parsed_path: str = quote(path, safe=SUB_DELIMS + ":/[]@")
     # For 'query' we need to drop '#' from the GEN_DELIMS set.
-    parsed_query: typing.Optional[str] = (
+    parsed_query: str | None = (
         None if query is None else quote(query, safe=SUB_DELIMS + ":/?[]@")
     )
     # For 'fragment' we can include all of the GEN_DELIMS set.
-    parsed_fragment: typing.Optional[str] = (
+    parsed_fragment: str | None = (
         None if fragment is None else quote(fragment, safe=SUB_DELIMS + ":/?#[]@")
     )
 
@@ -327,9 +329,7 @@ def encode_host(host: str) -> str:
         raise InvalidURL(f"Invalid IDNA hostname: {host!r}")
 
 
-def normalize_port(
-    port: typing.Optional[typing.Union[str, int]], scheme: str
-) -> typing.Optional[int]:
+def normalize_port(port: str | int | None, scheme: str) -> int | None:
     # From https://tools.ietf.org/html/rfc3986#section-3.2.3
     #
     # "A scheme may define a default port.  For example, the "http" scheme
@@ -393,7 +393,7 @@ def normalize_path(path: str) -> str:
     """
     # https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
     components = path.split("/")
-    output: typing.List[str] = []
+    output: list[str] = []
     for component in components:
         if component == ".":
             pass
@@ -479,7 +479,7 @@ def quote(string: str, safe: str = "/") -> str:
     return "".join(parts)
 
 
-def urlencode(items: typing.List[typing.Tuple[str, str]]) -> str:
+def urlencode(items: list[tuple[str, str]]) -> str:
     """
     We can use a much simpler version of the stdlib urlencode here because
     we don't need to handle a bunch of different typing cases, such as bytes vs str.
index 26202e95db29e1fa31eb7344f55b145a62e6f314..43dedd5644c6aef93004f0e2c82bd2576792109b 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 from urllib.parse import parse_qs, unquote
 
@@ -70,9 +72,7 @@ class URL:
       themselves.
     """
 
-    def __init__(
-        self, url: typing.Union["URL", str] = "", **kwargs: typing.Any
-    ) -> None:
+    def __init__(self, url: URL | str = "", **kwargs: typing.Any) -> None:
         if kwargs:
             allowed = {
                 "scheme": str,
@@ -213,7 +213,7 @@ class URL:
         return self._uri_reference.host.encode("ascii")
 
     @property
-    def port(self) -> typing.Optional[int]:
+    def port(self) -> int | None:
         """
         The URL port as an integer.
 
@@ -270,7 +270,7 @@ class URL:
         return query.encode("ascii")
 
     @property
-    def params(self) -> "QueryParams":
+    def params(self) -> QueryParams:
         """
         The URL query parameters, neatly parsed and packaged into an immutable
         multidict representation.
@@ -338,7 +338,7 @@ class URL:
         """
         return not self.is_absolute_url
 
-    def copy_with(self, **kwargs: typing.Any) -> "URL":
+    def copy_with(self, **kwargs: typing.Any) -> URL:
         """
         Copy this URL, returning a new URL with some components altered.
         Accepts the same set of parameters as the components that are made
@@ -353,19 +353,19 @@ class URL:
         """
         return URL(self, **kwargs)
 
-    def copy_set_param(self, key: str, value: typing.Any = None) -> "URL":
+    def copy_set_param(self, key: str, value: typing.Any = None) -> URL:
         return self.copy_with(params=self.params.set(key, value))
 
-    def copy_add_param(self, key: str, value: typing.Any = None) -> "URL":
+    def copy_add_param(self, key: str, value: typing.Any = None) -> URL:
         return self.copy_with(params=self.params.add(key, value))
 
-    def copy_remove_param(self, key: str) -> "URL":
+    def copy_remove_param(self, key: str) -> URL:
         return self.copy_with(params=self.params.remove(key))
 
-    def copy_merge_params(self, params: QueryParamTypes) -> "URL":
+    def copy_merge_params(self, params: QueryParamTypes) -> URL:
         return self.copy_with(params=self.params.merge(params))
 
-    def join(self, url: URLTypes) -> "URL":
+    def join(self, url: URLTypes) -> URL:
         """
         Return an absolute URL, using this URL as the base.
 
@@ -420,9 +420,7 @@ class QueryParams(typing.Mapping[str, str]):
     URL query parameters, as a multi-dict.
     """
 
-    def __init__(
-        self, *args: typing.Optional[QueryParamTypes], **kwargs: typing.Any
-    ) -> None:
+    def __init__(self, *args: QueryParamTypes | None, **kwargs: typing.Any) -> None:
         assert len(args) < 2, "Too many arguments."
         assert not (args and kwargs), "Cannot mix named and unnamed arguments."
 
@@ -434,7 +432,7 @@ class QueryParams(typing.Mapping[str, str]):
         elif isinstance(value, QueryParams):
             self._dict = {k: list(v) for k, v in value._dict.items()}
         else:
-            dict_value: typing.Dict[typing.Any, typing.List[typing.Any]] = {}
+            dict_value: dict[typing.Any, list[typing.Any]] = {}
             if isinstance(value, (list, tuple)):
                 # Convert list inputs like:
                 #     [("a", "123"), ("a", "456"), ("b", "789")]
@@ -495,7 +493,7 @@ class QueryParams(typing.Mapping[str, str]):
         """
         return {k: v[0] for k, v in self._dict.items()}.items()
 
-    def multi_items(self) -> typing.List[typing.Tuple[str, str]]:
+    def multi_items(self) -> list[tuple[str, str]]:
         """
         Return all items in the query params. Allow duplicate keys to occur.
 
@@ -504,7 +502,7 @@ class QueryParams(typing.Mapping[str, str]):
         q = httpx.QueryParams("a=123&a=456&b=789")
         assert list(q.multi_items()) == [("a", "123"), ("a", "456"), ("b", "789")]
         """
-        multi_items: typing.List[typing.Tuple[str, str]] = []
+        multi_items: list[tuple[str, str]] = []
         for k, v in self._dict.items():
             multi_items.extend([(k, i) for i in v])
         return multi_items
@@ -523,7 +521,7 @@ class QueryParams(typing.Mapping[str, str]):
             return self._dict[str(key)][0]
         return default
 
-    def get_list(self, key: str) -> typing.List[str]:
+    def get_list(self, key: str) -> list[str]:
         """
         Get all values from the query param for a given key.
 
@@ -534,7 +532,7 @@ class QueryParams(typing.Mapping[str, str]):
         """
         return list(self._dict.get(str(key), []))
 
-    def set(self, key: str, value: typing.Any = None) -> "QueryParams":
+    def set(self, key: str, value: typing.Any = None) -> QueryParams:
         """
         Return a new QueryParams instance, setting the value of a key.
 
@@ -549,7 +547,7 @@ class QueryParams(typing.Mapping[str, str]):
         q._dict[str(key)] = [primitive_value_to_str(value)]
         return q
 
-    def add(self, key: str, value: typing.Any = None) -> "QueryParams":
+    def add(self, key: str, value: typing.Any = None) -> QueryParams:
         """
         Return a new QueryParams instance, setting or appending the value of a key.
 
@@ -564,7 +562,7 @@ class QueryParams(typing.Mapping[str, str]):
         q._dict[str(key)] = q.get_list(key) + [primitive_value_to_str(value)]
         return q
 
-    def remove(self, key: str) -> "QueryParams":
+    def remove(self, key: str) -> QueryParams:
         """
         Return a new QueryParams instance, removing the value of a key.
 
@@ -579,7 +577,7 @@ class QueryParams(typing.Mapping[str, str]):
         q._dict.pop(str(key), None)
         return q
 
-    def merge(self, params: typing.Optional[QueryParamTypes] = None) -> "QueryParams":
+    def merge(self, params: QueryParamTypes | None = None) -> QueryParams:
         """
         Return a new QueryParams instance, updated with.
 
@@ -635,7 +633,7 @@ class QueryParams(typing.Mapping[str, str]):
         query_string = str(self)
         return f"{class_name}({query_string!r})"
 
-    def update(self, params: typing.Optional[QueryParamTypes] = None) -> None:
+    def update(self, params: QueryParamTypes | None = None) -> None:
         raise RuntimeError(
             "QueryParams are immutable since 0.18.0. "
             "Use `q = q.merge(...)` to create an updated copy."
index bc3cb001dd77589495a48c589833896f175a762f..a9ece1943878d0182d87ca77569fe3bf47e3bba8 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import codecs
 import email.message
 import ipaddress
@@ -27,9 +29,9 @@ _HTML5_FORM_ENCODING_RE = re.compile(
 
 
 def normalize_header_key(
-    value: typing.Union[str, bytes],
+    value: str | bytes,
     lower: bool,
-    encoding: typing.Optional[str] = None,
+    encoding: str | None = None,
 ) -> bytes:
     """
     Coerce str/bytes into a strictly byte-wise HTTP header key.
@@ -42,9 +44,7 @@ def normalize_header_key(
     return bytes_value.lower() if lower else bytes_value
 
 
-def normalize_header_value(
-    value: typing.Union[str, bytes], encoding: typing.Optional[str] = None
-) -> bytes:
+def normalize_header_value(value: str | bytes, encoding: str | None = None) -> bytes:
     """
     Coerce str/bytes into a strictly byte-wise HTTP header value.
     """
@@ -53,7 +53,7 @@ def normalize_header_value(
     return value.encode(encoding or "ascii")
 
 
-def primitive_value_to_str(value: "PrimitiveData") -> str:
+def primitive_value_to_str(value: PrimitiveData) -> str:
     """
     Coerce a primitive data type into a string value.
 
@@ -91,7 +91,7 @@ def format_form_param(name: str, value: str) -> bytes:
     return f'{name}="{value}"'.encode()
 
 
-def get_ca_bundle_from_env() -> typing.Optional[str]:
+def get_ca_bundle_from_env() -> str | None:
     if "SSL_CERT_FILE" in os.environ:
         ssl_file = Path(os.environ["SSL_CERT_FILE"])
         if ssl_file.is_file():
@@ -103,7 +103,7 @@ def get_ca_bundle_from_env() -> typing.Optional[str]:
     return None
 
 
-def parse_header_links(value: str) -> typing.List[typing.Dict[str, str]]:
+def parse_header_links(value: str) -> list[dict[str, str]]:
     """
     Returns a list of parsed link headers, for more info see:
     https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link
@@ -119,7 +119,7 @@ def parse_header_links(value: str) -> typing.List[typing.Dict[str, str]]:
     :param value: HTTP Link entity-header field
     :return: list of parsed link headers
     """
-    links: typing.List[typing.Dict[str, str]] = []
+    links: list[dict[str, str]] = []
     replace_chars = " '\""
     value = value.strip(replace_chars)
     if not value:
@@ -140,7 +140,7 @@ def parse_header_links(value: str) -> typing.List[typing.Dict[str, str]]:
     return links
 
 
-def parse_content_type_charset(content_type: str) -> typing.Optional[str]:
+def parse_content_type_charset(content_type: str) -> str | None:
     # We used to use `cgi.parse_header()` here, but `cgi` became a dead battery.
     # See: https://peps.python.org/pep-0594/#cgi
     msg = email.message.Message()
@@ -152,21 +152,21 @@ SENSITIVE_HEADERS = {"authorization", "proxy-authorization"}
 
 
 def obfuscate_sensitive_headers(
-    items: typing.Iterable[typing.Tuple[typing.AnyStr, typing.AnyStr]],
-) -> typing.Iterator[typing.Tuple[typing.AnyStr, typing.AnyStr]]:
+    items: typing.Iterable[tuple[typing.AnyStr, typing.AnyStr]],
+) -> typing.Iterator[tuple[typing.AnyStr, typing.AnyStr]]:
     for k, v in items:
         if to_str(k.lower()) in SENSITIVE_HEADERS:
             v = to_bytes_or_str("[secure]", match_type_of=v)
         yield k, v
 
 
-def port_or_default(url: "URL") -> typing.Optional[int]:
+def port_or_default(url: URL) -> int | None:
     if url.port is not None:
         return url.port
     return {"http": 80, "https": 443}.get(url.scheme)
 
 
-def same_origin(url: "URL", other: "URL") -> bool:
+def same_origin(url: URL, other: URL) -> bool:
     """
     Return 'True' if the given URLs share the same origin.
     """
@@ -177,7 +177,7 @@ def same_origin(url: "URL", other: "URL") -> bool:
     )
 
 
-def is_https_redirect(url: "URL", location: "URL") -> bool:
+def is_https_redirect(url: URL, location: URL) -> bool:
     """
     Return 'True' if 'location' is a HTTPS upgrade of 'url'
     """
@@ -192,7 +192,7 @@ def is_https_redirect(url: "URL", location: "URL") -> bool:
     )
 
 
-def get_environment_proxies() -> typing.Dict[str, typing.Optional[str]]:
+def get_environment_proxies() -> dict[str, str | None]:
     """Gets proxy information from the environment"""
 
     # urllib.request.getproxies() falls back on System
@@ -200,7 +200,7 @@ def get_environment_proxies() -> typing.Dict[str, typing.Optional[str]]:
     # We don't want to propagate non-HTTP proxies into
     # our configuration such as 'TRAVIS_APT_PROXY'.
     proxy_info = getproxies()
-    mounts: typing.Dict[str, typing.Optional[str]] = {}
+    mounts: dict[str, str | None] = {}
 
     for scheme in ("http", "https", "all"):
         if proxy_info.get(scheme):
@@ -241,11 +241,11 @@ def get_environment_proxies() -> typing.Dict[str, typing.Optional[str]]:
     return mounts
 
 
-def to_bytes(value: typing.Union[str, bytes], encoding: str = "utf-8") -> bytes:
+def to_bytes(value: str | bytes, encoding: str = "utf-8") -> bytes:
     return value.encode(encoding) if isinstance(value, str) else value
 
 
-def to_str(value: typing.Union[str, bytes], encoding: str = "utf-8") -> str:
+def to_str(value: str | bytes, encoding: str = "utf-8") -> str:
     return value if isinstance(value, str) else value.decode(encoding)
 
 
@@ -257,13 +257,13 @@ def unquote(value: str) -> str:
     return value[1:-1] if value[0] == value[-1] == '"' else value
 
 
-def guess_content_type(filename: typing.Optional[str]) -> typing.Optional[str]:
+def guess_content_type(filename: str | None) -> str | None:
     if filename:
         return mimetypes.guess_type(filename)[0] or "application/octet-stream"
     return None
 
 
-def peek_filelike_length(stream: typing.Any) -> typing.Optional[int]:
+def peek_filelike_length(stream: typing.Any) -> int | None:
     """
     Given a file-like stream object, return its length in number of bytes
     without reading it into memory.
@@ -373,7 +373,7 @@ class URLPattern:
         self.host = "" if url.host == "*" else url.host
         self.port = url.port
         if not url.host or url.host == "*":
-            self.host_regex: typing.Optional[typing.Pattern[str]] = None
+            self.host_regex: typing.Pattern[str] | None = None
         elif url.host.startswith("*."):
             # *.example.com should match "www.example.com", but not "example.com"
             domain = re.escape(url.host[2:])
@@ -387,7 +387,7 @@ class URLPattern:
             domain = re.escape(url.host)
             self.host_regex = re.compile(f"^{domain}$")
 
-    def matches(self, other: "URL") -> bool:
+    def matches(self, other: URL) -> bool:
         if self.scheme and self.scheme != other.scheme:
             return False
         if (
@@ -401,7 +401,7 @@ class URLPattern:
         return True
 
     @property
-    def priority(self) -> typing.Tuple[int, int, int]:
+    def priority(self) -> tuple[int, int, int]:
         """
         The priority allows URLPattern instances to be sortable, so that
         we can match from most specific to least specific.
@@ -417,7 +417,7 @@ class URLPattern:
     def __hash__(self) -> int:
         return hash(self.pattern)
 
-    def __lt__(self, other: "URLPattern") -> bool:
+    def __lt__(self, other: URLPattern) -> bool:
         return self.priority < other.priority
 
     def __eq__(self, other: typing.Any) -> bool:
index 49664df5899dd477cd6dfa88fca2a0c947a0244c..8d7eaa3c58ac4f4b334ebb1764d976f12bd8e6cc 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 from datetime import timedelta
 
@@ -181,7 +183,7 @@ async def test_100_continue(server):
 async def test_context_managed_transport():
     class Transport(httpx.AsyncBaseTransport):
         def __init__(self) -> None:
-            self.events: typing.List[str] = []
+            self.events: list[str] = []
 
         async def aclose(self):
             # The base implementation of httpx.AsyncBaseTransport just
@@ -214,7 +216,7 @@ async def test_context_managed_transport_and_mount():
     class Transport(httpx.AsyncBaseTransport):
         def __init__(self, name: str) -> None:
             self.name: str = name
-            self.events: typing.List[str] = []
+            self.events: list[str] = []
 
         async def aclose(self):
             # The base implementation of httpx.AsyncBaseTransport just
index fcc6ec6a08ed6c89edff90e97c926171862e22ed..2951e01b8a5259e634ccd7291dbdaa750e828b9b 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 from datetime import timedelta
 
@@ -230,7 +232,7 @@ def test_merge_relative_url_with_encoded_slashes():
 def test_context_managed_transport():
     class Transport(httpx.BaseTransport):
         def __init__(self) -> None:
-            self.events: typing.List[str] = []
+            self.events: list[str] = []
 
         def close(self):
             # The base implementation of httpx.BaseTransport just
@@ -262,7 +264,7 @@ def test_context_managed_transport_and_mount():
     class Transport(httpx.BaseTransport):
         def __init__(self, name: str) -> None:
             self.name: str = name
-            self.events: typing.List[str] = []
+            self.events: list[str] = []
 
         def close(self):
             # The base implementation of httpx.BaseTransport just
index 170a93453cfafd6e6ae1130c95f0b4f8d19bac61..73644e04e658efbb1718fc1c44d994de2cb22564 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 import zlib
 
@@ -224,7 +226,7 @@ def test_text_decoder_empty_cases():
     [((b"Hello,", b" world!"), ["Hello,", " world!"])],
 )
 def test_streaming_text_decoder(
-    data: typing.Iterable[bytes], expected: typing.List[str]
+    data: typing.Iterable[bytes], expected: list[str]
 ) -> None:
     response = httpx.Response(200, content=iter(data))
     assert list(response.iter_text()) == expected
index 6547ab37a52e9aeb2d3123da0b372d92982c5334..60c8721c02300f688a407154a5e64ab97a21e8a6 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import typing
 
 import httpcore
@@ -34,7 +36,7 @@ def test_httpcore_all_exceptions_mapped() -> None:
         pytest.fail(f"Unmapped httpcore exceptions: {unmapped_exceptions}")
 
 
-def test_httpcore_exception_mapping(server: "TestServer") -> None:
+def test_httpcore_exception_mapping(server: TestServer) -> None:
     """
     HTTPCore exception mapping works as expected.
     """
index fc283c9cc43d8a5b5ae336c3bc9d08dd19d8599b..5c4629152c09d93ff8ca50331761e9ae41af2b06 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import io
 import tempfile
 import typing
@@ -148,7 +150,7 @@ def test_multipart_file_tuple():
 
 
 @pytest.mark.parametrize("file_content_type", [None, "text/plain"])
-def test_multipart_file_tuple_headers(file_content_type: typing.Optional[str]) -> None:
+def test_multipart_file_tuple_headers(file_content_type: str | None) -> None:
     file_name = "test.txt"
     file_content = io.BytesIO(b"<file content>")
     file_headers = {"Expires": "0"}
index a952da6af914f5b6df768cb91390af2d7f83c073..3565a48c925a320c74a6398283298f7df238dbff 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import sys
 import typing
 import wsgiref.validate
@@ -12,7 +14,7 @@ if typing.TYPE_CHECKING:  # pragma: no cover
     from _typeshed.wsgi import StartResponse, WSGIApplication, WSGIEnvironment
 
 
-def application_factory(output: typing.Iterable[bytes]) -> "WSGIApplication":
+def application_factory(output: typing.Iterable[bytes]) -> WSGIApplication:
     def application(environ, start_response):
         status = "200 OK"
 
@@ -29,7 +31,7 @@ def application_factory(output: typing.Iterable[bytes]) -> "WSGIApplication":
 
 
 def echo_body(
-    environ: "WSGIEnvironment", start_response: "StartResponse"
+    environ: WSGIEnvironment, start_response: StartResponse
 ) -> typing.Iterable[bytes]:
     status = "200 OK"
     output = environ["wsgi.input"].read()
@@ -44,7 +46,7 @@ def echo_body(
 
 
 def echo_body_with_response_stream(
-    environ: "WSGIEnvironment", start_response: "StartResponse"
+    environ: WSGIEnvironment, start_response: StartResponse
 ) -> typing.Iterable[bytes]:
     status = "200 OK"
 
@@ -63,9 +65,9 @@ def echo_body_with_response_stream(
 
 
 def raise_exc(
-    environ: "WSGIEnvironment",
-    start_response: "StartResponse",
-    exc: typing.Type[Exception] = ValueError,
+    environ: WSGIEnvironment,
+    start_response: StartResponse,
+    exc: type[Exception] = ValueError,
 ) -> typing.Iterable[bytes]:
     status = "500 Server Error"
     output = b"Nope!"
@@ -161,7 +163,7 @@ def test_wsgi_server_port(url: str, expected_server_port: str) -> None:
     SERVER_PORT is populated correctly from the requested URL.
     """
     hello_world_app = application_factory([b"Hello, World!"])
-    server_port: typing.Optional[str] = None
+    server_port: str | None = None
 
     def app(environ, start_response):
         nonlocal server_port