Browse Source

Intermediate changes

robot-piglet 10 months ago
parent
commit
492446437a

+ 25 - 62
contrib/python/itsdangerous/py3/.dist-info/METADATA

@@ -1,32 +1,23 @@
 Metadata-Version: 2.1
 Name: itsdangerous
-Version: 2.1.2
+Version: 2.2.0
 Summary: Safely pass data to untrusted environments and back.
-Home-page: https://palletsprojects.com/p/itsdangerous/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Donate, https://palletsprojects.com/donate
-Project-URL: Documentation, https://itsdangerous.palletsprojects.com/
-Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/
-Project-URL: Source Code, https://github.com/pallets/itsdangerous/
-Project-URL: Issue Tracker, https://github.com/pallets/itsdangerous/issues/
-Project-URL: Twitter, https://twitter.com/PalletsTeam
-Project-URL: Chat, https://discord.gg/pallets
-Platform: UNKNOWN
+Maintainer-email: Pallets <contact@palletsprojects.com>
+Requires-Python: >=3.8
+Description-Content-Type: text/markdown
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: BSD License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Requires-Python: >=3.7
-Description-Content-Type: text/x-rst
-License-File: LICENSE.rst
+Classifier: Typing :: Typed
+Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/
+Project-URL: Chat, https://discord.gg/pallets
+Project-URL: Documentation, https://itsdangerous.palletsprojects.com/
+Project-URL: Donate, https://palletsprojects.com/donate
+Project-URL: Source, https://github.com/pallets/itsdangerous/
 
-ItsDangerous
-============
+# ItsDangerous
 
 ... so better sign this
 
@@ -39,59 +30,31 @@ needed. A timestamp can be added and verified automatically while
 loading a token.
 
 
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
-    pip install -U itsdangerous
-
-.. _pip: https://pip.pypa.io/en/stable/getting-started/
-
-
-A Simple Example
-----------------
+## A Simple Example
 
 Here's how you could generate a token for transmitting a user's id and
 name between web requests.
 
-.. code-block:: python
-
-    from itsdangerous import URLSafeSerializer
-    auth_s = URLSafeSerializer("secret key", "auth")
-    token = auth_s.dumps({"id": 5, "name": "itsdangerous"})
+```python
+from itsdangerous import URLSafeSerializer
+auth_s = URLSafeSerializer("secret key", "auth")
+token = auth_s.dumps({"id": 5, "name": "itsdangerous"})
 
-    print(token)
-    # eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg
+print(token)
+# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg
 
-    data = auth_s.loads(token)
-    print(data["name"])
-    # itsdangerous
+data = auth_s.loads(token)
+print(data["name"])
+# itsdangerous
+```
 
 
-Donate
-------
+## Donate
 
 The Pallets organization develops and supports ItsDangerous and other
 popular packages. In order to grow the community of contributors and
 users, and allow the maintainers to devote more time to the projects,
-`please donate today`_.
-
-.. _please donate today: https://palletsprojects.com/donate
-
-
-Links
------
-
--   Documentation: https://itsdangerous.palletsprojects.com/
--   Changes: https://itsdangerous.palletsprojects.com/changes/
--   PyPI Releases: https://pypi.org/project/ItsDangerous/
--   Source Code: https://github.com/pallets/itsdangerous/
--   Issue Tracker: https://github.com/pallets/itsdangerous/issues/
--   Website: https://palletsprojects.com/p/itsdangerous/
--   Twitter: https://twitter.com/PalletsTeam
--   Chat: https://discord.gg/pallets
+[please donate today][].
 
+[please donate today]: https://palletsprojects.com/donate
 

+ 0 - 0
contrib/python/itsdangerous/py3/LICENSE.rst → contrib/python/itsdangerous/py3/LICENSE.txt


+ 40 - 0
contrib/python/itsdangerous/py3/README.md

