Fix typing of the dummy vault configuration settings in the constructor
Marco Ricci

Marco Ricci commited on 2025-11-27 21:59:27
Zeige 3 geänderte Dateien mit 46 Einfügungen und 23 Löschungen.


One of our tests, a "manual sanity-check" kind of test, tries to use the
`tests.data.DUMMY_CONFIG_SETTINGS` symbol as keyword arguments in the
`vault.Vault` constructor.  This appeared to work with older `mypy`
versions, but now raises an error about extra keys in the symbol that
the constructor does not accept as keyword arguments.  (Because the
dummy config settings are actually typed as vault config "services"
settings, which *do* allow more settings than the constructor uses as
arguments.)

So, we now arrange for a second symbol with effectively the same
contents as the dummy config settings, but explicitly typed as
constructor arguments, to be used in the "manual sanity-check" test
instead.

(Implementation-wise, we introduce a new base type
`_types.VaultConstructorArgs`, and let
`_types.VaultConfigServicesSettings` inherit from that.  This is easier
than attempting to constrain the latter type after the fact.  We
introduce the new base type directly in the `_types` module, even though
it is otherwise only used in the tests, because the derived type (from
the `_types` module) also needs access during construction.)
... ...
@@ -52,19 +52,13 @@ class _Omitted:
52 52
         return "..."
53 53
 
54 54
 
55
-class VaultConfigGlobalSettings(TypedDict, total=False):
56
-    r"""Configuration for vault: global settings.
55
+class VaultConstructorArgs(TypedDict, total=False):
56
+    r"""Common, optional arguments for the vault constructor.
57
+
58
+    (Also doubles as a base class for the vault configuration global
59
+    settings.)
57 60
 
58 61
     Attributes:
59
-        key:
60
-            The base64-encoded ssh public key to use, overriding the
61
-            master passphrase. Optional.
62
-        phrase:
63
-            The master passphrase. Optional.
64
-        unicode_normalization_form:
65
-            The preferred Unicode normalization form; we warn the user
66
-            if textual passphrases do not match their normalized forms.
67
-            Optional, and a `derivepassphrase` extension.
68 62
         length:
69 63
             Desired passphrase length.
70 64
         repeat:
... ...
@@ -89,15 +83,6 @@ class VaultConfigGlobalSettings(TypedDict, total=False):
89 83
             ASCII printable characters (except backquote).
90 84
 
91 85
     """
92
-
93
-    key: NotRequired[str]
94
-    """"""
95
-    phrase: NotRequired[str]
96
-    """"""
97
-    unicode_normalization_form: NotRequired[
98
-        Literal["NFC", "NFD", "NFKC", "NFKD"]
99
-    ]
100
-    """"""
101 86
     length: NotRequired[int]
102 87
     """"""
103 88
     repeat: NotRequired[int]
... ...
@@ -116,6 +101,32 @@ class VaultConfigGlobalSettings(TypedDict, total=False):
116 101
     """"""
117 102
 
118 103
 
104
+class VaultConfigGlobalSettings(VaultConstructorArgs, total=False):
105
+    r"""Configuration for vault: global settings.
106
+
107
+    Attributes:
108
+        key:
109
+            The base64-encoded ssh public key to use, overriding the
110
+            master passphrase. Optional.
111
+        phrase:
112
+            The master passphrase. Optional.
113
+        unicode_normalization_form:
114
+            The preferred Unicode normalization form; we warn the user
115
+            if textual passphrases do not match their normalized forms.
116
+            Optional, and a `derivepassphrase` extension.
117
+
118
+    """
119
+
120
+    key: NotRequired[str]
121
+    """"""
122
+    phrase: NotRequired[str]
123
+    """"""
124
+    unicode_normalization_form: NotRequired[
125
+        Literal["NFC", "NFD", "NFKC", "NFKD"]
126
+    ]
127
+    """"""
128
+
129
+
119 130
 class VaultConfigServicesSettings(VaultConfigGlobalSettings, total=False):
120 131
     r"""Configuration for vault: services settings.
121 132
 
... ...
@@ -1356,7 +1356,9 @@ DUMMY_KEY3 = SUPPORTED_KEYS["ed448"].public_key_data
1356 1356
 """A third supported SSH test key (in wire format)."""
1357 1357
 DUMMY_KEY3_B64 = base64.standard_b64encode(DUMMY_KEY3).decode("ASCII")
1358 1358
 """A third supported SSH test key (in `authorized_keys` format)."""
1359
-DUMMY_CONFIG_SETTINGS = cast("_types.VaultConfigServicesSettings", {
1359
+DUMMY_CONFIG_SETTINGS_AS_CONSTRUCTOR_ARGS = cast(
1360
+    "_types.VaultConstructorArgs",
1361
+    {
1360 1362
         "length": 10,
1361 1363
         "upper": 1,
1362 1364
         "lower": 1,
... ...
@@ -1365,7 +1367,13 @@ DUMMY_CONFIG_SETTINGS = cast("_types.VaultConfigServicesSettings", {
1365 1367
         "space": 1,
1366 1368
         "dash": 1,
1367 1369
         "symbol": 1,
1368
-})
1370
+    },
1371
+)
1372
+"""Sample vault settings, as constructor args."""
1373
+DUMMY_CONFIG_SETTINGS = cast(
1374
+    "_types.VaultConfigServicesSettings",
1375
+    DUMMY_CONFIG_SETTINGS_AS_CONSTRUCTOR_ARGS,
1376
+)
1369 1377
 """Sample vault settings."""
1370 1378
 DUMMY_RESULT_PASSPHRASE = b".2V_QJkd o"
1371 1379
 """
... ...
@@ -48,6 +48,9 @@ if TYPE_CHECKING:
48 48
 DUMMY_SERVICE = data.DUMMY_SERVICE
49 49
 DUMMY_PASSPHRASE = data.DUMMY_PASSPHRASE
50 50
 DUMMY_CONFIG_SETTINGS = data.DUMMY_CONFIG_SETTINGS
51
+DUMMY_CONFIG_SETTINGS_AS_CONSTRUCTOR_ARGS = (
52
+    data.DUMMY_CONFIG_SETTINGS_AS_CONSTRUCTOR_ARGS
53
+)
51 54
 DUMMY_RESULT_PASSPHRASE = data.DUMMY_RESULT_PASSPHRASE
52 55
 DUMMY_RESULT_KEY1 = data.DUMMY_RESULT_KEY1
53 56
 DUMMY_PHRASE_FROM_KEY1_RAW = data.DUMMY_PHRASE_FROM_KEY1_RAW
... ...
@@ -1344,7 +1347,8 @@ class TestMisc:
1344 1347
         """The dummy service, key and config settings are consistent."""
1345 1348
         assert (
1346 1349
             vault.Vault(
1347
-                phrase=DUMMY_PHRASE_FROM_KEY1, **DUMMY_CONFIG_SETTINGS
1350
+                phrase=DUMMY_PHRASE_FROM_KEY1,
1351
+                **DUMMY_CONFIG_SETTINGS_AS_CONSTRUCTOR_ARGS,
1348 1352
             ).generate(DUMMY_SERVICE)
1349 1353
             == DUMMY_RESULT_KEY1
1350 1354
         )
1351 1355