Check at runtime if deprecated keyword arguments are used
Marco Ricci

Marco Ricci commited on 2025-01-21 21:02:31
Zeige 1 geänderte Dateien mit 21 Einfügungen und 2 Löschungen.


The `warnings.deprecated` decorator sadly does not do anything at
runtime if merely one of several overloads is deprecated.  And it seems
to fail even if the deprecated signature is actively used; see
`_types.is_vault_config`.  Implement a known working solution to check
if the deprecated keyword argument was supplied.

(No tests yet, so excluded from coverage.)
... ...
@@ -11,6 +11,7 @@ import enum
11 11
 import json
12 12
 import math
13 13
 import string
14
+import warnings
14 15
 from typing import TYPE_CHECKING, Generic, TypeVar
15 16
 
16 17
 from typing_extensions import (
... ...
@@ -19,6 +20,7 @@ from typing_extensions import (
19 20
     NotRequired,
20 21
     TypedDict,
21 22
     deprecated,
23
+    get_overloads,
22 24
     overload,
23 25
 )
24 26
 
... ...
@@ -41,6 +43,14 @@ __all__ = (
41 43
 )
42 44
 
43 45
 
46
+class _Omitted:  # pragma: no cover
47
+    def __bool__(self) -> bool:
48
+        return False
49
+
50
+    def __repr__(self) -> str:
51
+        return '...'
52
+
53
+
44 54
 class VaultConfigGlobalSettings(TypedDict, total=False):
45 55
     r"""Configuration for vault: global settings.
46 56
 
... ...
@@ -244,7 +254,7 @@ def validate_vault_config(  # noqa: C901,PLR0912
244 254
     /,
245 255
     *,
246 256
     allow_unknown_settings: bool = False,
247
-    allow_derivepassphrase_extensions: bool = False,
257
+    allow_derivepassphrase_extensions: bool = _Omitted(),  # type: ignore[assignment]
248 258
 ) -> None:
249 259
     """Check that `obj` is a valid vault config.
250 260
 
... ...
@@ -271,6 +281,16 @@ def validate_vault_config(  # noqa: C901,PLR0912
271 281
             specified `derivepassphrase` extensions.
272 282
 
273 283
     """
284
+    # TODO(the-13th-letter): Add tests that trigger the deprecation warning,
285
+    # then include this in coverage.
286
+    if not isinstance(
287
+        allow_derivepassphrase_extensions, _Omitted
288
+    ):  # pragma: no cover
289
+        warnings.warn(
290
+            get_overloads(validate_vault_config)[0].__deprecated__,  # type: ignore[attr-defined]
291
+            DeprecationWarning,
292
+            stacklevel=2,
293
+        )
274 294
     err_obj_not_a_dict = 'vault config is not a dict'
275 295
     err_non_str_service_name = (
276 296
         'vault config contains non-string service name {!r}'
... ...
@@ -377,7 +397,6 @@ def is_vault_config(obj: Any) -> TypeIs[VaultConfig]:  # noqa: ANN401
377 397
         validate_vault_config(
378 398
             obj,
379 399
             allow_unknown_settings=True,
380
-            allow_derivepassphrase_extensions=True,
381 400
         )
382 401
     except (TypeError, ValueError) as exc:
383 402
         if 'vault config ' not in str(exc):  # pragma: no cover
384 403