@@ -0,0 +1,40 @@
+# ItsDangerous
+
+... so better sign this
+
+Various helpers to pass data to untrusted environments and to get it
+back safe and sound. Data is cryptographically signed to ensure that a
+token has not been tampered with.
+
+It's possible to customize how data is serialized. Data is compressed as
+needed. A timestamp can be added and verified automatically while
+loading a token.
+
+
+## A Simple Example
+
+Here's how you could generate a token for transmitting a user's id and
+name between web requests.
+
+```python
+from itsdangerous import URLSafeSerializer
+auth_s = URLSafeSerializer("secret key", "auth")
+token = auth_s.dumps({"id": 5, "name": "itsdangerous"})
+
+print(token)
+# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg
+
+data = auth_s.loads(token)
+print(data["name"])
+# itsdangerous
+```
+
+
+## Donate
+
+The Pallets organization develops and supports ItsDangerous and other
+popular packages. In order to grow the community of contributors and
+users, and allow the maintainers to devote more time to the projects,
+[please donate today][].
+
+[please donate today]: https://palletsprojects.com/donate

+ 0 - 68
contrib/python/itsdangerous/py3/README.rst

@@ -1,68 +0,0 @@
-ItsDangerous
-============
-
-... so better sign this
-
-Various helpers to pass data to untrusted environments and to get it
-back safe and sound. Data is cryptographically signed to ensure that a
-token has not been tampered with.
-
-It's possible to customize how data is serialized. Data is compressed as
-needed. A timestamp can be added and verified automatically while
-loading a token.
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
-    pip install -U itsdangerous
-
-.. _pip: https://pip.pypa.io/en/stable/getting-started/
-
-
-A Simple Example
-----------------
-
-Here's how you could generate a token for transmitting a user's id and
-name between web requests.
-
-.. code-block:: python
-
-    from itsdangerous import URLSafeSerializer
-    auth_s = URLSafeSerializer("secret key", "auth")
-    token = auth_s.dumps({"id": 5, "name": "itsdangerous"})
-
-    print(token)
-    # eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg
-
-    data = auth_s.loads(token)
-    print(data["name"])
-    # itsdangerous
-
-
-Donate
-------
-
-The Pallets organization develops and supports ItsDangerous and other
-popular packages. In order to grow the community of contributors and
-users, and allow the maintainers to devote more time to the projects,
-`please donate today`_.
-
-.. _please donate today: https://palletsprojects.com/donate
-
-
-Links
------
-
--   Documentation: https://itsdangerous.palletsprojects.com/
--   Changes: https://itsdangerous.palletsprojects.com/changes/
--   PyPI Releases: https://pypi.org/project/ItsDangerous/
--   Source Code: https://github.com/pallets/itsdangerous/
--   Issue Tracker: https://github.com/pallets/itsdangerous/issues/
--   Website: https://palletsprojects.com/p/itsdangerous/
--   Twitter: https://twitter.com/PalletsTeam
--   Chat: https://discord.gg/pallets

+ 20 - 1
contrib/python/itsdangerous/py3/itsdangerous/__init__.py

@@ -1,3 +1,7 @@
+from __future__ import annotations
+
+import typing as t
+
 from .encoding import base64_decode as base64_decode
 from .encoding import base64_encode as base64_encode
 from .encoding import want_bytes as want_bytes
@@ -16,4 +20,19 @@ from .timed import TimestampSigner as TimestampSigner
 from .url_safe import URLSafeSerializer as URLSafeSerializer
 from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer
 
-__version__ = "2.1.2"
+
+def __getattr__(name: str) -> t.Any:
+    if name == "__version__":
+        import importlib.metadata
+        import warnings
+
+        warnings.warn(
+            "The '__version__' attribute is deprecated and will be removed in"
+            " ItsDangerous 2.3. Use feature detection or"
+            " 'importlib.metadata.version(\"itsdangerous\")' instead.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        return importlib.metadata.version("itsdangerous")
+
+    raise AttributeError(name)

+ 5 - 3
contrib/python/itsdangerous/py3/itsdangerous/_json.py

@@ -1,16 +1,18 @@
+from __future__ import annotations
+
 import json as _json
-import typing as _t
+import typing as t
 
 
 class _CompactJSON:
     """Wrapper around json module that strips whitespace."""
 
     @staticmethod
-    def loads(payload: _t.Union[str, bytes]) -> _t.Any:
+    def loads(payload: str | bytes) -> t.Any:
         return _json.loads(payload)
 
     @staticmethod
-    def dumps(obj: _t.Any, **kwargs: _t.Any) -> str:
+    def dumps(obj: t.Any, **kwargs: t.Any) -> str:
         kwargs.setdefault("ensure_ascii", False)
         kwargs.setdefault("separators", (",", ":"))
         return _json.dumps(obj, **kwargs)

+ 7 - 7
contrib/python/itsdangerous/py3/itsdangerous/encoding.py

@@ -1,15 +1,15 @@
+from __future__ import annotations
+
 import base64
 import string
 import struct
-import typing as _t
+import typing as t
 
 from .exc import BadData
 
-_t_str_bytes = _t.Union[str, bytes]
-
 
 def want_bytes(
-    s: _t_str_bytes, encoding: str = "utf-8", errors: str = "strict"
+    s: str | bytes, encoding: str = "utf-8", errors: str = "strict"
 ) -> bytes:
     if isinstance(s, str):
         s = s.encode(encoding, errors)
@@ -17,7 +17,7 @@ def want_bytes(
     return s
 
 
-def base64_encode(string: _t_str_bytes) -> bytes:
+def base64_encode(string: str | bytes) -> bytes:
     """Base64 encode a string of bytes or text. The resulting bytes are
     safe to use in URLs.
     """
@@ -25,7 +25,7 @@ def base64_encode(string: _t_str_bytes) -> bytes:
     return base64.urlsafe_b64encode(string).rstrip(b"=")
 
 
-def base64_decode(string: _t_str_bytes) -> bytes:
+def base64_decode(string: str | bytes) -> bytes:
     """Base64 decode a URL-safe string of bytes or text. The result is
     bytes.
     """
@@ -43,7 +43,7 @@ _base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii")
 
 _int64_struct = struct.Struct(">Q")
 _int_to_bytes = _int64_struct.pack
-_bytes_to_int = _t.cast("_t.Callable[[bytes], _t.Tuple[int]]", _int64_struct.unpack)
+_bytes_to_int = t.cast("t.Callable[[bytes], tuple[int]]", _int64_struct.unpack)
 
 
 def int_to_bytes(num: int) -> bytes:

+ 14 - 15
contrib/python/itsdangerous/py3/itsdangerous/exc.py

@@ -1,8 +1,7 @@
-import typing as _t
-from datetime import datetime
+from __future__ import annotations
 
-_t_opt_any = _t.Optional[_t.Any]
-_t_opt_exc = _t.Optional[Exception]
+import typing as t
+from datetime import datetime
 
 
 class BadData(Exception):
@@ -23,7 +22,7 @@ class BadData(Exception):
 class BadSignature(BadData):
     """Raised if a signature does not match."""
 
-    def __init__(self, message: str, payload: _t_opt_any = None):
+    def __init__(self, message: str, payload: t.Any | None = None):
         super().__init__(message)
 
         #: The payload that failed the signature test. In some
@@ -31,7 +30,7 @@ class BadSignature(BadData):
         #: you know it was tampered with.
         #:
         #: .. versionadded:: 0.14
-        self.payload: _t_opt_any = payload
+        self.payload: t.Any | None = payload
 
 
 class BadTimeSignature(BadSignature):
@@ -42,8 +41,8 @@ class BadTimeSignature(BadSignature):
     def __init__(
         self,
         message: str,
-        payload: _t_opt_any = None,
-        date_signed: _t.Optional[datetime] = None,
+        payload: t.Any | None = None,
+        date_signed: datetime | None = None,
     ):
         super().__init__(message, payload)
 
@@ -75,19 +74,19 @@ class BadHeader(BadSignature):
     def __init__(
         self,
         message: str,
-        payload: _t_opt_any = None,
-        header: _t_opt_any = None,
-        original_error: _t_opt_exc = None,
+        payload: t.Any | None = None,
+        header: t.Any | None = None,
+        original_error: Exception | None = None,
     ):
         super().__init__(message, payload)
 
         #: If the header is actually available but just malformed it
         #: might be stored here.
-        self.header: _t_opt_any = header
+        self.header: t.Any | None = header
 
         #: If available, the error that indicates why the payload was
         #: not valid. This might be ``None``.
-        self.original_error: _t_opt_exc = original_error
+        self.original_error: Exception | None = original_error
 
 
 class BadPayload(BadData):
@@ -99,9 +98,9 @@ class BadPayload(BadData):
     .. versionadded:: 0.15
     """
 
-    def __init__(self, message: str, original_error: _t_opt_exc = None):
+    def __init__(self, message: str, original_error: Exception | None = None):
         super().__init__(message)
 
         #: If available, the error that indicates why the payload was
         #: not valid. This might be ``None``.
-        self.original_error: _t_opt_exc = original_error
+        self.original_error: Exception | None = original_error

+ 163 - 52
contrib/python/itsdangerous/py3/itsdangerous/serializer.py

@@ -1,5 +1,8 @@
+from __future__ import annotations
+
+import collections.abc as cabc
 import json
-import typing as _t
+import typing as t
 
 from .encoding import want_bytes
 from .exc import BadPayload
@@ -7,22 +10,36 @@ from .exc import BadSignature
 from .signer import _make_keys_list
 from .signer import Signer
 
-_t_str_bytes = _t.Union[str, bytes]
-_t_opt_str_bytes = _t.Optional[_t_str_bytes]
-_t_kwargs = _t.Dict[str, _t.Any]
-_t_opt_kwargs = _t.Optional[_t_kwargs]
-_t_signer = _t.Type[Signer]
-_t_fallbacks = _t.List[_t.Union[_t_kwargs, _t.Tuple[_t_signer, _t_kwargs], _t_signer]]
-_t_load_unsafe = _t.Tuple[bool, _t.Any]
-_t_secret_key = _t.Union[_t.Iterable[_t_str_bytes], _t_str_bytes]
+if t.TYPE_CHECKING:
+    import typing_extensions as te
+
+    # This should be either be str or bytes. To avoid having to specify the
+    # bound type, it falls back to a union if structural matching fails.
+    _TSerialized = te.TypeVar(
+        "_TSerialized", bound=t.Union[str, bytes], default=t.Union[str, bytes]
+    )
+else:
+    # Still available at runtime on Python < 3.13, but without the default.
+    _TSerialized = t.TypeVar("_TSerialized", bound=t.Union[str, bytes])
+
 
+class _PDataSerializer(t.Protocol[_TSerialized]):
+    def loads(self, payload: _TSerialized, /) -> t.Any: ...
+    # A signature with additional arguments is not handled correctly by type
+    # checkers right now, so an overload is used below for serializers that
+    # don't match this strict protocol.
+    def dumps(self, obj: t.Any, /) -> _TSerialized: ...
 
-def is_text_serializer(serializer: _t.Any) -> bool:
+
+# Use TypeIs once it's available in typing_extensions or 3.13.
+def is_text_serializer(
+    serializer: _PDataSerializer[t.Any],
+) -> te.TypeGuard[_PDataSerializer[str]]:
     """Checks whether a serializer generates text or binary."""
     return isinstance(serializer.dumps({}), str)
 
 
-class Serializer:
+class Serializer(t.Generic[_TSerialized]):
     """A serializer wraps a :class:`~itsdangerous.signer.Signer` to
     enable serializing and securely signing data other than bytes. It
     can unsign to verify that the data hasn't been changed.
@@ -77,31 +94,120 @@ class Serializer:
     #: The default serialization module to use to serialize data to a
     #: string internally. The default is :mod:`json`, but can be changed
     #: to any object that provides ``dumps`` and ``loads`` methods.
-    default_serializer: _t.Any = json
+    default_serializer: _PDataSerializer[t.Any] = json
 
     #: The default ``Signer`` class to instantiate when signing data.
     #: The default is :class:`itsdangerous.signer.Signer`.
-    default_signer: _t_signer = Signer
+    default_signer: type[Signer] = Signer
 
     #: The default fallback signers to try when unsigning fails.
-    default_fallback_signers: _t_fallbacks = []
+    default_fallback_signers: list[
+        dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+    ] = []
+
+    # Serializer[str] if no data serializer is provided, or if it returns str.
+    @t.overload
+    def __init__(
+        self: Serializer[str],
+        secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+        salt: str | bytes | None = b"itsdangerous",
+        serializer: None | _PDataSerializer[str] = None,
+        serializer_kwargs: dict[str, t.Any] | None = None,
+        signer: type[Signer] | None = None,
+        signer_kwargs: dict[str, t.Any] | None = None,
+        fallback_signers: list[
+            dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+        ]
+        | None = None,
+    ): ...
+
+    # Serializer[bytes] with a bytes data serializer positional argument.
+    @t.overload
+    def __init__(
+        self: Serializer[bytes],
+        secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+        salt: str | bytes | None,
+        serializer: _PDataSerializer[bytes],
+        serializer_kwargs: dict[str, t.Any] | None = None,
+        signer: type[Signer] | None = None,
+        signer_kwargs: dict[str, t.Any] | None = None,
+        fallback_signers: list[
+            dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+        ]
+        | None = None,
+    ): ...
+
+    # Serializer[bytes] with a bytes data serializer keyword argument.
+    @t.overload
+    def __init__(
+        self: Serializer[bytes],
+        secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+        salt: str | bytes | None = b"itsdangerous",
+        *,
+        serializer: _PDataSerializer[bytes],
+        serializer_kwargs: dict[str, t.Any] | None = None,
+        signer: type[Signer] | None = None,
+        signer_kwargs: dict[str, t.Any] | None = None,
+        fallback_signers: list[
+            dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+        ]
+        | None = None,
+    ): ...
+
+    # Fall back with a positional argument. If the strict signature of
+    # _PDataSerializer doesn't match, fall back to a union, requiring the user
+    # to specify the type.
+    @t.overload
+    def __init__(
+        self,
+        secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+        salt: str | bytes | None,
+        serializer: t.Any,
+        serializer_kwargs: dict[str, t.Any] | None = None,
+        signer: type[Signer] | None = None,
+        signer_kwargs: dict[str, t.Any] | None = None,
+        fallback_signers: list[
+            dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+        ]
+        | None = None,
+    ): ...
+
+    # Fall back with a keyword argument.
+    @t.overload
+    def __init__(
+        self,
+        secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+        salt: str | bytes | None = b"itsdangerous",
+        *,
+        serializer: t.Any,
+        serializer_kwargs: dict[str, t.Any] | None = None,
+        signer: type[Signer] | None = None,
+        signer_kwargs: dict[str, t.Any] | None = None,
+        fallback_signers: list[
+            dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+        ]
+        | None = None,
+    ): ...
 
     def __init__(
         self,
-        secret_key: _t_secret_key,
-        salt: _t_opt_str_bytes = b"itsdangerous",
-        serializer: _t.Any = None,
-        serializer_kwargs: _t_opt_kwargs = None,
-        signer: _t.Optional[_t_signer] = None,
-        signer_kwargs: _t_opt_kwargs = None,
-        fallback_signers: _t.Optional[_t_fallbacks] = None,
+        secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+        salt: str | bytes | None = b"itsdangerous",
+        serializer: t.Any | None = None,
+        serializer_kwargs: dict[str, t.Any] | None = None,
+        signer: type[Signer] | None = None,
+        signer_kwargs: dict[str, t.Any] | None = None,
+        fallback_signers: list[
+            dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+        ]
+        | None = None,
     ):
         #: The list of secret keys to try for verifying signatures, from
         #: oldest to newest. The newest (last) key is used for signing.
         #:
         #: This allows a key rotation system to keep a list of allowed
         #: keys and remove expired ones.
-        self.secret_keys: _t.List[bytes] = _make_keys_list(secret_key)
+        self.secret_keys: list[bytes] = _make_keys_list(secret_key)
 
         if salt is not None:
             salt = want_bytes(salt)
@@ -112,20 +218,22 @@ class Serializer:
         if serializer is None:
             serializer = self.default_serializer
 
-        self.serializer: _t.Any = serializer
+        self.serializer: _PDataSerializer[_TSerialized] = serializer
         self.is_text_serializer: bool = is_text_serializer(serializer)
 
         if signer is None:
             signer = self.default_signer
 
-        self.signer: _t_signer = signer
-        self.signer_kwargs: _t_kwargs = signer_kwargs or {}
+        self.signer: type[Signer] = signer
+        self.signer_kwargs: dict[str, t.Any] = signer_kwargs or {}
 
         if fallback_signers is None:
-            fallback_signers = list(self.default_fallback_signers or ())
+            fallback_signers = list(self.default_fallback_signers)
 
-        self.fallback_signers: _t_fallbacks = fallback_signers
-        self.serializer_kwargs: _t_kwargs = serializer_kwargs or {}
+        self.fallback_signers: list[
+            dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer]
+        ] = fallback_signers
+        self.serializer_kwargs: dict[str, t.Any] = serializer_kwargs or {}
 
     @property
     def secret_key(self) -> bytes:
@@ -135,8 +243,8 @@ class Serializer:
         return self.secret_keys[-1]
 
     def load_payload(
-        self, payload: bytes, serializer: _t.Optional[_t.Any] = None
-    ) -> _t.Any:
+        self, payload: bytes, serializer: _PDataSerializer[t.Any] | None = None
+    ) -> t.Any:
         """Loads the encoded object. This function raises
         :class:`.BadPayload` if the payload is not valid. The
         ``serializer`` parameter can be used to override the serializer
@@ -144,16 +252,17 @@ class Serializer:
         bytes.
         """
         if serializer is None:
-            serializer = self.serializer
+            use_serializer = self.serializer
             is_text = self.is_text_serializer
         else:
+            use_serializer = serializer
             is_text = is_text_serializer(serializer)
 
         try:
             if is_text:
-                return serializer.loads(payload.decode("utf-8"))
+                return use_serializer.loads(payload.decode("utf-8"))  # type: ignore[arg-type]
 
-            return serializer.loads(payload)
+            return use_serializer.loads(payload)  # type: ignore[arg-type]
         except Exception as e:
             raise BadPayload(
                 "Could not load the payload because an exception"
@@ -161,14 +270,14 @@ class Serializer:
                 original_error=e,
             ) from e
 
-    def dump_payload(self, obj: _t.Any) -> bytes:
+    def dump_payload(self, obj: t.Any) -> bytes:
         """Dumps the encoded object. The return value is always bytes.
         If the internal serializer returns text, the value will be
         encoded as UTF-8.
         """
         return want_bytes(self.serializer.dumps(obj, **self.serializer_kwargs))
 
-    def make_signer(self, salt: _t_opt_str_bytes = None) -> Signer:
+    def make_signer(self, salt: str | bytes | None = None) -> Signer:
         """Creates a new instance of the signer to be used. The default
         implementation uses the :class:`.Signer` base class.
         """
@@ -177,7 +286,7 @@ class Serializer:
 
         return self.signer(self.secret_keys, salt=salt, **self.signer_kwargs)
 
-    def iter_unsigners(self, salt: _t_opt_str_bytes = None) -> _t.Iterator[Signer]:
+    def iter_unsigners(self, salt: str | bytes | None = None) -> cabc.Iterator[Signer]:
         """Iterates over all signers to be tried for unsigning. Starts
         with the configured signer, then constructs each signer
         specified in ``fallback_signers``.
@@ -199,7 +308,7 @@ class Serializer:
             for secret_key in self.secret_keys:
                 yield fallback(secret_key, salt=salt, **kwargs)
 
-    def dumps(self, obj: _t.Any, salt: _t_opt_str_bytes = None) -> _t_str_bytes:
+    def dumps(self, obj: t.Any, salt: str | bytes | None = None) -> _TSerialized:
         """Returns a signed string serialized with the internal
         serializer. The return value can be either a byte or unicode
         string depending on the format of the internal serializer.
@@ -208,19 +317,19 @@ class Serializer:
         rv = self.make_signer(salt).sign(payload)
 
         if self.is_text_serializer:
-            return rv.decode("utf-8")
+            return rv.decode("utf-8")  # type: ignore[return-value]
 
-        return rv
+        return rv  # type: ignore[return-value]
 
-    def dump(self, obj: _t.Any, f: _t.IO, salt: _t_opt_str_bytes = None) -> None:
+    def dump(self, obj: t.Any, f: t.IO[t.Any], salt: str | bytes | None = None) -> None:
         """Like :meth:`dumps` but dumps into a file. The file handle has
         to be compatible with what the internal serializer expects.
         """
         f.write(self.dumps(obj, salt))
 
     def loads(
-        self, s: _t_str_bytes, salt: _t_opt_str_bytes = None, **kwargs: _t.Any
-    ) -> _t.Any:
+        self, s: str | bytes, salt: str | bytes | None = None, **kwargs: t.Any
+    ) -> t.Any:
         """Reverse of :meth:`dumps`. Raises :exc:`.BadSignature` if the
         signature validation fails.
         """
@@ -233,15 +342,15 @@ class Serializer:
             except BadSignature as err:
                 last_exception = err
 
-        raise _t.cast(BadSignature, last_exception)
+        raise t.cast(BadSignature, last_exception)
 
-    def load(self, f: _t.IO, salt: _t_opt_str_bytes = None) -> _t.Any:
+    def load(self, f: t.IO[t.Any], salt: str | bytes | None = None) -> t.Any:
         """Like :meth:`loads` but loads from a file."""
         return self.loads(f.read(), salt)
 
     def loads_unsafe(
-        self, s: _t_str_bytes, salt: _t_opt_str_bytes = None
-    ) -> _t_load_unsafe:
+        self, s: str | bytes, salt: str | bytes | None = None
+    ) -> tuple[bool, t.Any]:
         """Like :meth:`loads` but without verifying the signature. This
         is potentially very dangerous to use depending on how your
         serializer works. The return value is ``(signature_valid,
@@ -259,11 +368,11 @@ class Serializer:
 
     def _loads_unsafe_impl(
         self,
-        s: _t_str_bytes,
-        salt: _t_opt_str_bytes,
-        load_kwargs: _t_opt_kwargs = None,
-        load_payload_kwargs: _t_opt_kwargs = None,
-    ) -> _t_load_unsafe:
+        s: str | bytes,
+        salt: str | bytes | None,
+        load_kwargs: dict[str, t.Any] | None = None,
+        load_payload_kwargs: dict[str, t.Any] | None = None,
+    ) -> tuple[bool, t.Any]:
         """Low level helper function to implement :meth:`loads_unsafe`
         in serializer subclasses.
         """
@@ -287,7 +396,9 @@ class Serializer:
             except BadPayload:
                 return False, None
 
-    def load_unsafe(self, f: _t.IO, salt: _t_opt_str_bytes = None) -> _t_load_unsafe:
+    def load_unsafe(
+        self, f: t.IO[t.Any], salt: str | bytes | None = None
+    ) -> tuple[bool, t.Any]:
         """Like :meth:`loads_unsafe` but loads from a file.
 
         .. versionadded:: 0.15

+ 36 - 27
contrib/python/itsdangerous/py3/itsdangerous/signer.py

@@ -1,6 +1,9 @@
+from __future__ import annotations
+
+import collections.abc as cabc
 import hashlib
 import hmac
-import typing as _t
+import typing as t
 
 from .encoding import _base64_alphabet
 from .encoding import base64_decode
@@ -8,10 +11,6 @@ from .encoding import base64_encode
 from .encoding import want_bytes
 from .exc import BadSignature
 
-_t_str_bytes = _t.Union[str, bytes]
-_t_opt_str_bytes = _t.Optional[_t_str_bytes]
-_t_secret_key = _t.Union[_t.Iterable[_t_str_bytes], _t_str_bytes]
-
 
 class SigningAlgorithm:
     """Subclasses must implement :meth:`get_signature` to provide
@@ -38,30 +37,40 @@ class NoneAlgorithm(SigningAlgorithm):
         return b""
 
 
+def _lazy_sha1(string: bytes = b"") -> t.Any:
+    """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include
+    SHA-1, in which case the import and use as a default would fail before the
+    developer can configure something else.
+    """
+    return hashlib.sha1(string)
+
+
 class HMACAlgorithm(SigningAlgorithm):
     """Provides signature generation using HMACs."""
 
     #: The digest method to use with the MAC algorithm. This defaults to
     #: SHA1, but can be changed to any other function in the hashlib
     #: module.
-    default_digest_method: _t.Any = staticmethod(hashlib.sha1)
+    default_digest_method: t.Any = staticmethod(_lazy_sha1)
 
-    def __init__(self, digest_method: _t.Any = None):
+    def __init__(self, digest_method: t.Any = None):
         if digest_method is None:
             digest_method = self.default_digest_method
 
-        self.digest_method: _t.Any = digest_method
+        self.digest_method: t.Any = digest_method
 
     def get_signature(self, key: bytes, value: bytes) -> bytes:
         mac = hmac.new(key, msg=value, digestmod=self.digest_method)
         return mac.digest()
 
 
-def _make_keys_list(secret_key: _t_secret_key) -> _t.List[bytes]:
+def _make_keys_list(
+    secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+) -> list[bytes]:
     if isinstance(secret_key, (str, bytes)):
         return [want_bytes(secret_key)]
 
-    return [want_bytes(s) for s in secret_key]
+    return [want_bytes(s) for s in secret_key]  # pyright: ignore
 
 
 class Signer:
@@ -108,7 +117,7 @@ class Signer:
     #: doesn't apply when used intermediately in HMAC.
     #:
     #: .. versionadded:: 0.14
-    default_digest_method: _t.Any = staticmethod(hashlib.sha1)
+    default_digest_method: t.Any = staticmethod(_lazy_sha1)
 
     #: The default scheme to use to derive the signing key from the
     #: secret key and salt. The default is ``django-concat``. Possible
@@ -119,19 +128,19 @@ class Signer:
 
     def __init__(
         self,
-        secret_key: _t_secret_key,
-        salt: _t_opt_str_bytes = b"itsdangerous.Signer",
-        sep: _t_str_bytes = b".",
-        key_derivation: _t.Optional[str] = None,
-        digest_method: _t.Optional[_t.Any] = None,
-        algorithm: _t.Optional[SigningAlgorithm] = None,
+        secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+        salt: str | bytes | None = b"itsdangerous.Signer",
+        sep: str | bytes = b".",
+        key_derivation: str | None = None,
+        digest_method: t.Any | None = None,
+        algorithm: SigningAlgorithm | None = None,
     ):
         #: The list of secret keys to try for verifying signatures, from
         #: oldest to newest. The newest (last) key is used for signing.
         #:
         #: This allows a key rotation system to keep a list of allowed
         #: keys and remove expired ones.
-        self.secret_keys: _t.List[bytes] = _make_keys_list(secret_key)
+        self.secret_keys: list[bytes] = _make_keys_list(secret_key)
         self.sep: bytes = want_bytes(sep)
 
         if self.sep in _base64_alphabet:
@@ -156,7 +165,7 @@ class Signer:
         if digest_method is None:
             digest_method = self.default_digest_method
 
-        self.digest_method: _t.Any = digest_method
+        self.digest_method: t.Any = digest_method
 
         if algorithm is None:
             algorithm = HMACAlgorithm(self.digest_method)
@@ -170,7 +179,7 @@ class Signer:
         """
         return self.secret_keys[-1]
 
-    def derive_key(self, secret_key: _t_opt_str_bytes = None) -> bytes:
+    def derive_key(self, secret_key: str | bytes | None = None) -> bytes:
         """This method is called to derive the key. The default key
         derivation choices can be overridden here. Key derivation is not
         intended to be used as a security method to make a complex key
@@ -189,9 +198,9 @@ class Signer:
             secret_key = want_bytes(secret_key)
 
         if self.key_derivation == "concat":
-            return _t.cast(bytes, self.digest_method(self.salt + secret_key).digest())
+            return t.cast(bytes, self.digest_method(self.salt + secret_key).digest())
         elif self.key_derivation == "django-concat":
-            return _t.cast(
+            return t.cast(
                 bytes, self.digest_method(self.salt + b"signer" + secret_key).digest()
             )
         elif self.key_derivation == "hmac":
@@ -203,19 +212,19 @@ class Signer:
         else:
             raise TypeError("Unknown key derivation method")
 
-    def get_signature(self, value: _t_str_bytes) -> bytes:
+    def get_signature(self, value: str | bytes) -> bytes:
         """Returns the signature for the given value."""
         value = want_bytes(value)
         key = self.derive_key()
         sig = self.algorithm.get_signature(key, value)
         return base64_encode(sig)
 
-    def sign(self, value: _t_str_bytes) -> bytes:
+    def sign(self, value: str | bytes) -> bytes:
         """Signs the given string."""
         value = want_bytes(value)
         return value + self.sep + self.get_signature(value)
 
-    def verify_signature(self, value: _t_str_bytes, sig: _t_str_bytes) -> bool:
+    def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool:
         """Verifies the signature for the given value."""
         try:
             sig = base64_decode(sig)
@@ -232,7 +241,7 @@ class Signer:
 
         return False
 
-    def unsign(self, signed_value: _t_str_bytes) -> bytes:
+    def unsign(self, signed_value: str | bytes) -> bytes:
         """Unsigns the given string."""
         signed_value = want_bytes(signed_value)
 
@@ -246,7 +255,7 @@ class Signer:
 
         raise BadSignature(f"Signature {sig!r} does not match", payload=value)
 
-    def validate(self, signed_value: _t_str_bytes) -> bool:
+    def validate(self, signed_value: str | bytes) -> bool:
         """Only validates the given signed value. Returns ``True`` if
         the signature exists and is valid.
         """

Some files were not shown because too many files changed in this diff