Change the code style to use double quotes for strings
Marco Ricci

Marco Ricci commited on 2025-08-05 21:11:03
Zeige 29 geänderte Dateien mit 4479 Einfügungen und 4479 Löschungen.


As is standard in Python auto-formatting (Black, Ruff), we now use
double quotes for strings where possible, reverting to single quotes
only where necessary.

(The numerous code changes in `scripts/`, `src/` and `tests/` stem from
the auto-formatter re-adjusting the quotes.)

Background: I originally started out as a Perl programmer, and in Perl,
single quotes signify literal strings without any interpolation
whatsoever, and double quotes signify strings with interpolation and
escape sequences. In those languages, the choice of string quotes makes
a subtle difference. In Python, the choice of quote character does not
matter, so while there is no reason to prefer one over the other, the
inertia of being used to "single means literal, double means
interpolated" meant that I basically kept my existing style of quoting.

Python, meanwhile, although careful not to *prescribe* one quote
character or the other (see PEP 8), uses double quotes by default in
`str.__repr__` and in docstrings (see PEP 257). The Black
auto-formatter, which Ruff is modeled on, also defaults to double
quotes, arguing in its style guide that (among other things) the empty
string with double quotes unambiguously looks like an empty string,
regardless of fonts and syntax highlighting, but the empty string with
single quotes not necessarily: it may look like a single double quote
character.

More importantly, auto-formatters are specifically designed to make
these (essentially arbitrary) decisions about code formatting for you,
in the name of a uniform code style such that a reader can focus on the
code *content*, not the code *presentation*.  The concrete set of
arbitrary decisions is essentially secondary, but the Black team (and
the Ruff team too) have a pretty good track record of keeping the
resulting code readable and sensibly diffable, and this styling decision
has long been established by Black and "blackened" code "in the wild"
(and thus tested), so I have no reason to object to this particular
arbitrary choice.  Furthermore, there's no need to manually adjust all
quote characters, or even to pay much attention during code authoring to
the quote characters; the auto-formatting pass will take care of
harmonizing them for you.

Given these reasons, continuing to insist on single-quoted strings, in
Python, out of some vague sense of familiarity with *other* programming
languages where quote characters have different meanings, seems rather
untenable to me.
... ...
@@ -187,8 +187,8 @@ first_value = '1'
187 187
 
188 188
 [[tool.bumpversion.files]]
189 189
 filename = 'src/derivepassphrase/__init__.py'
190
-search = "^ *__version__ *= *'{current_version}'"
191
-replace = "__version__ = '{new_version}'"
190
+search = '^ *__version__ *= *"{current_version}"'
191
+replace = '__version__ = "{new_version}"'
192 192
 regex = true
193 193
 
194 194
 [[tool.bumpversion.files]]
... ...
@@ -425,7 +425,7 @@ src = ["src"]
425 425
 docstring-code-format = true
426 426
 docstring-code-line-length = "dynamic"
427 427
 preview = true
428
-quote-style = 'single'
428
+quote-style = "double"
429 429
 
430 430
 [tool.ruff.lint]
431 431
 ignore = [
... ...
@@ -12,14 +12,14 @@ import re
12 12
 import sys
13 13
 from typing import TYPE_CHECKING, Literal, NewType, cast
14 14
 
15
-sys.path.append(str(pathlib.Path(sys.argv[0]).resolve().parent.parent / 'src'))
15
+sys.path.append(str(pathlib.Path(sys.argv[0]).resolve().parent.parent / "src"))
16 16
 from derivepassphrase._internals import cli_messages  # noqa: PLC2701
17 17
 
18 18
 if TYPE_CHECKING:
19 19
     from collections.abc import Iterator
20 20
 
21
-    EnumName = NewType('EnumName', str)
22
-    DiagnosticText = NewType('DiagnosticText', str)
21
+    EnumName = NewType("EnumName", str)
22
+    DiagnosticText = NewType("DiagnosticText", str)
23 23
 
24 24
 known_errors = cli_messages.ErrMsgTemplate.__members__
25 25
 known_warnings = cli_messages.WarnMsgTemplate.__members__
... ...
@@ -28,17 +28,17 @@ known_warnings = cli_messages.WarnMsgTemplate.__members__
28 28
 def _replace_known_metavars(string: str) -> str:
29 29
     return (
30 30
         string.replace(
31
-            '{service_metavar!s}',
31
+            "{service_metavar!s}",
32 32
             cli_messages.Label.VAULT_METAVAR_SERVICE.value.singular,
33 33
         )
34 34
         .replace(
35
-            '{service_metavar}',
35
+            "{service_metavar}",
36 36
             cli_messages.Label.VAULT_METAVAR_SERVICE.value.singular,
37 37
         )
38
-        .replace('{PROG_NAME!s}', cli_messages.PROG_NAME)
39
-        .replace('{PROG_NAME}', cli_messages.PROG_NAME)
40
-        .replace('{settings_type!s}', 'global/service-specific settings')
41
-        .replace('{settings_type}', 'global/service-specific settings')
38
+        .replace("{PROG_NAME!s}", cli_messages.PROG_NAME)
39
+        .replace("{PROG_NAME}", cli_messages.PROG_NAME)
40
+        .replace("{settings_type!s}", "global/service-specific settings")
41
+        .replace("{settings_type}", "global/service-specific settings")
42 42
     )
43 43
 
44 44
 
... ...
@@ -50,20 +50,20 @@ def _replace_known_metavars(string: str) -> str:
50 50
 def _mismatches_text(
51 51
     pattern: re.Pattern[str],
52 52
     enum_name: EnumName,
53
-    name_type: Literal['warning', 'error'],
53
+    name_type: Literal["warning", "error"],
54 54
 ) -> bool:
55
-    while '.' in enum_name:
56
-        enum_name = cast('EnumName', enum_name.partition('.')[2])
55
+    while "." in enum_name:
56
+        enum_name = cast("EnumName", enum_name.partition(".")[2])
57 57
     try:
58 58
         enum_value = (
59 59
             known_errors[enum_name].value
60
-            if name_type == 'error'
60
+            if name_type == "error"
61 61
             else known_warnings[enum_name].value
62 62
         )
63 63
     except KeyError:
64 64
         # No text, so no mismatch.
65 65
         return False
66
-    texts = {enum_value.singular, enum_value.plural} - {''}
66
+    texts = {enum_value.singular, enum_value.plural} - {""}
67 67
     return not all(pattern.match(_replace_known_metavars(t)) for t in texts)
68 68
 
69 69
 
... ...
@@ -72,120 +72,120 @@ def _entries_from_text(
72 72
     enum_names: set[EnumName],
73 73
 ) -> Iterator[
74 74
     tuple[
75
-        Literal['warning', 'error'],
75
+        Literal["warning", "error"],
76 76
         tuple[DiagnosticText, EnumName],
77 77
     ]
78 78
 ]:
79 79
     assert text not in manpage_documented_warnings
80 80
     assert text not in manpage_documented_errors
81 81
     pattern_parts = [
82
-        '.*' if part == '%s' else re.escape(part)
83
-        for part in re.split(r'(%s)', text)
82
+        ".*" if part == "%s" else re.escape(part)
83
+        for part in re.split(r"(%s)", text)
84 84
     ]
85
-    pattern = re.compile(''.join(pattern_parts))
85
+    pattern = re.compile("".join(pattern_parts))
86 86
     for name in enum_names:
87
-        _class_name, dot, enum_entry = name.partition('.')
88
-        assert dot == '.', f'Invalid enum name {name!r}'
89
-        assert '.' not in enum_entry, f'Unsupported enum name {name!r}'
90
-        if name.startswith('WarnMsgTemplate.'):
87
+        _class_name, dot, enum_entry = name.partition(".")
88
+        assert dot == ".", f"Invalid enum name {name!r}"
89
+        assert "." not in enum_entry, f"Unsupported enum name {name!r}"
90
+        if name.startswith("WarnMsgTemplate."):
91 91
             assert not _mismatches_text(
92
-                pattern, enum_name=name, name_type='warning'
92
+                pattern, enum_name=name, name_type="warning"
93 93
             ), (
94 94
                 f"Warning text for {name} doesn't match the manpage: "
95
-                f'{text!r} -> {pattern.pattern!r}'
95
+                f"{text!r} -> {pattern.pattern!r}"
96 96
             )
97
-            yield ('warning', (text, cast('EnumName', enum_entry)))
98
-        if name.startswith('ErrMsgTemplate.'):
97
+            yield ("warning", (text, cast("EnumName", enum_entry)))
98
+        if name.startswith("ErrMsgTemplate."):
99 99
             assert not _mismatches_text(
100
-                pattern, enum_name=name, name_type='error'
100
+                pattern, enum_name=name, name_type="error"
101 101
             ), (
102 102
                 f"Error text for {name} doesn't match the manpage: "
103
-                f'{text!r} -> {pattern.pattern!r}'
103
+                f"{text!r} -> {pattern.pattern!r}"
104 104
             )
105
-            yield ('error', (text, cast('EnumName', enum_entry)))
105
+            yield ("error", (text, cast("EnumName", enum_entry)))
106 106
 
107 107
 
108 108
 def _check_manpage(
109 109
     path: pathlib.Path,
110 110
 ) -> Iterator[
111 111
     tuple[
112
-        Literal['warning', 'error'],
112
+        Literal["warning", "error"],
113 113
         tuple[DiagnosticText, EnumName],
114 114
     ]
115 115
 ]:
116 116
     enum_names: set[EnumName] = set()
117 117
 
118
-    for line in path.read_text(encoding='UTF-8').splitlines(keepends=False):
119
-        if enum_names and line.startswith('.It '):
118
+    for line in path.read_text(encoding="UTF-8").splitlines(keepends=False):
119
+        if enum_names and line.startswith(".It "):
120 120
             # Some *roff escape sequences need to be undone.  This is not an
121 121
             # exhaustive list; new entries will be added based on the actual
122 122
             # manpages as the need arises.
123 123
             text = cast(
124
-                'DiagnosticText',
125
-                line.removeprefix('.It ').replace('"', '').replace(r'\-', '-'),
124
+                "DiagnosticText",
125
+                line.removeprefix(".It ").replace('"', "").replace(r"\-", "-"),
126 126
             )
127 127
             yield from _entries_from_text(text=text, enum_names=enum_names)
128 128
             enum_names.clear()
129
-        elif line.startswith(r'.\" Message-ID (mark only):'):
129
+        elif line.startswith(r".\" Message-ID (mark only):"):
130 130
             yield from _entries_from_mark_only(
131
-                cast('EnumName', line.split(None, 4)[4])
131
+                cast("EnumName", line.split(None, 4)[4])
132 132
             )
133
-        elif line.startswith(r'.\" Message-ID:'):
134
-            enum_names.add(cast('EnumName', line.split(None, 2)[2]))
133
+        elif line.startswith(r".\" Message-ID:"):
134
+            enum_names.add(cast("EnumName", line.split(None, 2)[2]))
135 135
 
136 136
 
137 137
 def _entries_from_mark_only(
138 138
     name: EnumName,
139 139
 ) -> Iterator[
140 140
     tuple[
141
-        Literal['warning', 'error'],
141
+        Literal["warning", "error"],
142 142
         tuple[DiagnosticText, EnumName],
143 143
     ]
144 144
 ]:
145
-    text = cast('DiagnosticText', '<mark only>')
146
-    _class_name, dot, enum_entry = name.partition('.')
147
-    assert dot == '.', f'Invalid enum name {name!r}'
148
-    assert '.' not in enum_entry, f'Unsupported enum name {name!r}'
149
-    if name.startswith('WarnMsgTemplate.'):
150
-        yield ('warning', (text, cast('EnumName', enum_entry)))
151
-    if name.startswith('ErrMsgTemplate.'):
152
-        yield ('error', (text, cast('EnumName', enum_entry)))
145
+    text = cast("DiagnosticText", "<mark only>")
146
+    _class_name, dot, enum_entry = name.partition(".")
147
+    assert dot == ".", f"Invalid enum name {name!r}"
148
+    assert "." not in enum_entry, f"Unsupported enum name {name!r}"
149
+    if name.startswith("WarnMsgTemplate."):
150
+        yield ("warning", (text, cast("EnumName", enum_entry)))
151
+    if name.startswith("ErrMsgTemplate."):
152
+        yield ("error", (text, cast("EnumName", enum_entry)))
153 153
 
154 154
 
155 155
 def _check_manpagedoc(
156 156
     path: pathlib.Path,
157 157
 ) -> Iterator[
158 158
     tuple[
159
-        Literal['warning', 'error'],
159
+        Literal["warning", "error"],
160 160
         tuple[DiagnosticText, EnumName],
161 161
     ]
162 162
 ]:
163 163
     enum_names: set[EnumName] = set()
164 164
 
165
-    for line in path.read_text(encoding='UTF-8').splitlines(keepends=False):
166
-        if enum_names and line.startswith(('??? failure ', '??? warning ')):
167
-            text = cast('DiagnosticText', line.split(None, 2)[2])
168
-            for ch in ['"', '`']:
165
+    for line in path.read_text(encoding="UTF-8").splitlines(keepends=False):
166
+        if enum_names and line.startswith(("??? failure ", "??? warning ")):
167
+            text = cast("DiagnosticText", line.split(None, 2)[2])
168
+            for ch in ['"', "`"]:
169 169
                 assert text.startswith(ch)
170 170
                 assert text.endswith(ch)
171
-                text = cast('DiagnosticText', text[1:-1])
171
+                text = cast("DiagnosticText", text[1:-1])
172 172
             yield from _entries_from_text(text=text, enum_names=enum_names)
173 173
             enum_names.clear()
174
-        elif line.startswith('<!-- Message-ID (mark only):') and line.endswith(
175
-            '-->'
174
+        elif line.startswith("<!-- Message-ID (mark only):") and line.endswith(
175
+            "-->"
176 176
         ):
177 177
             name = cast(
178
-                'EnumName',
179
-                line.removeprefix('<!-- Message-ID (mark only):')
180
-                .removesuffix('-->')
178
+                "EnumName",
179
+                line.removeprefix("<!-- Message-ID (mark only):")
180
+                .removesuffix("-->")
181 181
                 .strip(),
182 182
             )
183 183
             yield from _entries_from_mark_only(name)
184
-        elif line.startswith('<!-- Message-ID:') and line.endswith('-->'):
184
+        elif line.startswith("<!-- Message-ID:") and line.endswith("-->"):
185 185
             name = cast(
186
-                'EnumName',
187
-                line.removeprefix('<!-- Message-ID:')
188
-                .removesuffix('-->')
186
+                "EnumName",
187
+                line.removeprefix("<!-- Message-ID:")
188
+                .removesuffix("-->")
189 189
                 .strip(),
190 190
             )
191 191
             enum_names.add(name)
... ...
@@ -198,20 +198,20 @@ manpagedoc_documented_errors: dict[EnumName, DiagnosticText] = {}
198 198
 manpagedoc_documented_warnings: dict[EnumName, DiagnosticText] = {}
199 199
 for set_name, globs, errors, warnings in [
200 200
     (
201
-        'manpages',
201
+        "manpages",
202 202
         sorted(
203
-            pathlib.Path(base, 'share', 'man', 'man1').glob(
204
-                'derivepassphrase*.1'
203
+            pathlib.Path(base, "share", "man", "man1").glob(
204
+                "derivepassphrase*.1"
205 205
             )
206 206
         ),
207 207
         manpage_documented_errors,
208 208
         manpage_documented_warnings,
209 209
     ),
210 210
     (
211
-        'manpage-ish docs',
211
+        "manpage-ish docs",
212 212
         sorted(
213
-            pathlib.Path(base, 'docs', 'reference').glob(
214
-                'derivepassphrase*.1.md'
213
+            pathlib.Path(base, "docs", "reference").glob(
214
+                "derivepassphrase*.1.md"
215 215
             )
216 216
         ),
217 217
         manpagedoc_documented_errors,
... ...
@@ -219,17 +219,17 @@ for set_name, globs, errors, warnings in [
219 219
     ),
220 220
 ]:
221 221
     for path in globs:
222
-        print(f'CHECK DOC {str(path.relative_to(base))!r}')
222
+        print(f"CHECK DOC {str(path.relative_to(base))!r}")
223 223
         checker = (
224
-            _check_manpage if set_name == 'manpages' else _check_manpagedoc
224
+            _check_manpage if set_name == "manpages" else _check_manpagedoc
225 225
         )
226 226
         for diagnostic_type, (text, name) in checker(path):
227
-            if diagnostic_type == 'warning':
227
+            if diagnostic_type == "warning":
228 228
                 warnings[name] = text
229
-                print(f'DOC WARN {name} {text!r}')
229
+                print(f"DOC WARN {name} {text!r}")
230 230
             else:
231 231
                 errors[name] = text
232
-                print(f'DOC ERR {name} {text!r}')
232
+                print(f"DOC ERR {name} {text!r}")
233 233
     assert set(errors) >= set(known_errors), (
234 234
         f"Some error messages aren't documented in the {set_name}: "
235 235
         + repr(set(known_errors) - set(errors))
... ...
@@ -239,35 +239,35 @@ for set_name, globs, errors, warnings in [
239 239
         + repr(set(known_warnings) - set(warnings))
240 240
     )
241 241
     assert set(errors) <= set(known_errors), (
242
-        f'Some unknown error messages are documented in the {set_name}: '
242
+        f"Some unknown error messages are documented in the {set_name}: "
243 243
         + repr(set(errors) - set(known_errors))  # type: ignore[arg-type]
244 244
     )
245 245
     assert set(warnings) <= set(known_warnings), (
246
-        f'Some unknown warning messages are documented in the {set_name}: '
246
+        f"Some unknown warning messages are documented in the {set_name}: "
247 247
         + repr(set(warnings) - set(known_warnings))  # type: ignore[arg-type]
248 248
     )
249 249
 
250 250
 py_file_errors: set[EnumName] = set()
251 251
 py_file_warnings: set[EnumName] = set()
252 252
 match_errors_warnings = re.compile(
253
-    r'\b(?:cli_messages|msg|_msg)\.(Err|Warn)MsgTemplate\.([A-Z0-9_]+)'
253
+    r"\b(?:cli_messages|msg|_msg)\.(Err|Warn)MsgTemplate\.([A-Z0-9_]+)"
254 254
 )
255 255
 for path in sorted(
256
-    pathlib.Path(base, 'src', 'derivepassphrase').glob('**/*.py')
256
+    pathlib.Path(base, "src", "derivepassphrase").glob("**/*.py")
257 257
 ):
258 258
     if path != pathlib.Path(
259
-        base, 'src', 'derivepassphrase', '_internals', 'cli_messages.py'
259
+        base, "src", "derivepassphrase", "_internals", "cli_messages.py"
260 260
     ):
261
-        print(f'CHECK SOURCE {str(path.relative_to(base))!r}')
262
-        filecontents = path.read_text(encoding='UTF-8')
261
+        print(f"CHECK SOURCE {str(path.relative_to(base))!r}")
262
+        filecontents = path.read_text(encoding="UTF-8")
263 263
         for match in match_errors_warnings.finditer(filecontents):
264 264
             message_type, symbol = match.group(1, 2)
265
-            if message_type == 'Err':
266
-                py_file_errors.add(cast('EnumName', symbol))
267
-                print(f'SOURCE ERR {symbol}')
268
-            elif message_type == 'Warn':
269
-                py_file_warnings.add(cast('EnumName', symbol))
270
-                print(f'SOURCE WARN {symbol}')
265
+            if message_type == "Err":
266
+                py_file_errors.add(cast("EnumName", symbol))
267
+                print(f"SOURCE ERR {symbol}")
268
+            elif message_type == "Warn":
269
+                py_file_warnings.add(cast("EnumName", symbol))
270
+                print(f"SOURCE WARN {symbol}")
271 271
 if py_file_errors != set(known_errors):
272 272
     print(
273 273
         "Some error messages aren't in use: "
... ...
@@ -29,13 +29,13 @@ import sys
29 29
 
30 30
 BLOCK_SIZE = 4096
31 31
 
32
-envs = ['3.9', '3.11', '3.13', 'pypy3.10']
33
-opts = ['-py', ','.join(envs)]
32
+envs = ["3.9", "3.11", "3.13", "pypy3.10"]
33
+opts = ["-py", ",".join(envs)]
34 34
 
35 35
 current_branch = (
36
-    os.getenv('GIT_CURRENT_BRANCH')
36
+    os.getenv("GIT_CURRENT_BRANCH")
37 37
     or subprocess.run(
38
-        ['git', 'branch', '--show-current'],
38
+        ["git", "branch", "--show-current"],
39 39
         capture_output=True,
40 40
         text=True,
41 41
         check=False,
... ...
@@ -48,11 +48,11 @@ current_branch = (
48 48
 is_stgit_patch = bool(
49 49
     subprocess.run(
50 50
         [
51
-            'git',
52
-            'rev-parse',
53
-            '--verify',
54
-            '--end-of-options',
55
-            f'refs/stacks/{current_branch}',
51
+            "git",
52
+            "rev-parse",
53
+            "--verify",
54
+            "--end-of-options",
55
+            f"refs/stacks/{current_branch}",
56 56
         ],
57 57
         capture_output=True,
58 58
         check=False,
... ...
@@ -66,17 +66,17 @@ try:
66 66
     # violations.  Afterwards, run with normal settings to handle true
67 67
     # E501s.
68 68
     subprocess.run(
69
-        ['hatch', 'fmt', '-l', '--', '--ignore=E501,RUF100'], check=True
69
+        ["hatch", "fmt", "-l", "--", "--ignore=E501,RUF100"], check=True
70 70
     )
71
-    subprocess.run(['hatch', 'fmt', '-f'], check=True)
72
-    subprocess.run(['hatch', 'fmt', '-l'], check=True)
73
-    if current_branch == 'master':
71
+    subprocess.run(["hatch", "fmt", "-f"], check=True)
72
+    subprocess.run(["hatch", "fmt", "-l"], check=True)
73
+    if current_branch == "master":
74 74
         subprocess.run(
75
-            ['hatch', 'env', 'run', '-e', 'types', '--', 'check'], check=True
75
+            ["hatch", "env", "run", "-e", "types", "--", "check"], check=True
76 76
         )
77 77
         try:
78 78
             h = hashlib.sha256(
79
-                pathlib.Path('po/derivepassphrase.pot').read_bytes(),
79
+                pathlib.Path("po/derivepassphrase.pot").read_bytes(),
80 80
                 usedforsecurity=True,
81 81
             )
82 82
         except FileNotFoundError:
... ...
@@ -85,22 +85,22 @@ try:
85 85
             h2 = hashlib.sha256(
86 86
                 subprocess.run(
87 87
                     [
88
-                        'hatch',
89
-                        'run',
90
-                        'python3',
91
-                        '-m',
92
-                        'derivepassphrase._internals.cli_messages',
88
+                        "hatch",
89
+                        "run",
90
+                        "python3",
91
+                        "-m",
92
+                        "derivepassphrase._internals.cli_messages",
93 93
                     ],
94 94
                     check=True,
95 95
                     stdout=subprocess.PIPE,
96
-                    input=b'',
96
+                    input=b"",
97 97
                 ).stdout,
98 98
                 usedforsecurity=True,
99 99
             )
100 100
             if h.digest() != h2.digest():
101 101
                 sys.exit(
102
-                    'ERROR: po/derivepassphrase.pot '
103
-                    'has unreproducible contents'
102
+                    "ERROR: po/derivepassphrase.pot "
103
+                    "has unreproducible contents"
104 104
                 )
105 105
         # fmt: off
106 106
         subprocess.run(
... ...
@@ -112,19 +112,19 @@ try:
112 112
         )
113 113
         # fmt: on
114 114
         subprocess.run(
115
-            ['hatch', 'test', '-acpqr', '--', '--maxfail', '1'],
115
+            ["hatch", "test", "-acpqr", "--", "--maxfail", "1"],
116 116
             check=True,
117 117
         )
118 118
     elif not is_stgit_patch:
119 119
         subprocess.run(
120
-            ['hatch', 'env', 'run', '-e', 'types', '--', 'check'], check=True
120
+            ["hatch", "env", "run", "-e", "types", "--", "check"], check=True
121 121
         )
122 122
         subprocess.run(
123
-            ['hatch', 'test', '-cpqr', *opts, '--', '--maxfail', '1'],
124
-            env={**os.environ} | {'HYPOTHESIS_PROFILE': 'dev'},
123
+            ["hatch", "test", "-cpqr", *opts, "--", "--maxfail", "1"],
124
+            env={**os.environ} | {"HYPOTHESIS_PROFILE": "dev"},
125 125
             check=True,
126 126
         )
127 127
 except subprocess.CalledProcessError as exc:
128
-    sys.exit(getattr(exc, 'returncode', 1))
128
+    sys.exit(getattr(exc, "returncode", 1))
129 129
 except KeyboardInterrupt:
130 130
     sys.exit(1)
... ...
@@ -105,7 +105,7 @@ def try_key(
105 105
 def format_key(key: tests.SSHTestKey) -> str:
106 106
     """Return a formatted SSH test key."""
107 107
     ascii_printables = range(32, 127)
108
-    ascii_whitespace = {ord(' '), ord('\n'), ord('\t'), ord('\r'), ord('\f')}
108
+    ascii_whitespace = {ord(" "), ord("\n"), ord("\t"), ord("\r"), ord("\f")}
109 109
 
110 110
     def as_raw_string_or_hex(bytestring: bytes) -> str:
111 111
         if bytestring.find(b'"""') < 0 and all(
... ...
@@ -113,8 +113,8 @@ def format_key(key: tests.SSHTestKey) -> str:
113 113
             for byte in bytestring
114 114
         ):
115 115
             return f'rb"""{bytestring.decode("ascii")}"""'
116
-        hexstring = bytestring.hex(' ', 1)
117
-        wrapped_hexstring = '\n'.join(
116
+        hexstring = bytestring.hex(" ", 1)
117
+        wrapped_hexstring = "\n".join(
118 118
             textwrap.TextWrapper(width=48).wrap(hexstring)
119 119
         )
120 120
         return f'''bytes.fromhex("""
... ...
@@ -124,40 +124,40 @@ def format_key(key: tests.SSHTestKey) -> str:
124 124
     f = as_raw_string_or_hex
125 125
 
126 126
     lines = [
127
-        'SSHTestKey(\n',
128
-        '    public_key=' + f(key.public_key) + ',\n',
129
-        '    public_key_data=' + f(key.public_key_data) + ',\n',
130
-        '    private_key=' + f(key.private_key) + ',\n',
131
-        '    private_key_blob=' + f(key.private_key_blob) + ',\n',
127
+        "SSHTestKey(\n",
128
+        "    public_key=" + f(key.public_key) + ",\n",
129
+        "    public_key_data=" + f(key.public_key_data) + ",\n",
130
+        "    private_key=" + f(key.private_key) + ",\n",
131
+        "    private_key_blob=" + f(key.private_key_blob) + ",\n",
132 132
     ]
133 133
     if key.expected_signatures:
134 134
         expected_signature_lines = [
135
-            'expected_signatures={\n',
135
+            "expected_signatures={\n",
136 136
         ]
137 137
         for sig in key.expected_signatures.values():
138 138
             expected_signature_lines.extend([
139
-                f'    {sig.signature_class!s}: '
140
-                'SSHTestKeyDeterministicSignature(\n',
141
-                '        signature=' + f(sig.signature) + ',\n',
142
-                '        derived_passphrase='
139
+                f"    {sig.signature_class!s}: "
140
+                "SSHTestKeyDeterministicSignature(\n",
141
+                "        signature=" + f(sig.signature) + ",\n",
142
+                "        derived_passphrase="
143 143
                 + f(sig.derived_passphrase)
144
-                + ',\n',
144
+                + ",\n",
145 145
             ])
146 146
             if (
147 147
                 sig.signature_class
148 148
                 != tests.SSHTestKeyDeterministicSignatureClass.SPEC
149 149
             ):
150 150
                 expected_signature_lines.append(
151
-                    f'        signature_class={sig.signature_class!s},\n'
151
+                    f"        signature_class={sig.signature_class!s},\n"
152 152
                 )
153
-            expected_signature_lines.append('    ),\n')
154
-        expected_signature_lines.append('},\n')
155
-        lines.extend('    ' + x for x in expected_signature_lines)
153
+            expected_signature_lines.append("    ),\n")
154
+        expected_signature_lines.append("},\n")
155
+        lines.extend("    " + x for x in expected_signature_lines)
156 156
     else:
157
-        lines.append('    expected_signatures={},\n')
158
-    lines.append(')')
157
+        lines.append("    expected_signatures={},\n")
158
+    lines.append(")")
159 159
 
160
-    return ''.join(lines)
160
+    return "".join(lines)
161 161
 
162 162
 
163 163
 def main(argv: list[str] | None = None) -> None:
... ...
@@ -165,27 +165,27 @@ def main(argv: list[str] | None = None) -> None:
165 165
     ap = argparse.ArgumentParser()
166 166
     group = ap.add_mutually_exclusive_group()
167 167
     group.add_argument(
168
-        '--rfc-6979',
169
-        action='store_const',
170
-        dest='deterministic_signature_class',
168
+        "--rfc-6979",
169
+        action="store_const",
170
+        dest="deterministic_signature_class",
171 171
         const=tests.SSHTestKeyDeterministicSignatureClass.RFC_6979,
172 172
         default=tests.SSHTestKeyDeterministicSignatureClass.RFC_6979,
173
-        help='assume RFC 6979 signatures for deterministic DSA',
173
+        help="assume RFC 6979 signatures for deterministic DSA",
174 174
     )
175 175
     group.add_argument(
176
-        '--pageant-068-080',
177
-        action='store_const',
178
-        dest='deterministic_signature_class',
176
+        "--pageant-068-080",
177
+        action="store_const",
178
+        dest="deterministic_signature_class",
179 179
         const=tests.SSHTestKeyDeterministicSignatureClass.Pageant_068_080,
180 180
         default=tests.SSHTestKeyDeterministicSignatureClass.RFC_6979,
181
-        help='assume Pageant 0.68-0.80 signatures for deterministic DSA',
181
+        help="assume Pageant 0.68-0.80 signatures for deterministic DSA",
182 182
     )
183 183
     ap.add_argument(
184
-        'keynames',
185
-        nargs='*',
186
-        metavar='KEYNAME',
187
-        help='query the named test key in the agent '
188
-        '(multiple use possible; default: all keys)',
184
+        "keynames",
185
+        nargs="*",
186
+        metavar="KEYNAME",
187
+        help="query the named test key in the agent "
188
+        "(multiple use possible; default: all keys)",
189 189
     )
190 190
     args = ap.parse_args(args=argv)
191 191
     if not args.keynames:
... ...
@@ -198,8 +198,8 @@ def main(argv: list[str] | None = None) -> None:
198 198
                 deterministic_signature_class=args.deterministic_signature_class,
199 199
             )
200 200
             if key is not None:
201
-                print(f'keys[{keyname!r}] =', format_key(key))
201
+                print(f"keys[{keyname!r}] =", format_key(key))
202 202
 
203 203
 
204
-if __name__ == '__main__':
204
+if __name__ == "__main__":
205 205
     main()
... ...
@@ -4,10 +4,10 @@
4 4
 
5 5
 """Work-alike of vault(1) – a deterministic, stateless password manager"""  # noqa: D415,RUF002
6 6
 
7
-__author__ = 'Marco Ricci <software@the13thletter.info>'
8
-__distribution_name__ = 'derivepassphrase'
7
+__author__ = "Marco Ricci <software@the13thletter.info>"
8
+__distribution_name__ = "derivepassphrase"
9 9
 
10 10
 # Automatically generated.  DO NOT EDIT! Use importlib.metadata instead
11 11
 # to query the correct values.
12
-__version__ = '0.5.2'
12
+__version__ = "0.5.2"
13 13
 # END automatically generated.
... ...
@@ -5,7 +5,7 @@
5 5
 
6 6
 import sys
7 7
 
8
-if __name__ == '__main__':
8
+if __name__ == "__main__":
9 9
     from derivepassphrase.cli import derivepassphrase
10 10
 
11 11
     sys.exit(derivepassphrase())
... ...
@@ -65,10 +65,10 @@ PROG_NAME = _msg.PROG_NAME
65 65
 KEY_DISPLAY_LENGTH = 50
66 66
 
67 67
 # Error messages
68
-INVALID_VAULT_CONFIG = 'Invalid vault config'
69
-AGENT_COMMUNICATION_ERROR = 'Error communicating with the SSH agent'
70
-NO_SUITABLE_KEYS = 'No suitable SSH keys were found'
71
-EMPTY_SELECTION = 'Empty selection'
68
+INVALID_VAULT_CONFIG = "Invalid vault config"
69
+AGENT_COMMUNICATION_ERROR = "Error communicating with the SSH agent"
70
+NO_SUITABLE_KEYS = "No suitable SSH keys were found"
71
+EMPTY_SELECTION = "Empty selection"
72 72
 
73 73
 
74 74
 # Shell completion
... ...
@@ -92,7 +92,7 @@ def shell_complete_path(
92 92
 ) -> list[str | click.shell_completion.CompletionItem]:
93 93
     """Request standard path completion for the `path` argument."""  # noqa: DOC201
94 94
     del ctx, parameter, value
95
-    return [click.shell_completion.CompletionItem('', type='file')]
95
+    return [click.shell_completion.CompletionItem("", type="file")]
96 96
 
97 97
 
98 98
 # The standard `click` shell completion scripts serialize the completion
... ...
@@ -128,7 +128,7 @@ def is_completable_item(obj: object) -> bool:
128 128
 
129 129
     """
130 130
     obj = str(obj)
131
-    forbidden = frozenset(chr(i) for i in range(32)) | {'\x7f'}
131
+    forbidden = frozenset(chr(i) for i in range(32)) | {"\x7f"}
132 132
     return not any(f in obj for f in forbidden)
133 133
 
134 134
 
... ...
@@ -150,7 +150,7 @@ def shell_complete_service(
150 150
         config = load_config()
151 151
         return sorted(
152 152
             sv
153
-            for sv in config['services']
153
+            for sv in config["services"]
154 154
             if sv.startswith(value) and is_completable_item(sv)
155 155
         )
156 156
     except FileNotFoundError:
... ...
@@ -158,7 +158,7 @@ def shell_complete_service(
158 158
             config, _exc = migrate_and_load_old_config()
159 159
             return sorted(
160 160
                 sv
161
-                for sv in config['services']
161
+                for sv in config["services"]
162 162
                 if sv.startswith(value) and is_completable_item(sv)
163 163
             )
164 164
         except FileNotFoundError:
... ...
@@ -171,14 +171,14 @@ def shell_complete_service(
171 171
 # =====
172 172
 
173 173
 config_filename_table = {
174
-    None: '.',
175
-    'write lock': '',
176
-    'vault': 'vault.json',
177
-    'user configuration': 'config.toml',
174
+    None: ".",
175
+    "write lock": "",
176
+    "vault": "vault.json",
177
+    "user configuration": "config.toml",
178 178
     # TODO(the-13th-letter): Remove the old settings.json file.
179 179
     # https://the13thletter.info/derivepassphrase/latest/upgrade-notes.html#v1.0-old-settings-file
180
-    'old settings.json': 'settings.json',
181
-    'notes backup': 'old-notes.txt',
180
+    "old settings.json": "settings.json",
181
+    "notes backup": "old-notes.txt",
182 182
 }
183 183
 
184 184
 LOCK_SIZE = 4096
... ...
@@ -243,7 +243,7 @@ class ConfigurationMutex:
243 243
 
244 244
     def __init__(self) -> None:
245 245
         """Initialize self."""
246
-        if sys.platform == 'win32':  # pragma: unless the-annoying-os no cover
246
+        if sys.platform == "win32":  # pragma: unless the-annoying-os no cover
247 247
             import msvcrt  # noqa: PLC0415
248 248
 
249 249
             locking = msvcrt.locking
... ...
@@ -276,14 +276,14 @@ class ConfigurationMutex:
276 276
                 )
277 277
                 self.write_lock_condition.notify()
278 278
                 self.write_lock_file.touch()
279
-                self.write_lock_fileobj = self.write_lock_file.open('wb')
279
+                self.write_lock_fileobj = self.write_lock_file.open("wb")
280 280
                 lock_fd(self.write_lock_fileobj.fileno())
281 281
 
282 282
         def unlock_func() -> None:
283 283
             with self.write_lock_condition:
284 284
                 assert self.write_lock_fileobj is not None, (
285
-                    'We lost track of the configuration write lock '
286
-                    'file object, so we cannot unlock it anymore!'
285
+                    "We lost track of the configuration write lock "
286
+                    "file object, so we cannot unlock it anymore!"
287 287
                 )
288 288
                 unlock_fd(self.write_lock_fileobj.fileno())
289 289
                 self.write_lock_fileobj.close()
... ...
@@ -292,7 +292,7 @@ class ConfigurationMutex:
292 292
         self.lock = lock_func
293 293
         self.unlock = unlock_func
294 294
         self.write_lock_fileobj = None
295
-        self.write_lock_file = config_filename('write lock')
295
+        self.write_lock_file = config_filename("write lock")
296 296
         self.write_lock_condition = threading.Condition(threading.Lock())
297 297
 
298 298
     def __enter__(self) -> Self:
... ...
@@ -364,28 +364,28 @@ def get_tempdir() -> pathlib.Path:
364 364
     """
365 365
     paths_to_try: list[pathlib.PurePath] = []
366 366
     env_paths_to_try = [
367
-        os.getenv('TMPDIR'),
368
-        os.getenv('TEMP'),
369
-        os.getenv('TMP'),
367
+        os.getenv("TMPDIR"),
368
+        os.getenv("TEMP"),
369
+        os.getenv("TMP"),
370 370
     ]
371 371
     paths_to_try.extend(
372 372
         pathlib.PurePath(p) for p in env_paths_to_try if p is not None
373 373
     )
374 374
     posix_paths_to_try = [
375
-        pathlib.PurePosixPath('/tmp'),  # noqa: S108
376
-        pathlib.PurePosixPath('/var/tmp'),  # noqa: S108
377
-        pathlib.PurePosixPath('/usr/tmp'),
375
+        pathlib.PurePosixPath("/tmp"),  # noqa: S108
376
+        pathlib.PurePosixPath("/var/tmp"),  # noqa: S108
377
+        pathlib.PurePosixPath("/usr/tmp"),
378 378
     ]
379 379
     windows_paths_to_try = [
380
-        pathlib.PureWindowsPath(r'~\AppData\Local\Temp'),
381
-        pathlib.PureWindowsPath(os.path.expandvars(r'%SYSTEMROOT%\Temp')),
382
-        pathlib.PureWindowsPath(r'C:\TEMP'),
383
-        pathlib.PureWindowsPath(r'C:\TMP'),
384
-        pathlib.PureWindowsPath(r'\TEMP'),
385
-        pathlib.PureWindowsPath(r'\TMP'),
380
+        pathlib.PureWindowsPath(r"~\AppData\Local\Temp"),
381
+        pathlib.PureWindowsPath(os.path.expandvars(r"%SYSTEMROOT%\Temp")),
382
+        pathlib.PureWindowsPath(r"C:\TEMP"),
383
+        pathlib.PureWindowsPath(r"C:\TMP"),
384
+        pathlib.PureWindowsPath(r"\TEMP"),
385
+        pathlib.PureWindowsPath(r"\TMP"),
386 386
     ]
387 387
     paths_to_try.extend(
388
-        windows_paths_to_try if sys.platform == 'win32' else posix_paths_to_try
388
+        windows_paths_to_try if sys.platform == "win32" else posix_paths_to_try
389 389
     )
390 390
     for p in paths_to_try:
391 391
         path = pathlib.Path(p).expanduser()
... ...
@@ -400,7 +400,7 @@ def get_tempdir() -> pathlib.Path:
400 400
 
401 401
 
402 402
 def config_filename(
403
-    subsystem: str | None = 'old settings.json',
403
+    subsystem: str | None = "old settings.json",
404 404
 ) -> pathlib.Path:
405 405
     """Return the filename of the configuration file for the subsystem.
406 406
 
... ...
@@ -429,21 +429,21 @@ def config_filename(
429 429
 
430 430
     """
431 431
     path = pathlib.Path(
432
-        os.getenv(PROG_NAME.upper() + '_PATH')
432
+        os.getenv(PROG_NAME.upper() + "_PATH")
433 433
         or click.get_app_dir(PROG_NAME, force_posix=True)
434 434
     )
435
-    if subsystem == 'write lock':
435
+    if subsystem == "write lock":
436 436
         path_hash = base64.b32encode(
437 437
             hashlib.sha256(os.fsencode(path.resolve())).digest()
438 438
         )
439
-        path_hash_text = path_hash[:12].lower().decode('ASCII')
439
+        path_hash_text = path_hash[:12].lower().decode("ASCII")
440 440
         temp_path = get_tempdir()
441
-        filename_ = f'derivepassphrase-lock-{path_hash_text}.txt'
441
+        filename_ = f"derivepassphrase-lock-{path_hash_text}.txt"
442 442
         return temp_path / filename_
443 443
     try:
444 444
         filename = config_filename_table[subsystem]
445 445
     except (KeyError, TypeError):  # pragma: no cover [failsafe]
446
-        msg = f'Unknown configuration subsystem: {subsystem!r}'
446
+        msg = f"Unknown configuration subsystem: {subsystem!r}"
447 447
         raise AssertionError(msg) from None
448 448
     return path / filename
449 449
 
... ...
@@ -465,8 +465,8 @@ def load_config() -> _types.VaultConfig:
465 465
             config.
466 466
 
467 467
     """
468
-    filename = config_filename(subsystem='vault')
469
-    with filename.open('rb') as fileobj:
468
+    filename = config_filename(subsystem="vault")
469
+    with filename.open("rb") as fileobj:
470 470
         data = json.load(fileobj)
471 471
     if not _types.is_vault_config(data):
472 472
         raise ValueError(INVALID_VAULT_CONFIG)
... ...
@@ -495,9 +495,9 @@ def migrate_and_load_old_config() -> tuple[_types.VaultConfig, OSError | None]:
495 495
             config.
496 496
 
497 497
     """
498
-    new_filename = config_filename(subsystem='vault')
499
-    old_filename = config_filename(subsystem='old settings.json')
500
-    with old_filename.open('rb') as fileobj:
498
+    new_filename = config_filename(subsystem="vault")
499
+    old_filename = config_filename(subsystem="old settings.json")
500
+    with old_filename.open("rb") as fileobj:
501 501
         data = json.load(fileobj)
502 502
     if not _types.is_vault_config(data):
503 503
         raise ValueError(INVALID_VAULT_CONFIG)
... ...
@@ -528,10 +528,10 @@ def save_config(config: _types.VaultConfig, /) -> None:
528 528
     """
529 529
     if not _types.is_vault_config(config):
530 530
         raise ValueError(INVALID_VAULT_CONFIG)
531
-    filename = config_filename(subsystem='vault')
531
+    filename = config_filename(subsystem="vault")
532 532
     filedir = filename.resolve().parent
533 533
     filedir.mkdir(parents=True, exist_ok=True)
534
-    with filename.open('w', encoding='UTF-8') as fileobj:
534
+    with filename.open("w", encoding="UTF-8") as fileobj:
535 535
         json.dump(
536 536
             config, fileobj, ensure_ascii=False, indent=2, sort_keys=True
537 537
         )
... ...
@@ -553,8 +553,8 @@ def load_user_config() -> dict[str, Any]:
553 553
             file.
554 554
 
555 555
     """
556
-    filename = config_filename(subsystem='user configuration')
557
-    with filename.open('rb') as fileobj:
556
+    filename = config_filename(subsystem="user configuration")
557
+    with filename.open("rb") as fileobj:
558 558
         return tomllib.load(fileobj)
559 559
 
560 560
 
... ...
@@ -625,8 +625,8 @@ def get_suitable_ssh_keys(
625 625
 
626 626
 def prompt_for_selection(
627 627
     items: Sequence[str | bytes],
628
-    heading: str = 'Possible choices:',
629
-    single_choice_prompt: str = 'Confirm this choice?',
628
+    heading: str = "Possible choices:",
629
+    single_choice_prompt: str = "Confirm this choice?",
630 630
     ctx: click.Context | None = None,
631 631
 ) -> int:
632 632
     """Prompt user for a choice among the given items.
... ...
@@ -667,20 +667,20 @@ def prompt_for_selection(
667 667
         click.echo(click.style(heading, bold=True), err=True, color=color)
668 668
     for i, x in enumerate(items, start=1):
669 669
         click.echo(
670
-            click.style(f'[{i}]', bold=True), nl=False, err=True, color=color
670
+            click.style(f"[{i}]", bold=True), nl=False, err=True, color=color
671 671
         )
672
-        click.echo(' ', nl=False, err=True, color=color)
672
+        click.echo(" ", nl=False, err=True, color=color)
673 673
         click.echo(x, err=True, color=color)
674 674
     if n > 1:
675
-        choices = click.Choice([''] + [str(i) for i in range(1, n + 1)])
675
+        choices = click.Choice([""] + [str(i) for i in range(1, n + 1)])
676 676
         try:
677 677
             choice = click.prompt(
678
-                f'Your selection? (1-{n}, leave empty to abort)',
678
+                f"Your selection? (1-{n}, leave empty to abort)",
679 679
                 err=True,
680 680
                 type=choices,
681 681
                 show_choices=False,
682 682
                 show_default=False,
683
-                default='',
683
+                default="",
684 684
             )
685 685
         except click.Abort:  # pragma: no cover [external]
686 686
             # This branch will not be triggered during testing on
... ...
@@ -690,12 +690,12 @@ def prompt_for_selection(
690 690
             # coverage.
691 691
             #
692 692
             # https://github.com/pallets/click/issues/2934
693
-            choice = ''
693
+            choice = ""
694 694
         if not choice:
695 695
             raise IndexError(EMPTY_SELECTION)
696 696
         return int(choice) - 1
697 697
     prompt_suffix = (
698
-        ' ' if single_choice_prompt.endswith(tuple('?.!')) else ': '
698
+        " " if single_choice_prompt.endswith(tuple("?.!")) else ": "
699 699
     )
700 700
     try:
701 701
         click.confirm(
... ...
@@ -895,21 +895,21 @@ def select_ssh_key(
895 895
     key_listing: list[str] = []
896 896
     unstring_prefix = ssh_agent.SSHAgentClient.unstring_prefix
897 897
     for key, comment in suitable_keys:
898
-        keytype = unstring_prefix(key)[0].decode('ASCII')
899
-        key_str = base64.standard_b64encode(key).decode('ASCII')
898
+        keytype = unstring_prefix(key)[0].decode("ASCII")
899
+        key_str = base64.standard_b64encode(key).decode("ASCII")
900 900
         remaining_key_display_length = KEY_DISPLAY_LENGTH - 1 - len(keytype)
901 901
         key_extract = min(
902 902
             key_str,
903
-            '...' + key_str[-remaining_key_display_length:],
903
+            "..." + key_str[-remaining_key_display_length:],
904 904
             key=len,
905 905
         )
906
-        comment_str = comment.decode('UTF-8', errors='replace')
907
-        key_listing.append(f'{keytype} {key_extract}  {comment_str}')
906
+        comment_str = comment.decode("UTF-8", errors="replace")
907
+        key_listing.append(f"{keytype} {key_extract}  {comment_str}")
908 908
     try:
909 909
         choice = prompt_for_selection(
910 910
             key_listing,
911
-            heading='Suitable SSH keys:',
912
-            single_choice_prompt='Use this key?',
911
+            heading="Suitable SSH keys:",
912
+            single_choice_prompt="Use this key?",
913 913
             ctx=ctx,
914 914
         )
915 915
     except IndexError:
... ...
@@ -933,10 +933,10 @@ def prompt_for_passphrase() -> str:
933 933
     """
934 934
     try:
935 935
         return cast(
936
-            'str',
936
+            "str",
937 937
             click.prompt(
938
-                'Passphrase',
939
-                default='',
938
+                "Passphrase",
939
+                default="",
940 940
                 hide_input=True,
941 941
                 show_default=False,
942 942
                 err=True,
... ...
@@ -949,7 +949,7 @@ def prompt_for_passphrase() -> str:
949 949
         # of nondeterminism, exclude it from coverage.
950 950
         #
951 951
         # https://github.com/pallets/click/issues/2934
952
-        return ''
952
+        return ""
953 953
 
954 954
 
955 955
 def toml_key(*parts: str) -> str:
... ...
@@ -957,29 +957,29 @@ def toml_key(*parts: str) -> str:
957 957
 
958 958
     def escape(string: str) -> str:
959 959
         translated = string.translate({
960
-            0: r'\u0000',
961
-            1: r'\u0001',
962
-            2: r'\u0002',
963
-            3: r'\u0003',
964
-            4: r'\u0004',
965
-            5: r'\u0005',
966
-            6: r'\u0006',
967
-            7: r'\u0007',
968
-            8: r'\b',
969
-            9: r'\t',
970
-            10: r'\n',
971
-            11: r'\u000B',
972
-            12: r'\f',
973
-            13: r'\r',
974
-            14: r'\u000E',
975
-            15: r'\u000F',
976
-            ord('"'): r'\"',
977
-            ord('\\'): r'\\',
978
-            127: r'\u007F',
960
+            0: r"\u0000",
961
+            1: r"\u0001",
962
+            2: r"\u0002",
963
+            3: r"\u0003",
964
+            4: r"\u0004",
965
+            5: r"\u0005",
966
+            6: r"\u0006",
967
+            7: r"\u0007",
968
+            8: r"\b",
969
+            9: r"\t",
970
+            10: r"\n",
971
+            11: r"\u000B",
972
+            12: r"\f",
973
+            13: r"\r",
974
+            14: r"\u000E",
975
+            15: r"\u000F",
976
+            ord('"'): r"\"",
977
+            ord("\\"): r"\\",
978
+            127: r"\u007F",
979 979
         })
980 980
         return f'"{translated}"' if translated != string else string
981 981
 
982
-    return '.'.join(map(escape, parts))
982
+    return ".".join(map(escape, parts))
983 983
 
984 984
 
985 985
 class ORIGIN(enum.Enum):
... ...
@@ -1026,23 +1026,23 @@ def check_for_misleading_passphrase(
1026 1026
             The main user configuration is invalid.
1027 1027
 
1028 1028
     """
1029
-    form_key = 'unicode-normalization-form'
1030
-    default_form: str = main_config.get('vault', {}).get(
1031
-        f'default-{form_key}', 'NFC'
1029
+    form_key = "unicode-normalization-form"
1030
+    default_form: str = main_config.get("vault", {}).get(
1031
+        f"default-{form_key}", "NFC"
1032 1032
     )
1033
-    form_dict: dict[str, dict] = main_config.get('vault', {}).get(form_key, {})
1033
+    form_dict: dict[str, dict] = main_config.get("vault", {}).get(form_key, {})
1034 1034
     form: Any = (
1035 1035
         default_form
1036
-        if isinstance(key, ORIGIN) or key == ('global',)
1036
+        if isinstance(key, ORIGIN) or key == ("global",)
1037 1037
         else form_dict.get(key[1], default_form)
1038 1038
     )
1039 1039
     config_key = (
1040
-        toml_key('vault', key[1], form_key)
1040
+        toml_key("vault", key[1], form_key)
1041 1041
         if isinstance(key, tuple) and len(key) > 1 and key[1] in form_dict
1042
-        else f'vault.default-{form_key}'
1042
+        else f"vault.default-{form_key}"
1043 1043
     )
1044
-    if form not in {'NFC', 'NFD', 'NFKC', 'NFKD'}:
1045
-        msg = f'Invalid value {form!r} for config key {config_key}'
1044
+    if form not in {"NFC", "NFD", "NFKC", "NFKD"}:
1045
+        msg = f"Invalid value {form!r} for config key {config_key}"
1046 1046
         raise AssertionError(msg)
1047 1047
     logger = logging.getLogger(PROG_NAME)
1048 1048
     formatted_key = (
... ...
@@ -1050,8 +1050,8 @@ def check_for_misleading_passphrase(
1050 1050
         if isinstance(key, ORIGIN)
1051 1051
         else _types.json_path(key)
1052 1052
     )
1053
-    if 'phrase' in value:
1054
-        phrase = value['phrase']
1053
+    if "phrase" in value:
1054
+        phrase = value["phrase"]
1055 1055
         if not unicodedata.is_normalized(form, phrase):
1056 1056
             logger.warning(
1057 1057
                 _msg.TranslatedString(
... ...
@@ -1060,7 +1060,7 @@ def check_for_misleading_passphrase(
1060 1060
                     form=form,
1061 1061
                 ),
1062 1062
                 stacklevel=2,
1063
-                extra={'color': ctx.color if ctx is not None else None},
1063
+                extra={"color": ctx.color if ctx is not None else None},
1064 1064
             )
1065 1065
 
1066 1066
 
... ...
@@ -1141,27 +1141,27 @@ def print_config_as_sh_script(
1141 1141
 
1142 1142
     """
1143 1143
     service_keys = (
1144
-        'length',
1145
-        'repeat',
1146
-        'lower',
1147
-        'upper',
1148
-        'number',
1149
-        'space',
1150
-        'dash',
1151
-        'symbol',
1144
+        "length",
1145
+        "repeat",
1146
+        "lower",
1147
+        "upper",
1148
+        "number",
1149
+        "space",
1150
+        "dash",
1151
+        "symbol",
1152 1152
     )
1153
-    print('#!/bin/sh -e', file=outfile)
1153
+    print("#!/bin/sh -e", file=outfile)
1154 1154
     print(file=outfile)
1155
-    print(shlex.join([*prog_name_list, '--clear']), file=outfile)
1155
+    print(shlex.join([*prog_name_list, "--clear"]), file=outfile)
1156 1156
     sv_obj_pairs: list[
1157 1157
         tuple[
1158 1158
             str | None,
1159 1159
             _types.VaultConfigGlobalSettings
1160 1160
             | _types.VaultConfigServicesSettings,
1161 1161
         ],
1162
-    ] = list(config['services'].items())
1163
-    if config.get('global', {}):
1164
-        sv_obj_pairs.insert(0, (None, config['global']))
1162
+    ] = list(config["services"].items())
1163
+    if config.get("global", {}):
1164
+        sv_obj_pairs.insert(0, (None, config["global"]))
1165 1165
     for sv, sv_obj in sv_obj_pairs:
1166 1166
         this_service_keys = tuple(k for k in service_keys if k in sv_obj)
1167 1167
         this_other_keys = tuple(k for k in sv_obj if k not in service_keys)
... ...
@@ -1169,37 +1169,37 @@ def print_config_as_sh_script(
1169 1169
             other_sv_obj = {k: sv_obj[k] for k in this_other_keys}  # type: ignore[literal-required]
1170 1170
             dumped_config = json.dumps(
1171 1171
                 (
1172
-                    {'services': {sv: other_sv_obj}}
1172
+                    {"services": {sv: other_sv_obj}}
1173 1173
                     if sv is not None
1174
-                    else {'global': other_sv_obj, 'services': {}}
1174
+                    else {"global": other_sv_obj, "services": {}}
1175 1175
                 ),
1176 1176
                 ensure_ascii=False,
1177 1177
                 indent=None,
1178 1178
             )
1179 1179
             print(
1180
-                shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
1180
+                shlex.join([*prog_name_list, "--import", "-"]) + " <<'HERE'",
1181 1181
                 dumped_config,
1182
-                'HERE',
1183
-                sep='\n',
1182
+                "HERE",
1183
+                sep="\n",
1184 1184
                 file=outfile,
1185 1185
             )
1186 1186
         if not this_service_keys and not this_other_keys and sv:
1187 1187
             dumped_config = json.dumps(
1188
-                {'services': {sv: {}}},
1188
+                {"services": {sv: {}}},
1189 1189
                 ensure_ascii=False,
1190 1190
                 indent=None,
1191 1191
             )
1192 1192
             print(
1193
-                shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
1193
+                shlex.join([*prog_name_list, "--import", "-"]) + " <<'HERE'",
1194 1194
                 dumped_config,
1195
-                'HERE',
1196
-                sep='\n',
1195
+                "HERE",
1196
+                sep="\n",
1197 1197
                 file=outfile,
1198 1198
             )
1199 1199
         elif this_service_keys:
1200
-            tokens = [*prog_name_list, '--config']
1200
+            tokens = [*prog_name_list, "--config"]
1201 1201
             for key in this_service_keys:
1202
-                tokens.extend([f'--{key}', str(sv_obj[key])])  # type: ignore[literal-required]
1202
+                tokens.extend([f"--{key}", str(sv_obj[key])])  # type: ignore[literal-required]
1203 1203
             if sv is not None:
1204
-                tokens.extend(['--', sv])
1204
+                tokens.extend(["--", sv])
1205 1205
             print(shlex.join(tokens), file=outfile)
... ...
@@ -41,9 +41,9 @@ VERSION = _internals.VERSION
41 41
 VERSION_OUTPUT_WRAPPING_WIDTH = 72
42 42
 
43 43
 # Error messages
44
-NOT_AN_INTEGER = 'not an integer'
45
-NOT_A_NONNEGATIVE_INTEGER = 'not a non-negative integer'
46
-NOT_A_POSITIVE_INTEGER = 'not a positive integer'
44
+NOT_AN_INTEGER = "not an integer"
45
+NOT_A_NONNEGATIVE_INTEGER = "not a non-negative integer"
46
+NOT_A_POSITIVE_INTEGER = "not a positive integer"
47 47
 
48 48
 
49 49
 # Logging
... ...
@@ -67,7 +67,7 @@ class ClickEchoStderrHandler(logging.Handler):
67 67
         click.echo(
68 68
             self.format(record),
69 69
             err=True,
70
-            color=getattr(record, 'color', None),
70
+            color=getattr(record, "color", None),
71 71
         )
72 72
 
73 73
 
... ...
@@ -103,7 +103,7 @@ class CLIofPackageFormatter(logging.Formatter):
103 103
         self.package_name = (
104 104
             package_name
105 105
             if package_name is not None
106
-            else prog_name.lower().replace(' ', '_').replace('-', '_')
106
+            else prog_name.lower().replace(" ", "_").replace("-", "_")
107 107
         )
108 108
 
109 109
     def format(self, record: logging.LogRecord) -> str:
... ...
@@ -142,38 +142,38 @@ class CLIofPackageFormatter(logging.Formatter):
142 142
 
143 143
         """
144 144
         preliminary_result = record.getMessage()
145
-        prefix = f'{self.prog_name}: '
146
-        if record.levelname == 'DEBUG':  # pragma: no cover [unused]
147
-            level_indicator = 'Debug: '
148
-        elif record.levelname == 'INFO':
149
-            level_indicator = ''
150
-        elif record.levelname == 'WARNING':
145
+        prefix = f"{self.prog_name}: "
146
+        if record.levelname == "DEBUG":  # pragma: no cover [unused]
147
+            level_indicator = "Debug: "
148
+        elif record.levelname == "INFO":
149
+            level_indicator = ""
150
+        elif record.levelname == "WARNING":
151 151
             level_indicator = (
152
-                f'{click.style("Deprecation warning", bold=True)}: '
153
-                if record.name.endswith('.deprecation')
154
-                else f'{click.style("Warning", bold=True)}: '
152
+                f"{click.style('Deprecation warning', bold=True)}: "
153
+                if record.name.endswith(".deprecation")
154
+                else f"{click.style('Warning', bold=True)}: "
155 155
             )
156
-        elif record.levelname in {'ERROR', 'CRITICAL'}:
157
-            level_indicator = ''
156
+        elif record.levelname in {"ERROR", "CRITICAL"}:
157
+            level_indicator = ""
158 158
         else:  # pragma: no cover [failsafe]
159
-            msg = f'Unsupported logging level: {record.levelname}'
159
+            msg = f"Unsupported logging level: {record.levelname}"
160 160
             raise AssertionError(msg)
161 161
         parts = [
162
-            ''.join(
162
+            "".join(
163 163
                 prefix + level_indicator + line
164 164
                 for line in preliminary_result.splitlines(True)  # noqa: FBT003
165 165
             )
166 166
         ]
167 167
         if record.exc_info:
168
-            parts.append(self.formatException(record.exc_info) + '\n')
169
-        return ''.join(parts)
168
+            parts.append(self.formatException(record.exc_info) + "\n")
169
+        return "".join(parts)
170 170
 
171 171
 
172 172
 class StandardCLILogging:
173 173
     """Set up CLI logging handlers upon instantiation."""
174 174
 
175 175
     prog_name = PROG_NAME
176
-    package_name = PROG_NAME.lower().replace(' ', '_').replace('-', '_')
176
+    package_name = PROG_NAME.lower().replace(" ", "_").replace("-", "_")
177 177
     cli_formatter = CLIofPackageFormatter(
178 178
         prog_name=prog_name, package_name=package_name
179 179
     )
... ...
@@ -182,7 +182,7 @@ class StandardCLILogging:
182 182
     cli_handler.setFormatter(cli_formatter)
183 183
     cli_handler.setLevel(logging.WARNING)
184 184
     warnings_handler = ClickEchoStderrHandler()
185
-    warnings_handler.addFilter(logging.Filter(name='py.warnings'))
185
+    warnings_handler.addFilter(logging.Filter(name="py.warnings"))
186 186
     warnings_handler.setFormatter(cli_formatter)
187 187
     warnings_handler.setLevel(logging.WARNING)
188 188
 
... ...
@@ -264,7 +264,7 @@ class StandardWarningsLoggingContextManager(StandardLoggingContextManager):
264 264
         self,
265 265
         handler: logging.Handler,
266 266
     ) -> None:
267
-        super().__init__(handler=handler, root_logger='py.warnings')
267
+        super().__init__(handler=handler, root_logger="py.warnings")
268 268
         self.stack: MutableSequence[
269 269
             tuple[
270 270
                 Callable[
... ...
@@ -303,7 +303,7 @@ class StandardWarningsLoggingContextManager(StandardLoggingContextManager):
303 303
                     message, category, filename, lineno, file, line
304 304
                 )
305 305
             else:
306
-                logging.getLogger('py.warnings').warning(
306
+                logging.getLogger("py.warnings").warning(
307 307
                     str(
308 308
                         warnings.formatwarning(
309 309
                             message, category, filename, lineno, line
... ...
@@ -330,8 +330,8 @@ class StandardWarningsLoggingContextManager(StandardLoggingContextManager):
330 330
         return ret
331 331
 
332 332
 
333
-P = ParamSpec('P')
334
-R = TypeVar('R')
333
+P = ParamSpec("P")
334
+R = TypeVar("R")
335 335
 
336 336
 
337 337
 def adjust_logging_level(
... ...
@@ -375,9 +375,9 @@ class OptionGroupOption(click.Option):
375 375
 
376 376
     """
377 377
 
378
-    option_group_name: object = ''
378
+    option_group_name: object = ""
379 379
     """"""
380
-    epilog: object = ''
380
+    epilog: object = ""
381 381
     """"""
382 382
 
383 383
     def __init__(self, *args: Any, **kwargs: Any) -> None:  # noqa: ANN401
... ...
@@ -390,7 +390,7 @@ class OptionGroupOption(click.Option):
390 390
         # help text from the constructor arguments and re-adding it,
391 391
         # unprocessed, after constructor finishes.
392 392
         unset = object()
393
-        help = kwargs.pop('help', unset)  # noqa: A001
393
+        help = kwargs.pop("help", unset)  # noqa: A001
394 394
         super().__init__(*args, **kwargs)
395 395
         if help is not unset:  # pragma: no branch
396 396
             self.help = help
... ...
@@ -458,7 +458,7 @@ class CommandWithHelpGroups(click.Command):
458 458
     @staticmethod
459 459
     def _text(text: object, /) -> str:
460 460
         if isinstance(text, (list, tuple)):
461
-            return '\n\n'.join(str(x) for x in text)
461
+            return "\n\n".join(str(x) for x in text)
462 462
         return str(text)
463 463
 
464 464
     # This method is based on click 8.1; see the comment above the class
... ...
@@ -542,7 +542,7 @@ class CommandWithHelpGroups(click.Command):
542 542
                 self._text(self.help), limit
543 543
             )
544 544
         else:  # pragma: no cover [external-api]
545
-            text = ''
545
+            text = ""
546 546
         if self.deprecated:  # pragma: no cover [external-api]
547 547
             # Modification against click 8.1: The translated string is
548 548
             # looked up in the derivepassphrase message domain, not the
... ...
@@ -574,9 +574,9 @@ class CommandWithHelpGroups(click.Command):
574 574
         # Used to implement translatable strings, as objects that
575 575
         # stringify to the translation.
576 576
         text = (
577
-            inspect.cleandoc(self._text(self.help).partition('\f')[0])
577
+            inspect.cleandoc(self._text(self.help).partition("\f")[0])
578 578
             if self.help is not None
579
-            else ''
579
+            else ""
580 580
         )
581 581
         if self.deprecated:  # pragma: no cover [external-api]
582 582
             # Modification against click 8.1: The translated string is
... ...
@@ -623,7 +623,7 @@ class CommandWithHelpGroups(click.Command):
623 623
                 The formatter for the `--help` listing.
624 624
 
625 625
         """
626
-        default_group_name = ''
626
+        default_group_name = ""
627 627
         help_records: dict[str, list[tuple[str, str]]] = {}
628 628
         epilogs: dict[str, str] = {}
629 629
         params = self.params[:]
... ...
@@ -656,7 +656,7 @@ class CommandWithHelpGroups(click.Command):
656 656
         for group_name, records in help_records.items():
657 657
             with formatter.section(group_name):
658 658
                 formatter.write_dl(records)
659
-            epilog = inspect.cleandoc(epilogs.get(group_name, ''))
659
+            epilog = inspect.cleandoc(epilogs.get(group_name, ""))
660 660
             if epilog:
661 661
                 formatter.write_paragraph()
662 662
                 with formatter.indentation():
... ...
@@ -697,7 +697,7 @@ class CommandWithHelpGroups(click.Command):
697 697
             limit = formatter.width - 6 - len(longest_command)
698 698
             rows: list[tuple[str, str]] = []
699 699
             for subcommand, cmd in commands:
700
-                help_str = self._text(cmd.get_short_help_str(limit) or '')
700
+                help_str = self._text(cmd.get_short_help_str(limit) or "")
701 701
                 rows.append((subcommand, help_str))
702 702
             if rows:  # pragma: no branch
703 703
                 commands_label = self._text(
... ...
@@ -822,20 +822,20 @@ class DefaultToVaultGroup(CommandWithHelpGroups, click.Group):
822 822
             #
823 823
             # END modifications for derivepassphrase
824 824
             ####
825
-            if cmd_name.startswith('-'):
825
+            if cmd_name.startswith("-"):
826 826
                 self.parse_args(ctx, ctx.args)
827 827
             ####
828 828
             # BEGIN modifications for derivepassphrase
829 829
             #
830 830
             # Instead of calling ctx.fail here, default to "vault", and
831 831
             # issue a deprecation warning.
832
-            deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
832
+            deprecation = logging.getLogger(f"{PROG_NAME}.deprecation")
833 833
             deprecation.warning(
834 834
                 _msg.TranslatedString(
835 835
                     _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
836 836
                 )
837 837
             )
838
-            cmd_name = 'vault'
838
+            cmd_name = "vault"
839 839
             cmd = self.get_command(ctx, cmd_name)
840 840
             assert cmd is not None, 'Mandatory subcommand "vault" missing!'
841 841
             args = [cmd_name, *args]
... ...
@@ -984,15 +984,15 @@ def common_version_output(
984 984
     del param, value
985 985
     major_dependencies: list[str] = []
986 986
     try:
987
-        cryptography_version = importlib.metadata.version('cryptography')
987
+        cryptography_version = importlib.metadata.version("cryptography")
988 988
     except ModuleNotFoundError:
989 989
         pass
990 990
     else:
991
-        major_dependencies.append(f'cryptography {cryptography_version}')
992
-    major_dependencies.append(f'click {importlib.metadata.version("click")}')
991
+        major_dependencies.append(f"cryptography {cryptography_version}")
992
+    major_dependencies.append(f"click {importlib.metadata.version('click')}")
993 993
 
994 994
     click.echo(
995
-        ' '.join([
995
+        " ".join([
996 996
             click.style(PROG_NAME, bold=True),
997 997
             VERSION,
998 998
         ]),
... ...
@@ -1022,26 +1022,26 @@ def print_version_info_types(
1022 1022
             formatted_item_list_pieces: list[str] = []
1023 1023
             n = len(item_list)
1024 1024
             for i, item in enumerate(item_list, start=1):
1025
-                space = ' '
1026
-                punctuation = '.' if i == n else ','
1025
+                space = " "
1026
+                punctuation = "." if i == n else ","
1027 1027
                 if (
1028 1028
                     current_length + len(space) + len(item) + len(punctuation)
1029 1029
                     <= VERSION_OUTPUT_WRAPPING_WIDTH
1030 1030
                 ):
1031 1031
                     current_length += len(space) + len(item) + len(punctuation)
1032
-                    piece = f'{space}{item}{punctuation}'
1032
+                    piece = f"{space}{item}{punctuation}"
1033 1033
                 else:
1034
-                    space = '    '
1034
+                    space = "    "
1035 1035
                     current_length = len(space) + len(item) + len(punctuation)
1036
-                    piece = f'\n{space}{item}{punctuation}'
1036
+                    piece = f"\n{space}{item}{punctuation}"
1037 1037
                 formatted_item_list_pieces.append(piece)
1038 1038
             click.echo(
1039
-                ''.join([
1039
+                "".join([
1040 1040
                     click.style(
1041 1041
                         str(_msg.TranslatedString(message_label)),
1042 1042
                         bold=True,
1043 1043
                     ),
1044
-                    ''.join(formatted_item_list_pieces),
1044
+                    "".join(formatted_item_list_pieces),
1045 1045
                 ]),
1046 1046
                 color=ctx.color,
1047 1047
             )
... ...
@@ -1159,7 +1159,7 @@ def version_option(
1159 1159
     ],
1160 1160
 ) -> Callable[[Callable[P, R]], Callable[P, R]]:
1161 1161
     return click.option(
1162
-        '--version',
1162
+        "--version",
1163 1163
         is_flag=True,
1164 1164
         is_eager=True,
1165 1165
         expose_value=False,
... ...
@@ -1170,14 +1170,14 @@ def version_option(
1170 1170
 
1171 1171
 
1172 1172
 color_forcing_pseudo_option = click.option(
1173
-    '--_pseudo-option-color-forcing',
1174
-    '_color_forcing',
1173
+    "--_pseudo-option-color-forcing",
1174
+    "_color_forcing",
1175 1175
     is_flag=True,
1176 1176
     is_eager=True,
1177 1177
     expose_value=False,
1178 1178
     hidden=True,
1179 1179
     callback=color_forcing_callback,
1180
-    help='(pseudo-option)',
1180
+    help="(pseudo-option)",
1181 1181
 )
1182 1182
 
1183 1183
 
... ...
@@ -1228,12 +1228,12 @@ class LoggingOption(OptionGroupOption):
1228 1228
     """Logging options for the CLI."""
1229 1229
 
1230 1230
     option_group_name = _msg.TranslatedString(_msg.Label.LOGGING_LABEL)
1231
-    epilog = ''
1231
+    epilog = ""
1232 1232
 
1233 1233
 
1234 1234
 debug_option = click.option(
1235
-    '--debug',
1236
-    'logging_level',
1235
+    "--debug",
1236
+    "logging_level",
1237 1237
     is_flag=True,
1238 1238
     flag_value=logging.DEBUG,
1239 1239
     expose_value=False,
... ...
@@ -1242,9 +1242,9 @@ debug_option = click.option(
1242 1242
     cls=LoggingOption,
1243 1243
 )
1244 1244
 verbose_option = click.option(
1245
-    '-v',
1246
-    '--verbose',
1247
-    'logging_level',
1245
+    "-v",
1246
+    "--verbose",
1247
+    "logging_level",
1248 1248
     is_flag=True,
1249 1249
     flag_value=logging.INFO,
1250 1250
     expose_value=False,
... ...
@@ -1253,9 +1253,9 @@ verbose_option = click.option(
1253 1253
     cls=LoggingOption,
1254 1254
 )
1255 1255
 quiet_option = click.option(
1256
-    '-q',
1257
-    '--quiet',
1258
-    'logging_level',
1256
+    "-q",
1257
+    "--quiet",
1258
+    "logging_level",
1259 1259
     is_flag=True,
1260 1260
     flag_value=logging.ERROR,
1261 1261
     expose_value=False,
... ...
@@ -1324,9 +1324,9 @@ class ZshComplete(click.shell_completion.ZshComplete):
1324 1324
         non-degenerate.
1325 1325
 
1326 1326
         """
1327
-        help_ = item.help or '_'
1328
-        value = item.value.replace(':', r'\:' if help_ != '_' else ':')
1329
-        return f'{item.type}\n{value}\n{help_}'
1327
+        help_ = item.help or "_"
1328
+        value = item.value.replace(":", r"\:" if help_ != "_" else ":")
1329
+        return f"{item.type}\n{value}\n{help_}"
1330 1330
 
1331 1331
 
1332 1332
 # Our ZshComplete class depends crucially on the exact shape of the Zsh
... ...
@@ -40,7 +40,7 @@ if TYPE_CHECKING:
40 40
 
41 41
     from typing_extensions import Any, Self
42 42
 
43
-__all__ = ('PROG_NAME',)
43
+__all__ = ("PROG_NAME",)
44 44
 
45 45
 PROG_NAME = _internals.PROG_NAME
46 46
 VERSION = _internals.VERSION
... ...
@@ -88,22 +88,22 @@ def load_translations(
88 88
         # stores its packaged translations.  Then reimplement `gettext.find`
89 89
         # and `gettext.translation` with support for `importlib.resources`.
90 90
         # The heavy lifting is already being done by `locale.normalize`.
91
-        if sys.platform.startswith('win'):
91
+        if sys.platform.startswith("win"):
92 92
             xdg_data_home = (
93
-                pathlib.Path(os.environ['APPDATA'])
94
-                if os.environ.get('APPDATA')
95
-                else pathlib.Path('~').expanduser()
93
+                pathlib.Path(os.environ["APPDATA"])
94
+                if os.environ.get("APPDATA")
95
+                else pathlib.Path("~").expanduser()
96 96
             )
97
-        elif os.environ.get('XDG_DATA_HOME'):
98
-            xdg_data_home = pathlib.Path(os.environ['XDG_DATA_HOME'])
97
+        elif os.environ.get("XDG_DATA_HOME"):
98
+            xdg_data_home = pathlib.Path(os.environ["XDG_DATA_HOME"])
99 99
         else:
100 100
             xdg_data_home = (
101
-                pathlib.Path('~').expanduser() / '.local' / '.share'
101
+                pathlib.Path("~").expanduser() / ".local" / ".share"
102 102
             )
103 103
         localedirs = [
104
-            pathlib.Path(xdg_data_home, 'locale'),
105
-            pathlib.Path(sys.prefix, 'share', 'locale'),
106
-            pathlib.Path(sys.base_prefix, 'share', 'locale'),
104
+            pathlib.Path(xdg_data_home, "locale"),
105
+            pathlib.Path(sys.prefix, "share", "locale"),
106
+            pathlib.Path(sys.base_prefix, "share", "locale"),
107 107
         ]
108 108
     for localedir in localedirs:
109 109
         with contextlib.suppress(OSError):
... ...
@@ -137,13 +137,13 @@ class DebugTranslations(gettext.NullTranslations):
137 137
         cache = _debug_translation_message_cache
138 138
         for enum_class in MSG_TEMPLATE_CLASSES:
139 139
             for member in enum_class.__members__.values():
140
-                value = cast('TranslatableString', member.value)
140
+                value = cast("TranslatableString", member.value)
141 141
                 queue: list[tuple[TranslatableString, frozenset[str]]] = [
142 142
                     (value, frozenset())
143 143
                 ]
144 144
                 value2 = value.maybe_without_filename()
145 145
                 if value != value2:
146
-                    queue.append((value2, frozenset({'filename'})))
146
+                    queue.append((value2, frozenset({"filename"})))
147 147
                 for v, trimmed in queue:
148 148
                     singular = v.singular
149 149
                     plural = v.plural
... ...
@@ -158,8 +158,8 @@ class DebugTranslations(gettext.NullTranslations):
158 158
         message: str,
159 159
         /,
160 160
         *,
161
-        context: str = '',
162
-        message_plural: str = '',
161
+        context: str = "",
162
+        message_plural: str = "",
163 163
         n: int = 1,
164 164
     ) -> str:
165 165
         try:
... ...
@@ -170,7 +170,7 @@ class DebugTranslations(gettext.NullTranslations):
170 170
             return message if not message_plural or n == 1 else message_plural
171 171
         return cls._format_enum_name_maybe_with_fields(
172 172
             enum_name=str(enum_value),
173
-            ts=cast('TranslatableString', enum_value.value),
173
+            ts=cast("TranslatableString", enum_value.value),
174 174
             trimmed=trimmed,
175 175
         )
176 176
 
... ...
@@ -181,11 +181,11 @@ class DebugTranslations(gettext.NullTranslations):
181 181
         trimmed: frozenset[str] = frozenset(),
182 182
     ) -> str:
183 183
         formatted_fields = [
184
-            f'{f}=None' if f in trimmed else f'{f}={{{f}!r}}'
184
+            f"{f}=None" if f in trimmed else f"{f}={{{f}!r}}"
185 185
             for f in ts.fields()
186 186
         ]
187 187
         return (
188
-            '{}({})'.format(enum_name, ', '.join(formatted_fields))
188
+            "{}({})".format(enum_name, ", ".join(formatted_fields))
189 189
             if formatted_fields
190 190
             else str(enum_name)
191 191
         )
... ...
@@ -261,11 +261,11 @@ class TranslatableString(NamedTuple):
261 261
     """"""
262 262
     singular: str
263 263
     """"""
264
-    plural: str = ''
264
+    plural: str = ""
265 265
     """"""
266 266
     flags: frozenset[str] = frozenset()
267 267
     """"""
268
-    translator_comments: str = ''
268
+    translator_comments: str = ""
269 269
     """"""
270 270
 
271 271
     def fields(self) -> list[str]:
... ...
@@ -277,15 +277,15 @@ class TranslatableString(NamedTuple):
277 277
                 implemented.
278 278
 
279 279
         """
280
-        if 'python-format' in self.flags:  # pragma: no cover [unused]
280
+        if "python-format" in self.flags:  # pragma: no cover [unused]
281 281
             err_msg = (
282
-                'Replacement field discovery for %-formatting '
283
-                'is not implemented'
282
+                "Replacement field discovery for %-formatting "
283
+                "is not implemented"
284 284
             )
285 285
             raise NotImplementedError(err_msg)
286 286
         if (
287
-            'no-python-brace-format' in self.flags
288
-            or 'python-brace-format' not in self.flags
287
+            "no-python-brace-format" in self.flags
288
+            or "python-brace-format" not in self.flags
289 289
         ):
290 290
             return []
291 291
         formatter = string.Formatter()
... ...
@@ -303,19 +303,19 @@ class TranslatableString(NamedTuple):
303 303
         fix_sentence_endings: bool = True,
304 304
     ) -> str:
305 305
         string = inspect.cleandoc(string)
306
-        if not any(s.strip() == '\b' for s in string.splitlines()):
307
-            string = '\n'.join(
306
+        if not any(s.strip() == "\b" for s in string.splitlines()):
307
+            string = "\n".join(
308 308
                 textwrap.wrap(
309 309
                     string,
310
-                    width=float('inf'),  # type: ignore[arg-type]
310
+                    width=float("inf"),  # type: ignore[arg-type]
311 311
                     fix_sentence_endings=fix_sentence_endings,
312 312
                 )
313 313
             )
314 314
         else:
315
-            string = ''.join(
315
+            string = "".join(
316 316
                 s
317 317
                 for s in string.splitlines(True)  # noqa: FBT003
318
-                if s.strip() != '\b'
318
+                if s.strip() != "\b"
319 319
             )
320 320
         return string
321 321
 
... ...
@@ -329,7 +329,7 @@ class TranslatableString(NamedTuple):
329 329
         necessarily in other languages.
330 330
 
331 331
         """
332
-        filename_str = ': {filename!r}'
332
+        filename_str = ": {filename!r}"
333 333
         ret = self
334 334
         a, sep1, b = self.singular.partition(filename_str)
335 335
         c, sep2, d = self.plural.partition(filename_str)
... ...
@@ -369,9 +369,9 @@ class TranslatableString(NamedTuple):
369 369
 
370 370
         """
371 371
         if comments.strip() and not comments.lstrip().startswith(
372
-            'TRANSLATORS:'
372
+            "TRANSLATORS:"
373 373
         ):  # pragma: no cover [unused]
374
-            comments = 'TRANSLATORS: ' + comments.lstrip()
374
+            comments = "TRANSLATORS: " + comments.lstrip()
375 375
         comments = self._maybe_rewrap(comments, fix_sentence_endings=False)
376 376
         return self._replace(translator_comments=comments)
377 377
 
... ...
@@ -388,29 +388,29 @@ class TranslatableString(NamedTuple):
388 388
                 message for details.
389 389
 
390 390
         Examples:
391
-            >>> TranslatableString('', 'all OK').validate_flags()
391
+            >>> TranslatableString("", "all OK").validate_flags()
392 392
             ... # doctest: +NORMALIZE_WHITESPACE
393 393
             TranslatableString(l10n_context='', singular='all OK', plural='',
394 394
                                flags=frozenset(), translator_comments='')
395
-            >>> TranslatableString('', '20% OK').validate_flags(
396
-            ...     'no-python-format'
395
+            >>> TranslatableString("", "20% OK").validate_flags(
396
+            ...     "no-python-format"
397 397
             ... )
398 398
             ... # doctest: +NORMALIZE_WHITESPACE
399 399
             TranslatableString(l10n_context='', singular='20% OK', plural='',
400 400
                                flags=frozenset({'no-python-format'}),
401 401
                                translator_comments='')
402
-            >>> TranslatableString('', '%d items').validate_flags()
402
+            >>> TranslatableString("", "%d items").validate_flags()
403 403
             ... # doctest: +ELLIPSIS
404 404
             Traceback (most recent call last):
405 405
                 ...
406 406
             ValueError: Missing flag for how to deal with percent character ...
407
-            >>> TranslatableString('', '{braces}').validate_flags()
407
+            >>> TranslatableString("", "{braces}").validate_flags()
408 408
             ... # doctest: +ELLIPSIS
409 409
             Traceback (most recent call last):
410 410
                 ...
411 411
             ValueError: Missing flag for how to deal with brace character ...
412
-            >>> TranslatableString('', 'no braces').validate_flags(
413
-            ...     'python-brace-format'
412
+            >>> TranslatableString("", "no braces").validate_flags(
413
+            ...     "python-brace-format"
414 414
             ... )
415 415
             ... # doctest: +ELLIPSIS
416 416
             Traceback (most recent call last):
... ...
@@ -419,28 +419,28 @@ class TranslatableString(NamedTuple):
419 419
 
420 420
         """
421 421
         all_flags = frozenset(f.strip() for f in self.flags.union(extra_flags))
422
-        if '{' in self.singular and not bool(
423
-            all_flags & {'python-brace-format', 'no-python-brace-format'}
422
+        if "{" in self.singular and not bool(
423
+            all_flags & {"python-brace-format", "no-python-brace-format"}
424 424
         ):
425 425
             msg = (
426
-                f'Missing flag for how to deal with brace character '
427
-                f'in {self.singular!r}'
426
+                f"Missing flag for how to deal with brace character "
427
+                f"in {self.singular!r}"
428 428
             )
429 429
             raise ValueError(msg)
430
-        if '%' in self.singular and not bool(
431
-            all_flags & {'python-format', 'no-python-format'}
430
+        if "%" in self.singular and not bool(
431
+            all_flags & {"python-format", "no-python-format"}
432 432
         ):
433 433
             msg = (
434
-                f'Missing flag for how to deal with percent character '
435
-                f'in {self.singular!r}'
434
+                f"Missing flag for how to deal with percent character "
435
+                f"in {self.singular!r}"
436 436
             )
437 437
             raise ValueError(msg)
438 438
         if (
439
-            all_flags & {'python-format', 'python-brace-format'}
440
-            and '%' not in self.singular
441
-            and '{' not in self.singular
439
+            all_flags & {"python-format", "python-brace-format"}
440
+            and "%" not in self.singular
441
+            and "{" not in self.singular
442 442
         ):
443
-            msg = f'Missing format string parameters in {self.singular!r}'
443
+            msg = f"Missing format string parameters in {self.singular!r}"
444 444
             raise ValueError(msg)
445 445
         return self._replace(flags=all_flags)
446 446
 
... ...
@@ -450,8 +450,8 @@ def translatable(
450 450
     single: str,
451 451
     /,
452 452
     flags: Iterable[str] = (),
453
-    plural: str = '',
454
-    comments: str = '',
453
+    plural: str = "",
454
+    comments: str = "",
455 455
 ) -> TranslatableString:
456 456
     """Return a [`TranslatableString`][] with validated parts.
457 457
 
... ...
@@ -502,7 +502,7 @@ class TranslatedString:
502 502
 
503 503
         """
504 504
         if isinstance(template, MSG_TEMPLATE_CLASSES):
505
-            template = cast('TranslatableString', template.value)
505
+            template = cast("TranslatableString", template.value)
506 506
         self.template = template
507 507
         self.kwargs = {**args_dict, **kwargs}
508 508
         self._rendered: str | None = None
... ...
@@ -522,8 +522,8 @@ class TranslatedString:
522 522
     def __repr__(self) -> str:  # pragma: no cover [debug]
523 523
         """"""  # noqa: D419
524 524
         return (
525
-            f'{self.__class__.__name__}({self.template!r}, '
526
-            f'{dict(self.kwargs)!r})'
525
+            f"{self.__class__.__name__}({self.template!r}, "
526
+            f"{dict(self.kwargs)!r})"
527 527
         )
528 528
 
529 529
     def __str__(self) -> str:
... ...
@@ -537,12 +537,12 @@ class TranslatedString:
537 537
         if self._rendered is None:
538 538
             do_escape = False
539 539
             if isinstance(self.template, str):
540
-                context = ''
540
+                context = ""
541 541
                 template = self.template
542 542
             else:
543 543
                 context = self.template.l10n_context
544 544
                 template = self.template.singular
545
-                do_escape = 'no-python-brace-format' in self.template.flags
545
+                do_escape = "no-python-brace-format" in self.template.flags
546 546
             template = (
547 547
                 translation.pgettext(context, template)
548 548
                 if context
... ...
@@ -559,8 +559,8 @@ class TranslatedString:
559 559
     @staticmethod
560 560
     def _escape(template: str) -> str:
561 561
         return template.translate({
562
-            ord('{'): '{{',
563
-            ord('}'): '}}',
562
+            ord("{"): "{{",
563
+            ord("}"): "}}",
564 564
         })
565 565
 
566 566
     @classmethod
... ...
@@ -583,7 +583,7 @@ class TranslatedString:
583 583
         )
584 584
         if (
585 585
             not isinstance(new_template, str)
586
-            and self.kwargs.get('filename') is None
586
+            and self.kwargs.get("filename") is None
587 587
             and new_template != self.template
588 588
         ):
589 589
             return self.__class__(new_template, self.kwargs)
... ...
@@ -599,8 +599,8 @@ class TranslatableStringConstructor(Protocol):
599 599
         single: str,
600 600
         /,
601 601
         flags: Iterable[str] = (),
602
-        plural: str = '',
603
-        comments: str = '',
602
+        plural: str = "",
603
+        comments: str = "",
604 604
     ) -> TranslatableString:
605 605
         """Return a [`TranslatableString`][] from these parts.
606 606
 
... ...
@@ -612,7 +612,7 @@ class TranslatableStringConstructor(Protocol):
612 612
         """
613 613
 
614 614
 
615
-def commented(comments: str = '', /) -> TranslatableStringConstructor:
615
+def commented(comments: str = "", /) -> TranslatableStringConstructor:
616 616
     """A "decorator" for readably constructing commented enum values.
617 617
 
618 618
     Returns a partial application of [`translatable`][] with the `comments`
... ...
@@ -640,161 +640,161 @@ class Label(enum.Enum):
640 640
     """
641 641
 
642 642
     DEPRECATION_WARNING_LABEL = commented(
643
-        'This is a short label that will be prepended to '
643
+        "This is a short label that will be prepended to "
644 644
         'a warning message, e.g., "Deprecation warning: A subcommand '
645 645
         'will be required in v1.0."',
646 646
     )(
647
-        'Label :: Diagnostics :: Marker',
648
-        'Deprecation warning',
647
+        "Label :: Diagnostics :: Marker",
648
+        "Deprecation warning",
649 649
     )
650 650
     """"""
651 651
     WARNING_LABEL = commented(
652
-        'This is a short label that will be prepended to '
652
+        "This is a short label that will be prepended to "
653 653
         'a warning message, e.g., "Warning: An empty service name '
654 654
         'is not supported by vault(1)."',
655 655
     )(
656
-        'Label :: Diagnostics :: Marker',
657
-        'Warning',
656
+        "Label :: Diagnostics :: Marker",
657
+        "Warning",
658 658
     )
659 659
     """"""
660 660
     CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_GLOBAL = commented(
661
-        'This is one of two values of the settings_type metavar '
662
-        'used in the CANNOT_UPDATE_SETTINGS_NO_SETTINGS entry.  '
663
-        'It is only used there.  '
664
-        'The full sentence then reads: '
661
+        "This is one of two values of the settings_type metavar "
662
+        "used in the CANNOT_UPDATE_SETTINGS_NO_SETTINGS entry.  "
663
+        "It is only used there.  "
664
+        "The full sentence then reads: "
665 665
         '"Cannot update the global settings without any given settings."',
666 666
     )(
667
-        'Label :: Error message :: Metavar',
668
-        'global settings',
667
+        "Label :: Error message :: Metavar",
668
+        "global settings",
669 669
     )
670 670
     """"""
671 671
     CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_SERVICE = commented(
672
-        'This is one of two values of the settings_type metavar '
673
-        'used in the CANNOT_UPDATE_SETTINGS_NO_SETTINGS entry.  '
674
-        'It is only used there.  '
675
-        'The full sentence then reads: '
672
+        "This is one of two values of the settings_type metavar "
673
+        "used in the CANNOT_UPDATE_SETTINGS_NO_SETTINGS entry.  "
674
+        "It is only used there.  "
675
+        "The full sentence then reads: "
676 676
         '"Cannot update the service-specific settings without any '
677 677
         'given settings."',
678 678
     )(
679
-        'Label :: Error message :: Metavar',
680
-        'service-specific settings',
679
+        "Label :: Error message :: Metavar",
680
+        "service-specific settings",
681 681
     )
682 682
     """"""
683 683
     SETTINGS_ORIGIN_INTERACTIVE = commented(
684
-        'This value is used as the {key} metavar for '
685
-        'Label.PASSPHRASE_NOT_NORMALIZED if the passphrase was '
686
-        'entered interactively.',
684
+        "This value is used as the {key} metavar for "
685
+        "Label.PASSPHRASE_NOT_NORMALIZED if the passphrase was "
686
+        "entered interactively.",
687 687
     )(
688
-        'Label :: Error message :: Metavar',
689
-        'interactive input',
688
+        "Label :: Error message :: Metavar",
689
+        "interactive input",
690 690
     )
691 691
     CONFIGURATION_EPILOG = commented(
692
-        '',
692
+        "",
693 693
     )(
694
-        'Label :: Help text :: Explanation',
695
-        'Use $VISUAL or $EDITOR to configure the spawned editor.',
694
+        "Label :: Help text :: Explanation",
695
+        "Use $VISUAL or $EDITOR to configure the spawned editor.",
696 696
     )
697 697
     """"""
698 698
     DERIVEPASSPHRASE_02 = commented(
699
-        '',
699
+        "",
700 700
     )(
701
-        'Label :: Help text :: Explanation',
701
+        "Label :: Help text :: Explanation",
702 702
         'The currently implemented subcommands are "vault" '
703 703
         '(for the scheme used by vault) and "export" '
704
-        '(for exporting foreign configuration data).  '
705
-        'See the respective `--help` output for instructions.  '
704
+        "(for exporting foreign configuration data).  "
705
+        "See the respective `--help` output for instructions.  "
706 706
         'If no subcommand is given, we default to "vault".',
707 707
     )
708 708
     """"""
709 709
     DERIVEPASSPHRASE_03 = commented(
710
-        '',
710
+        "",
711 711
     )(
712
-        'Label :: Help text :: Explanation',
712
+        "Label :: Help text :: Explanation",
713 713
         'Deprecation notice: Defaulting to "vault" is deprecated.  '
714
-        'Starting in v1.0, the subcommand must be specified explicitly.',
714
+        "Starting in v1.0, the subcommand must be specified explicitly.",
715 715
     )
716 716
     """"""
717 717
     DERIVEPASSPHRASE_EPILOG_01 = commented(
718
-        '',
718
+        "",
719 719
     )(
720
-        'Label :: Help text :: Explanation',
721
-        'Configuration is stored in a directory according to the '
722
-        '`DERIVEPASSPHRASE_PATH` variable, which defaults to '
723
-        '`~/.derivepassphrase` on UNIX-like systems and '
724
-        r'`C:\Users\<user>\AppData\Roaming\Derivepassphrase` on Windows.',
720
+        "Label :: Help text :: Explanation",
721
+        "Configuration is stored in a directory according to the "
722
+        "`DERIVEPASSPHRASE_PATH` variable, which defaults to "
723
+        "`~/.derivepassphrase` on UNIX-like systems and "
724
+        r"`C:\Users\<user>\AppData\Roaming\Derivepassphrase` on Windows.",
725 725
     )
726 726
     """"""
727 727
     DERIVEPASSPHRASE_EXPORT_02 = commented(
728
-        '',
728
+        "",
729 729
     )(
730
-        'Label :: Help text :: Explanation',
730
+        "Label :: Help text :: Explanation",
731 731
         'The only available subcommand is "vault", '
732
-        'which implements the vault-native configuration scheme.  '
732
+        "which implements the vault-native configuration scheme.  "
733 733
         'If no subcommand is given, we default to "vault".',
734 734
     )
735 735
     """"""
736 736
     DERIVEPASSPHRASE_EXPORT_03 = DERIVEPASSPHRASE_03
737 737
     """"""
738 738
     DERIVEPASSPHRASE_EXPORT_VAULT_02 = commented(
739
-        'The metavar is Label.EXPORT_VAULT_METAVAR_PATH.',
739
+        "The metavar is Label.EXPORT_VAULT_METAVAR_PATH.",
740 740
     )(
741
-        'Label :: Help text :: Explanation',
742
-        'Depending on the configuration format, '
743
-        '{path_metavar} may either be a file or a directory.  '
741
+        "Label :: Help text :: Explanation",
742
+        "Depending on the configuration format, "
743
+        "{path_metavar} may either be a file or a directory.  "
744 744
         'We support the vault "v0.2", "v0.3" and "storeroom" formats.',
745
-        flags='python-brace-format',
745
+        flags="python-brace-format",
746 746
     )
747 747
     """"""
748 748
     DERIVEPASSPHRASE_EXPORT_VAULT_03 = commented(
749
-        'The metavar is Label.EXPORT_VAULT_METAVAR_PATH.',
749
+        "The metavar is Label.EXPORT_VAULT_METAVAR_PATH.",
750 750
     )(
751
-        'Label :: Help text :: Explanation',
752
-        'If {path_metavar} is explicitly given as `VAULT_PATH`, '
753
-        'then use the `VAULT_PATH` environment variable to '
754
-        'determine the correct path.  '
755
-        '(Use `./VAULT_PATH` or similar to indicate a file/directory '
756
-        'actually named `VAULT_PATH`.)',
757
-        flags='python-brace-format',
751
+        "Label :: Help text :: Explanation",
752
+        "If {path_metavar} is explicitly given as `VAULT_PATH`, "
753
+        "then use the `VAULT_PATH` environment variable to "
754
+        "determine the correct path.  "
755
+        "(Use `./VAULT_PATH` or similar to indicate a file/directory "
756
+        "actually named `VAULT_PATH`.)",
757
+        flags="python-brace-format",
758 758
     )
759 759
     """"""
760 760
     DERIVEPASSPHRASE_VAULT_02 = commented(
761
-        'The metavar is Label.VAULT_METAVAR_SERVICE.',
761
+        "The metavar is Label.VAULT_METAVAR_SERVICE.",
762 762
     )(
763
-        'Label :: Help text :: Explanation',
764
-        'If operating on global settings, or importing/exporting settings, '
765
-        'then {service_metavar} must be omitted.  '
766
-        'Otherwise it is required.',
767
-        flags='python-brace-format',
763
+        "Label :: Help text :: Explanation",
764
+        "If operating on global settings, or importing/exporting settings, "
765
+        "then {service_metavar} must be omitted.  "
766
+        "Otherwise it is required.",
767
+        flags="python-brace-format",
768 768
     )
769 769
     """"""
770 770
     DERIVEPASSPHRASE_VAULT_EPILOG_01 = commented(
771
-        '',
771
+        "",
772 772
     )(
773
-        'Label :: Help text :: Explanation',
774
-        'WARNING: There is NO WAY to retrieve the generated passphrases '
775
-        'if the master passphrase, the SSH key, or the exact '
776
-        'passphrase settings are lost, '
777
-        'short of trying out all possible combinations.  '
778
-        'You are STRONGLY advised to keep independent backups of '
779
-        'the settings and the SSH key, if any.',
773
+        "Label :: Help text :: Explanation",
774
+        "WARNING: There is NO WAY to retrieve the generated passphrases "
775
+        "if the master passphrase, the SSH key, or the exact "
776
+        "passphrase settings are lost, "
777
+        "short of trying out all possible combinations.  "
778
+        "You are STRONGLY advised to keep independent backups of "
779
+        "the settings and the SSH key, if any.",
780 780
     )
781 781
     """"""
782 782
     DERIVEPASSPHRASE_VAULT_EPILOG_02 = commented(
783
-        '',
783
+        "",
784 784
     )(
785
-        'Label :: Help text :: Explanation',
786
-        'The configuration is NOT encrypted, and you are '
787
-        'STRONGLY discouraged from using a stored passphrase.',
785
+        "Label :: Help text :: Explanation",
786
+        "The configuration is NOT encrypted, and you are "
787
+        "STRONGLY discouraged from using a stored passphrase.",
788 788
     )
789 789
     """"""
790 790
     DERIVEPASSPHRASE_VAULT_NOTES_INSTRUCTION_TEXT = commented(
791 791
         "This instruction text is shown above the user's old stored notes "
792
-        'for this service, if any, if the recommended '
792
+        "for this service, if any, if the recommended "
793 793
         '"modern" editor interface is used.  '
794
-        'The next line is the cut marking defined in '
795
-        'Label.DERIVEPASSPHRASE_VAULT_NOTES_MARKER.'
794
+        "The next line is the cut marking defined in "
795
+        "Label.DERIVEPASSPHRASE_VAULT_NOTES_MARKER."
796 796
     )(
797
-        'Label :: Help text :: Explanation',
797
+        "Label :: Help text :: Explanation",
798 798
         """\
799 799
 \b
800 800
 # Enter notes below the line with the cut mark (ASCII scissors and
... ...
@@ -809,591 +809,591 @@ class Label(enum.Enum):
809 809
     )
810 810
     """"""
811 811
     DERIVEPASSPHRASE_VAULT_NOTES_LEGACY_INSTRUCTION_TEXT = commented(
812
-        'This instruction text is shown if the vault(1)-compatible '
812
+        "This instruction text is shown if the vault(1)-compatible "
813 813
         '"legacy" editor interface is used and no previous notes exist.  '
814
-        'The interface does not support commentary in the notes, '
815
-        'so we fill this with obvious placeholder text instead.  '
816
-        '(Please replace this with what *your* language/culture would '
817
-        'obviously recognize as placeholder text.)'
814
+        "The interface does not support commentary in the notes, "
815
+        "so we fill this with obvious placeholder text instead.  "
816
+        "(Please replace this with what *your* language/culture would "
817
+        "obviously recognize as placeholder text.)"
818 818
     )(
819
-        'Label :: Help text :: Explanation',
820
-        'INSERT NOTES HERE',
819
+        "Label :: Help text :: Explanation",
820
+        "INSERT NOTES HERE",
821 821
     )
822 822
     """"""
823 823
     PASSPHRASE_GENERATION_EPILOG = commented(
824
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
824
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
825 825
     )(
826
-        'Label :: Help text :: Explanation',
827
-        'Use {metavar}=0 to exclude a character type from the output.',
828
-        flags='python-brace-format',
826
+        "Label :: Help text :: Explanation",
827
+        "Use {metavar}=0 to exclude a character type from the output.",
828
+        flags="python-brace-format",
829 829
     )
830 830
     """"""
831 831
     STORAGE_MANAGEMENT_EPILOG = commented(
832
-        'The metavar is Label.STORAGE_MANAGEMENT_METAVAR_PATH.',
832
+        "The metavar is Label.STORAGE_MANAGEMENT_METAVAR_PATH.",
833 833
     )(
834
-        'Label :: Help text :: Explanation',
834
+        "Label :: Help text :: Explanation",
835 835
         'Using "-" as {metavar} for standard input/standard output '
836
-        'is supported.',
837
-        flags='python-brace-format',
836
+        "is supported.",
837
+        flags="python-brace-format",
838 838
     )
839 839
     """"""
840 840
     DEPRECATED_COMMAND_LABEL = commented(
841
-        'We use this format string to indicate, at the beginning '
841
+        "We use this format string to indicate, at the beginning "
842 842
         "of a command's help text, that this command is deprecated.",
843 843
     )(
844
-        'Label :: Help text :: Marker',
845
-        '(Deprecated) {text}',
846
-        flags='python-brace-format',
844
+        "Label :: Help text :: Marker",
845
+        "(Deprecated) {text}",
846
+        flags="python-brace-format",
847 847
     )
848 848
     """"""
849 849
     DERIVEPASSPHRASE_VAULT_NOTES_MARKER = commented(
850
-        'The marker for separating the text from '
851
-        'Label.DERIVEPASSPHRASE_VAULT_NOTES_INSTRUCTION_TEXT '
850
+        "The marker for separating the text from "
851
+        "Label.DERIVEPASSPHRASE_VAULT_NOTES_INSTRUCTION_TEXT "
852 852
         "from the user's input (below the marker).  "
853
-        'The first line starting with this label marks the separation point.',
853
+        "The first line starting with this label marks the separation point.",
854 854
     )(
855
-        'Label :: Help text :: Marker',
856
-        '# - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -',
855
+        "Label :: Help text :: Marker",
856
+        "# - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -",
857 857
     )
858 858
     """"""
859 859
     EXPORT_VAULT_FORMAT_METAVAR_FMT = commented(
860
-        'This text is used as {metavar} in '
861
-        'Label.EXPORT_VAULT_FORMAT_HELP_TEXT, yielding e.g. '
860
+        "This text is used as {metavar} in "
861
+        "Label.EXPORT_VAULT_FORMAT_HELP_TEXT, yielding e.g. "
862 862
         '"Try the following storage format FMT."',
863 863
     )(
864
-        'Label :: Help text :: Metavar :: export vault',
865
-        'FMT',
864
+        "Label :: Help text :: Metavar :: export vault",
865
+        "FMT",
866 866
     )
867 867
     """"""
868 868
     EXPORT_VAULT_KEY_METAVAR_K = commented(
869
-        'This text is used as {metavar} in '
870
-        'Label.EXPORT_VAULT_KEY_HELP_TEXT, yielding e.g. '
869
+        "This text is used as {metavar} in "
870
+        "Label.EXPORT_VAULT_KEY_HELP_TEXT, yielding e.g. "
871 871
         '"Use K as the storage master key."',
872 872
     )(
873
-        'Label :: Help text :: Metavar :: export vault',
874
-        'K',
873
+        "Label :: Help text :: Metavar :: export vault",
874
+        "K",
875 875
     )
876 876
     """"""
877 877
     EXPORT_VAULT_METAVAR_PATH = commented(
878 878
         'Used as "path_metavar" in '
879
-        'Label.DERIVEPASSPHRASE_EXPORT_VAULT_02 and others, '
879
+        "Label.DERIVEPASSPHRASE_EXPORT_VAULT_02 and others, "
880 880
         'yielding e.g. "Depending on the configuration format, '
881 881
         'PATH may either be a file or a directory."',
882 882
     )(
883
-        'Label :: Help text :: Metavar :: export vault',
884
-        'PATH',
883
+        "Label :: Help text :: Metavar :: export vault",
884
+        "PATH",
885 885
     )
886 886
     """"""
887 887
     PASSPHRASE_GENERATION_METAVAR_NUMBER = commented(
888
-        'This metavar is used in Label.PASSPHRASE_GENERATION_EPILOG, '
889
-        'Label.DERIVEPASSPHRASE_VAULT_LENGTH_HELP_TEXT and others, '
888
+        "This metavar is used in Label.PASSPHRASE_GENERATION_EPILOG, "
889
+        "Label.DERIVEPASSPHRASE_VAULT_LENGTH_HELP_TEXT and others, "
890 890
         'yielding e.g. "Ensure a passphrase length of NUMBER characters.".  ',
891 891
     )(
892
-        'Label :: Help text :: Metavar :: vault',
893
-        'NUMBER',
892
+        "Label :: Help text :: Metavar :: vault",
893
+        "NUMBER",
894 894
     )
895 895
     """"""
896 896
     STORAGE_MANAGEMENT_METAVAR_PATH = commented(
897
-        'This metavar is used in Label.STORAGE_MANAGEMENT_EPILOG, '
898
-        'Label.DERIVEPASSPHRASE_VAULT_IMPORT_HELP_TEXT and others, '
897
+        "This metavar is used in Label.STORAGE_MANAGEMENT_EPILOG, "
898
+        "Label.DERIVEPASSPHRASE_VAULT_IMPORT_HELP_TEXT and others, "
899 899
         'yielding e.g. "Ensure a passphrase length of NUMBER characters.".  ',
900 900
     )(
901
-        'Label :: Help text :: Metavar :: vault',
902
-        'PATH',
901
+        "Label :: Help text :: Metavar :: vault",
902
+        "PATH",
903 903
     )
904 904
     """"""
905 905
     VAULT_METAVAR_SERVICE = commented(
906 906
         'This metavar is used as "service_metavar" in multiple help texts, '
907
-        'such as Label.DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT, '
908
-        'Label.DERIVEPASSPHRASE_VAULT_02, ErrMsgTemplate.SERVICE_REQUIRED, '
907
+        "such as Label.DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT, "
908
+        "Label.DERIVEPASSPHRASE_VAULT_02, ErrMsgTemplate.SERVICE_REQUIRED, "
909 909
         'etc.  Sample texts are "Deriving a passphrase requires a SERVICE.", '
910 910
         '"save the given settings for SERVICE, or global" and '
911 911
         '"If operating on global settings, or importing/exporting settings, '
912 912
         'then SERVICE must be omitted."',
913 913
     )(
914
-        'Label :: Help text :: Metavar :: vault',
915
-        'SERVICE',
914
+        "Label :: Help text :: Metavar :: vault",
915
+        "SERVICE",
916 916
     )
917 917
     """"""
918 918
     DEBUG_OPTION_HELP_TEXT = commented(
919
-        '',
919
+        "",
920 920
     )(
921
-        'Label :: Help text :: One-line description',
922
-        'Also emit debug information.  Implies --verbose.',
921
+        "Label :: Help text :: One-line description",
922
+        "Also emit debug information.  Implies --verbose.",
923 923
     )
924 924
     """"""
925 925
     DERIVEPASSPHRASE_01 = commented(
926
-        'This is the first paragraph of the command help text, '
927
-        'but it also appears (in truncated form, if necessary) '
928
-        'as one-line help text for this command.  '
929
-        'The translation should thus be as meaningful as possible '
930
-        'even if truncated.',
926
+        "This is the first paragraph of the command help text, "
927
+        "but it also appears (in truncated form, if necessary) "
928
+        "as one-line help text for this command.  "
929
+        "The translation should thus be as meaningful as possible "
930
+        "even if truncated.",
931 931
     )(
932
-        'Label :: Help text :: One-line description',
933
-        'Derive a strong passphrase, deterministically, from a master secret.',
932
+        "Label :: Help text :: One-line description",
933
+        "Derive a strong passphrase, deterministically, from a master secret.",
934 934
     )
935 935
     """"""
936 936
     DERIVEPASSPHRASE_EXPORT_01 = commented(
937
-        'This is the first paragraph of the command help text, '
938
-        'but it also appears (in truncated form, if necessary) '
939
-        'as one-line help text for this command.  '
940
-        'The translation should thus be as meaningful as possible '
941
-        'even if truncated.',
937
+        "This is the first paragraph of the command help text, "
938
+        "but it also appears (in truncated form, if necessary) "
939
+        "as one-line help text for this command.  "
940
+        "The translation should thus be as meaningful as possible "
941
+        "even if truncated.",
942 942
     )(
943
-        'Label :: Help text :: One-line description',
944
-        'Export a foreign configuration to standard output.',
943
+        "Label :: Help text :: One-line description",
944
+        "Export a foreign configuration to standard output.",
945 945
     )
946 946
     """"""
947 947
     DERIVEPASSPHRASE_EXPORT_VAULT_01 = commented(
948
-        'This is the first paragraph of the command help text, '
949
-        'but it also appears (in truncated form, if necessary) '
950
-        'as one-line help text for this command.  '
951
-        'The translation should thus be as meaningful as possible '
952
-        'even if truncated.',
948
+        "This is the first paragraph of the command help text, "
949
+        "but it also appears (in truncated form, if necessary) "
950
+        "as one-line help text for this command.  "
951
+        "The translation should thus be as meaningful as possible "
952
+        "even if truncated.",
953 953
     )(
954
-        'Label :: Help text :: One-line description',
955
-        'Export a vault-native configuration to standard output.',
954
+        "Label :: Help text :: One-line description",
955
+        "Export a vault-native configuration to standard output.",
956 956
     )
957 957
     """"""
958 958
     DERIVEPASSPHRASE_VAULT_01 = commented(
959
-        'This is the first paragraph of the command help text, '
960
-        'but it also appears (in truncated form, if necessary) '
961
-        'as one-line help text for this command.  '
962
-        'The translation should thus be as meaningful as possible '
963
-        'even if truncated.',
959
+        "This is the first paragraph of the command help text, "
960
+        "but it also appears (in truncated form, if necessary) "
961
+        "as one-line help text for this command.  "
962
+        "The translation should thus be as meaningful as possible "
963
+        "even if truncated.",
964 964
     )(
965
-        'Label :: Help text :: One-line description',
966
-        'Derive a passphrase using the vault derivation scheme.',
965
+        "Label :: Help text :: One-line description",
966
+        "Derive a passphrase using the vault derivation scheme.",
967 967
     )
968 968
     """"""
969 969
     DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT = commented(
970
-        'The metavar is Label.VAULT_METAVAR_SERVICE.',
970
+        "The metavar is Label.VAULT_METAVAR_SERVICE.",
971 971
     )(
972
-        'Label :: Help text :: One-line description',
973
-        'Save the given settings for {service_metavar}, or global.',
974
-        flags='python-brace-format',
972
+        "Label :: Help text :: One-line description",
973
+        "Save the given settings for {service_metavar}, or global.",
974
+        flags="python-brace-format",
975 975
     )
976 976
     """"""
977 977
     DERIVEPASSPHRASE_VAULT_DASH_HELP_TEXT = commented(
978
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
978
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
979 979
     )(
980
-        'Label :: Help text :: One-line description',
980
+        "Label :: Help text :: One-line description",
981 981
         'Ensure at least {metavar} "-" or "_" characters.',
982
-        flags='python-brace-format',
982
+        flags="python-brace-format",
983 983
     )
984 984
     """"""
985 985
     DERIVEPASSPHRASE_VAULT_DELETE_ALL_HELP_TEXT = commented(
986
-        '',
986
+        "",
987 987
     )(
988
-        'Label :: Help text :: One-line description',
989
-        'Delete all settings.',
988
+        "Label :: Help text :: One-line description",
989
+        "Delete all settings.",
990 990
     )
991 991
     """"""
992 992
     DERIVEPASSPHRASE_VAULT_DELETE_GLOBALS_HELP_TEXT = commented(
993
-        '',
993
+        "",
994 994
     )(
995
-        'Label :: Help text :: One-line description',
996
-        'Delete the global settings.',
995
+        "Label :: Help text :: One-line description",
996
+        "Delete the global settings.",
997 997
     )
998 998
     """"""
999 999
     DERIVEPASSPHRASE_VAULT_DELETE_HELP_TEXT = commented(
1000
-        'The metavar is Label.VAULT_METAVAR_SERVICE.',
1000
+        "The metavar is Label.VAULT_METAVAR_SERVICE.",
1001 1001
     )(
1002
-        'Label :: Help text :: One-line description',
1003
-        'Delete the settings for {service_metavar}.',
1004
-        flags='python-brace-format',
1002
+        "Label :: Help text :: One-line description",
1003
+        "Delete the settings for {service_metavar}.",
1004
+        flags="python-brace-format",
1005 1005
     )
1006 1006
     """"""
1007 1007
     DERIVEPASSPHRASE_VAULT_EDITOR_INTERFACE_HELP_TEXT = commented(
1008
-        'The corresponding option is displayed as '
1008
+        "The corresponding option is displayed as "
1009 1009
         '"--modern-editor-interface / --vault-legacy-editor-interface", '
1010
-        'so you may want to hint that the default (legacy) '
1011
-        'is the second of those options.  '
1012
-        'Though the vault(1) legacy editor interface clearly has deficiencies '
1013
-        'and (in my opinion) should only be used for compatibility purposes, '
1014
-        'the one-line help text should try not to sound too judgmental, '
1015
-        'if possible.',
1010
+        "so you may want to hint that the default (legacy) "
1011
+        "is the second of those options.  "
1012
+        "Though the vault(1) legacy editor interface clearly has deficiencies "
1013
+        "and (in my opinion) should only be used for compatibility purposes, "
1014
+        "the one-line help text should try not to sound too judgmental, "
1015
+        "if possible.",
1016 1016
     )(
1017
-        'Label :: Help text :: One-line description',
1018
-        'Edit notes using the modern editor interface '
1019
-        'or the vault-like legacy one (default).',
1017
+        "Label :: Help text :: One-line description",
1018
+        "Edit notes using the modern editor interface "
1019
+        "or the vault-like legacy one (default).",
1020 1020
     )
1021 1021
     """"""
1022 1022
     DERIVEPASSPHRASE_VAULT_EXPORT_AS_HELP_TEXT = commented(
1023
-        'The corresponding option is displayed as '
1023
+        "The corresponding option is displayed as "
1024 1024
         '"--export-as=json|sh", so json refers to the JSON format (default) '
1025
-        'and sh refers to the POSIX sh format.  '
1025
+        "and sh refers to the POSIX sh format.  "
1026 1026
         'Please ensure that it is clear what the "json" and "sh" refer to '
1027
-        'in your translation... even if you cannot use texutal correspondence '
1028
-        'like the English text does.',
1027
+        "in your translation... even if you cannot use texutal correspondence "
1028
+        "like the English text does.",
1029 1029
     )(
1030
-        'Label :: Help text :: One-line description',
1031
-        'When exporting, export as JSON (default) or as POSIX sh.',
1030
+        "Label :: Help text :: One-line description",
1031
+        "When exporting, export as JSON (default) or as POSIX sh.",
1032 1032
     )
1033 1033
     """"""
1034 1034
     DERIVEPASSPHRASE_VAULT_EXPORT_HELP_TEXT = commented(
1035
-        'The metavar is Label.STORAGE_MANAGEMENT_METAVAR_PATH.',
1035
+        "The metavar is Label.STORAGE_MANAGEMENT_METAVAR_PATH.",
1036 1036
     )(
1037
-        'Label :: Help text :: One-line description',
1038
-        'Export all saved settings to {metavar}.',
1039
-        flags='python-brace-format',
1037
+        "Label :: Help text :: One-line description",
1038
+        "Export all saved settings to {metavar}.",
1039
+        flags="python-brace-format",
1040 1040
     )
1041 1041
     """"""
1042 1042
     DERIVEPASSPHRASE_VAULT_IMPORT_HELP_TEXT = commented(
1043
-        'The metavar is Label.STORAGE_MANAGEMENT_METAVAR_PATH.',
1043
+        "The metavar is Label.STORAGE_MANAGEMENT_METAVAR_PATH.",
1044 1044
     )(
1045
-        'Label :: Help text :: One-line description',
1046
-        'Import saved settings from {metavar}.',
1047
-        flags='python-brace-format',
1045
+        "Label :: Help text :: One-line description",
1046
+        "Import saved settings from {metavar}.",
1047
+        flags="python-brace-format",
1048 1048
     )
1049 1049
     """"""
1050 1050
     DERIVEPASSPHRASE_VAULT_KEY_HELP_TEXT = commented(
1051
-        '',
1051
+        "",
1052 1052
     )(
1053
-        'Label :: Help text :: One-line description',
1054
-        'Select a suitable SSH key from the SSH agent.',
1053
+        "Label :: Help text :: One-line description",
1054
+        "Select a suitable SSH key from the SSH agent.",
1055 1055
     )
1056 1056
     """"""
1057 1057
     DERIVEPASSPHRASE_VAULT_LENGTH_HELP_TEXT = commented(
1058
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
1058
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
1059 1059
     )(
1060
-        'Label :: Help text :: One-line description',
1061
-        'Ensure a passphrase length of {metavar} characters.',
1062
-        flags='python-brace-format',
1060
+        "Label :: Help text :: One-line description",
1061
+        "Ensure a passphrase length of {metavar} characters.",
1062
+        flags="python-brace-format",
1063 1063
     )
1064 1064
     """"""
1065 1065
     DERIVEPASSPHRASE_VAULT_LOWER_HELP_TEXT = commented(
1066
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
1066
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
1067 1067
     )(
1068
-        'Label :: Help text :: One-line description',
1069
-        'Ensure at least {metavar} lowercase characters.',
1070
-        flags='python-brace-format',
1068
+        "Label :: Help text :: One-line description",
1069
+        "Ensure at least {metavar} lowercase characters.",
1070
+        flags="python-brace-format",
1071 1071
     )
1072 1072
     """"""
1073 1073
     DERIVEPASSPHRASE_VAULT_NOTES_HELP_TEXT = commented(
1074
-        'The metavar is Label.VAULT_METAVAR_SERVICE.',
1074
+        "The metavar is Label.VAULT_METAVAR_SERVICE.",
1075 1075
     )(
1076
-        'Label :: Help text :: One-line description',
1077
-        'With --config and {service_metavar}, spawn an editor to edit notes.',
1078
-        flags='python-brace-format',
1076
+        "Label :: Help text :: One-line description",
1077
+        "With --config and {service_metavar}, spawn an editor to edit notes.",
1078
+        flags="python-brace-format",
1079 1079
     )
1080 1080
     """"""
1081 1081
     DERIVEPASSPHRASE_VAULT_NUMBER_HELP_TEXT = commented(
1082
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
1082
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
1083 1083
     )(
1084
-        'Label :: Help text :: One-line description',
1085
-        'Ensure at least {metavar} digits.',
1086
-        flags='python-brace-format',
1084
+        "Label :: Help text :: One-line description",
1085
+        "Ensure at least {metavar} digits.",
1086
+        flags="python-brace-format",
1087 1087
     )
1088 1088
     """"""
1089 1089
     DERIVEPASSPHRASE_VAULT_OVERWRITE_HELP_TEXT = commented(
1090
-        'The corresponding option is displayed as '
1090
+        "The corresponding option is displayed as "
1091 1091
         '"--overwrite-existing / --merge-existing", so you may want to '
1092
-        'hint that the default (merge) is the second of those options.',
1092
+        "hint that the default (merge) is the second of those options.",
1093 1093
     )(
1094
-        'Label :: Help text :: One-line description',
1095
-        'Overwrite or merge (default) the existing configuration.',
1094
+        "Label :: Help text :: One-line description",
1095
+        "Overwrite or merge (default) the existing configuration.",
1096 1096
     )
1097 1097
     """"""
1098 1098
     DERIVEPASSPHRASE_VAULT_PHRASE_HELP_TEXT = commented(
1099
-        '',
1099
+        "",
1100 1100
     )(
1101
-        'Label :: Help text :: One-line description',
1102
-        'Prompt for a master passphrase.',
1101
+        "Label :: Help text :: One-line description",
1102
+        "Prompt for a master passphrase.",
1103 1103
     )
1104 1104
     """"""
1105 1105
     DERIVEPASSPHRASE_VAULT_PRINT_NOTES_BEFORE_HELP_TEXT = commented(
1106
-        'The corresponding option is displayed as '
1106
+        "The corresponding option is displayed as "
1107 1107
         '"--print-notes-before / --print-notes-after", so you may want to '
1108
-        'hint that the default (after) is the second of those options.',
1108
+        "hint that the default (after) is the second of those options.",
1109 1109
     )(
1110
-        'Label :: Help text :: One-line description',
1111
-        'Print the notes for {service_metavar} (if any) before or '
1112
-        'after (default) the derived passphrase.',
1113
-        flags='python-brace-format',
1110
+        "Label :: Help text :: One-line description",
1111
+        "Print the notes for {service_metavar} (if any) before or "
1112
+        "after (default) the derived passphrase.",
1113
+        flags="python-brace-format",
1114 1114
     )
1115 1115
     """"""
1116 1116
     DERIVEPASSPHRASE_VAULT_REPEAT_HELP_TEXT = commented(
1117
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
1117
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
1118 1118
     )(
1119
-        'Label :: Help text :: One-line description',
1120
-        'Restrict runs of identical characters to at most {metavar} '
1121
-        'characters.',
1122
-        flags='python-brace-format',
1119
+        "Label :: Help text :: One-line description",
1120
+        "Restrict runs of identical characters to at most {metavar} "
1121
+        "characters.",
1122
+        flags="python-brace-format",
1123 1123
     )
1124 1124
     """"""
1125 1125
     DERIVEPASSPHRASE_VAULT_SPACE_HELP_TEXT = commented(
1126
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
1126
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
1127 1127
     )(
1128
-        'Label :: Help text :: One-line description',
1129
-        'Ensure at least {metavar} spaces.',
1130
-        flags='python-brace-format',
1128
+        "Label :: Help text :: One-line description",
1129
+        "Ensure at least {metavar} spaces.",
1130
+        flags="python-brace-format",
1131 1131
     )
1132 1132
     """"""
1133 1133
     DERIVEPASSPHRASE_VAULT_SYMBOL_HELP_TEXT = commented(
1134
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
1134
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
1135 1135
     )(
1136
-        'Label :: Help text :: One-line description',
1137
-        'Ensure at least {metavar} symbol characters.',
1138
-        flags='python-brace-format',
1136
+        "Label :: Help text :: One-line description",
1137
+        "Ensure at least {metavar} symbol characters.",
1138
+        flags="python-brace-format",
1139 1139
     )
1140 1140
     """"""
1141 1141
     DERIVEPASSPHRASE_VAULT_UNSET_HELP_TEXT = commented(
1142
-        'The corresponding option is displayed as '
1142
+        "The corresponding option is displayed as "
1143 1143
         '"--unset=phrase|key|...|symbol", so the "given setting" is '
1144 1144
         'referring to "phrase", "key", "lower", ..., or "symbol", '
1145
-        'respectively.  '
1145
+        "respectively.  "
1146 1146
         '"with --config" here means that the user must also specify '
1147 1147
         '"--config" for this option to have any effect.',
1148 1148
     )(
1149
-        'Label :: Help text :: One-line description',
1150
-        'With --config, also unset the given setting.  '
1151
-        'May be specified multiple times.',
1149
+        "Label :: Help text :: One-line description",
1150
+        "With --config, also unset the given setting.  "
1151
+        "May be specified multiple times.",
1152 1152
     )
1153 1153
     """"""
1154 1154
     DERIVEPASSPHRASE_VAULT_UPPER_HELP_TEXT = commented(
1155
-        'The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.',
1155
+        "The metavar is Label.PASSPHRASE_GENERATION_METAVAR_NUMBER.",
1156 1156
     )(
1157
-        'Label :: Help text :: One-line description',
1158
-        'Ensure at least {metavar} uppercase characters.',
1159
-        flags='python-brace-format',
1157
+        "Label :: Help text :: One-line description",
1158
+        "Ensure at least {metavar} uppercase characters.",
1159
+        flags="python-brace-format",
1160 1160
     )
1161 1161
     """"""
1162 1162
 
1163 1163
     EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT = commented(
1164
-        'See EXPORT_VAULT_FORMAT_HELP_TEXT.  '
1164
+        "See EXPORT_VAULT_FORMAT_HELP_TEXT.  "
1165 1165
         'The format names/labels "v0.3", "v0.2" and "storeroom" '
1166
-        'should not be translated.',
1166
+        "should not be translated.",
1167 1167
     )(
1168
-        'Label :: Help text :: One-line description',
1169
-        'Default: v0.3, v0.2, storeroom.',
1168
+        "Label :: Help text :: One-line description",
1169
+        "Default: v0.3, v0.2, storeroom.",
1170 1170
     )
1171 1171
     """"""
1172 1172
     EXPORT_VAULT_FORMAT_HELP_TEXT = commented(
1173
-        'The defaults_hint is Label.EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT, '
1174
-        'the metavar is Label.EXPORT_VAULT_FORMAT_METAVAR_FMT.',
1173
+        "The defaults_hint is Label.EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT, "
1174
+        "the metavar is Label.EXPORT_VAULT_FORMAT_METAVAR_FMT.",
1175 1175
     )(
1176
-        'Label :: Help text :: One-line description',
1177
-        'Try the following storage format {metavar}.  '
1178
-        'If specified multiple times, the '
1179
-        'formats will be tried in order.  '
1180
-        '{defaults_hint}',
1181
-        flags='python-brace-format',
1176
+        "Label :: Help text :: One-line description",
1177
+        "Try the following storage format {metavar}.  "
1178
+        "If specified multiple times, the "
1179
+        "formats will be tried in order.  "
1180
+        "{defaults_hint}",
1181
+        flags="python-brace-format",
1182 1182
     )
1183 1183
     """"""
1184 1184
     EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT = commented(
1185
-        'See EXPORT_VAULT_KEY_HELP_TEXT.',
1185
+        "See EXPORT_VAULT_KEY_HELP_TEXT.",
1186 1186
     )(
1187
-        'Label :: Help text :: One-line description',
1188
-        'Default: check the VAULT_KEY, LOGNAME, USER, or USERNAME '
1189
-        'environment variables.',
1187
+        "Label :: Help text :: One-line description",
1188
+        "Default: check the VAULT_KEY, LOGNAME, USER, or USERNAME "
1189
+        "environment variables.",
1190 1190
     )
1191 1191
     """"""
1192 1192
     EXPORT_VAULT_KEY_HELP_TEXT = commented(
1193
-        'The defaults_hint is Label.EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT, '
1194
-        'the metavar is Label.EXPORT_VAULT_KEY_METAVAR_K.',
1193
+        "The defaults_hint is Label.EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT, "
1194
+        "the metavar is Label.EXPORT_VAULT_KEY_METAVAR_K.",
1195 1195
     )(
1196
-        'Label :: Help text :: One-line description',
1197
-        'Use {metavar} as the storage master key.  {defaults_hint}',
1198
-        flags='python-brace-format',
1196
+        "Label :: Help text :: One-line description",
1197
+        "Use {metavar} as the storage master key.  {defaults_hint}",
1198
+        flags="python-brace-format",
1199 1199
     )
1200 1200
     """"""
1201 1201
     HELP_OPTION_HELP_TEXT = commented(
1202
-        '',
1202
+        "",
1203 1203
     )(
1204
-        'Label :: Help text :: One-line description',
1205
-        'Show this help text, then exit.',
1204
+        "Label :: Help text :: One-line description",
1205
+        "Show this help text, then exit.",
1206 1206
     )
1207 1207
     """"""
1208 1208
     QUIET_OPTION_HELP_TEXT = commented(
1209
-        '',
1209
+        "",
1210 1210
     )(
1211
-        'Label :: Help text :: One-line description',
1212
-        'Suppress even warnings; emit only errors.',
1211
+        "Label :: Help text :: One-line description",
1212
+        "Suppress even warnings; emit only errors.",
1213 1213
     )
1214 1214
     """"""
1215 1215
     VERBOSE_OPTION_HELP_TEXT = commented(
1216
-        '',
1216
+        "",
1217 1217
     )(
1218
-        'Label :: Help text :: One-line description',
1219
-        'Emit extra/progress information to standard error.',
1218
+        "Label :: Help text :: One-line description",
1219
+        "Emit extra/progress information to standard error.",
1220 1220
     )
1221 1221
     """"""
1222 1222
     VERSION_OPTION_HELP_TEXT = commented(
1223
-        '',
1223
+        "",
1224 1224
     )(
1225
-        'Label :: Help text :: One-line description',
1226
-        'Show version and feature information, then exit.',
1225
+        "Label :: Help text :: One-line description",
1226
+        "Show version and feature information, then exit.",
1227 1227
     )
1228 1228
     """"""
1229 1229
     COMMANDS_LABEL = commented(
1230
-        '',
1230
+        "",
1231 1231
     )(
1232
-        'Label :: Help text :: Option group name',
1233
-        'Commands',
1232
+        "Label :: Help text :: Option group name",
1233
+        "Commands",
1234 1234
     )
1235 1235
     """"""
1236 1236
     COMPATIBILITY_OPTION_LABEL = commented(
1237
-        '',
1237
+        "",
1238 1238
     )(
1239
-        'Label :: Help text :: Option group name',
1240
-        'Compatibility and extension options',
1239
+        "Label :: Help text :: Option group name",
1240
+        "Compatibility and extension options",
1241 1241
     )
1242 1242
     """"""
1243 1243
     CONFIGURATION_LABEL = commented(
1244
-        '',
1244
+        "",
1245 1245
     )(
1246
-        'Label :: Help text :: Option group name',
1247
-        'Configuration',
1246
+        "Label :: Help text :: Option group name",
1247
+        "Configuration",
1248 1248
     )
1249 1249
     """"""
1250 1250
     LOGGING_LABEL = commented(
1251
-        '',
1251
+        "",
1252 1252
     )(
1253
-        'Label :: Help text :: Option group name',
1254
-        'Logging',
1253
+        "Label :: Help text :: Option group name",
1254
+        "Logging",
1255 1255
     )
1256 1256
     """"""
1257 1257
     OPTIONS_LABEL = commented(
1258
-        '',
1258
+        "",
1259 1259
     )(
1260
-        'Label :: Help text :: Option group name',
1261
-        'Options',
1260
+        "Label :: Help text :: Option group name",
1261
+        "Options",
1262 1262
     )
1263 1263
     """"""
1264 1264
     OTHER_OPTIONS_LABEL = commented(
1265
-        '',
1265
+        "",
1266 1266
     )(
1267
-        'Label :: Help text :: Option group name',
1268
-        'Other options',
1267
+        "Label :: Help text :: Option group name",
1268
+        "Other options",
1269 1269
     )
1270 1270
     """"""
1271 1271
     PASSPHRASE_GENERATION_LABEL = commented(
1272
-        '',
1272
+        "",
1273 1273
     )(
1274
-        'Label :: Help text :: Option group name',
1275
-        'Passphrase generation',
1274
+        "Label :: Help text :: Option group name",
1275
+        "Passphrase generation",
1276 1276
     )
1277 1277
     """"""
1278 1278
     STORAGE_MANAGEMENT_LABEL = commented(
1279
-        '',
1279
+        "",
1280 1280
     )(
1281
-        'Label :: Help text :: Option group name',
1282
-        'Storage management',
1281
+        "Label :: Help text :: Option group name",
1282
+        "Storage management",
1283 1283
     )
1284 1284
     """"""
1285 1285
     VERSION_INFO_MAJOR_LIBRARY_TEXT = commented(
1286
-        'This message reports on the version of a major library '
1286
+        "This message reports on the version of a major library "
1287 1287
         'currently in use, such as "cryptography".',
1288 1288
     )(
1289
-        'Label :: Info Message',
1290
-        'Using {dependency_name_and_version}',
1291
-        flags='python-brace-format',
1289
+        "Label :: Info Message",
1290
+        "Using {dependency_name_and_version}",
1291
+        flags="python-brace-format",
1292 1292
     )
1293 1293
     """"""
1294 1294
     ENABLED_PEP508_EXTRAS = commented(
1295
-        'This is part of the version output, emitting lists of enabled '
1296
-        'PEP 508 extras.  '
1297
-        'A comma-separated English list of items follows, '
1298
-        'with standard English punctuation.',
1295
+        "This is part of the version output, emitting lists of enabled "
1296
+        "PEP 508 extras.  "
1297
+        "A comma-separated English list of items follows, "
1298
+        "with standard English punctuation.",
1299 1299
     )(
1300
-        'Label :: Info Message:: Table row header',
1301
-        'PEP 508 extras:',
1300
+        "Label :: Info Message:: Table row header",
1301
+        "PEP 508 extras:",
1302 1302
     )
1303 1303
     """"""
1304 1304
     SUPPORTED_DERIVATION_SCHEMES = commented(
1305
-        'This is part of the version output, emitting lists of supported '
1306
-        'derivation schemes.  '
1307
-        'A comma-separated English list of items follows, '
1308
-        'with standard English punctuation.',
1305
+        "This is part of the version output, emitting lists of supported "
1306
+        "derivation schemes.  "
1307
+        "A comma-separated English list of items follows, "
1308
+        "with standard English punctuation.",
1309 1309
     )(
1310
-        'Label :: Info Message:: Table row header',
1311
-        'Supported derivation schemes:',
1310
+        "Label :: Info Message:: Table row header",
1311
+        "Supported derivation schemes:",
1312 1312
     )
1313 1313
     """"""
1314 1314
     SUPPORTED_FEATURES = commented(
1315
-        'This is part of the version output, emitting lists of supported '
1316
-        'features for this subcommand.  '
1317
-        'A comma-separated English list of items follows, '
1318
-        'with standard English punctuation.',
1315
+        "This is part of the version output, emitting lists of supported "
1316
+        "features for this subcommand.  "
1317
+        "A comma-separated English list of items follows, "
1318
+        "with standard English punctuation.",
1319 1319
     )(
1320
-        'Label :: Info Message:: Table row header',
1321
-        'Supported features:',
1320
+        "Label :: Info Message:: Table row header",
1321
+        "Supported features:",
1322 1322
     )
1323 1323
     """"""
1324 1324
     SUPPORTED_FOREIGN_CONFIGURATION_FORMATS = commented(
1325
-        'This is part of the version output, emitting lists of supported '
1326
-        'foreign configuration formats.  '
1327
-        'A comma-separated English list of items follows, '
1328
-        'with standard English punctuation.',
1325
+        "This is part of the version output, emitting lists of supported "
1326
+        "foreign configuration formats.  "
1327
+        "A comma-separated English list of items follows, "
1328
+        "with standard English punctuation.",
1329 1329
     )(
1330
-        'Label :: Info Message:: Table row header',
1331
-        'Supported foreign configuration formats:',
1330
+        "Label :: Info Message:: Table row header",
1331
+        "Supported foreign configuration formats:",
1332 1332
     )
1333 1333
     """"""
1334 1334
     SUPPORTED_SUBCOMMANDS = commented(
1335
-        'This is part of the version output, emitting lists of supported '
1336
-        'subcommands.  '
1337
-        'A comma-separated English list of items follows, '
1338
-        'with standard English punctuation.',
1335
+        "This is part of the version output, emitting lists of supported "
1336
+        "subcommands.  "
1337
+        "A comma-separated English list of items follows, "
1338
+        "with standard English punctuation.",
1339 1339
     )(
1340
-        'Label :: Info Message:: Table row header',
1341
-        'Supported subcommands:',
1340
+        "Label :: Info Message:: Table row header",
1341
+        "Supported subcommands:",
1342 1342
     )
1343 1343
     """"""
1344 1344
     UNAVAILABLE_DERIVATION_SCHEMES = commented(
1345
-        'This is part of the version output, emitting lists of known, '
1346
-        'unavailable derivation schemes.  '
1347
-        'A comma-separated English list of items follows, '
1348
-        'with standard English punctuation.',
1345
+        "This is part of the version output, emitting lists of known, "
1346
+        "unavailable derivation schemes.  "
1347
+        "A comma-separated English list of items follows, "
1348
+        "with standard English punctuation.",
1349 1349
     )(
1350
-        'Label :: Info Message:: Table row header',
1351
-        'Known derivation schemes:',
1350
+        "Label :: Info Message:: Table row header",
1351
+        "Known derivation schemes:",
1352 1352
     )
1353 1353
     """"""
1354 1354
     UNAVAILABLE_FEATURES = commented(
1355
-        'This is part of the version output, emitting lists of known, '
1356
-        'unavailable features for this subcommand.  '
1357
-        'A comma-separated English list of items follows, '
1358
-        'with standard English punctuation.',
1355
+        "This is part of the version output, emitting lists of known, "
1356
+        "unavailable features for this subcommand.  "
1357
+        "A comma-separated English list of items follows, "
1358
+        "with standard English punctuation.",
1359 1359
     )(
1360
-        'Label :: Info Message:: Table row header',
1361
-        'Known features:',
1360
+        "Label :: Info Message:: Table row header",
1361
+        "Known features:",
1362 1362
     )
1363 1363
     """"""
1364 1364
     UNAVAILABLE_FOREIGN_CONFIGURATION_FORMATS = commented(
1365
-        'This is part of the version output, emitting lists of known, '
1366
-        'unavailable foreign configuration formats.  '
1367
-        'A comma-separated English list of items follows, '
1368
-        'with standard English punctuation.',
1365
+        "This is part of the version output, emitting lists of known, "
1366
+        "unavailable foreign configuration formats.  "
1367
+        "A comma-separated English list of items follows, "
1368
+        "with standard English punctuation.",
1369 1369
     )(
1370
-        'Label :: Info Message:: Table row header',
1371
-        'Known foreign configuration formats:',
1370
+        "Label :: Info Message:: Table row header",
1371
+        "Known foreign configuration formats:",
1372 1372
     )
1373 1373
     """"""
1374 1374
     CONFIRM_THIS_CHOICE_PROMPT_TEXT = commented(
1375 1375
         'There is no support for "yes" or "no" in other languages '
1376
-        'than English, so it is advised that your translation makes it '
1376
+        "than English, so it is advised that your translation makes it "
1377 1377
         'clear that only the strings "y", "yes", "n" or "no" are supported, '
1378
-        'even if the prompt becomes a bit longer.',
1378
+        "even if the prompt becomes a bit longer.",
1379 1379
     )(
1380
-        'Label :: Interactive prompt',
1381
-        'Confirm this choice? (y/N)',
1380
+        "Label :: Interactive prompt",
1381
+        "Confirm this choice? (y/N)",
1382 1382
     )
1383 1383
     """"""
1384 1384
     SUITABLE_SSH_KEYS_LABEL = commented(
1385
-        'This label is the heading of the list of suitable SSH keys.',
1385
+        "This label is the heading of the list of suitable SSH keys.",
1386 1386
     )(
1387
-        'Label :: Interactive prompt',
1388
-        'Suitable SSH keys:',
1387
+        "Label :: Interactive prompt",
1388
+        "Suitable SSH keys:",
1389 1389
     )
1390 1390
     """"""
1391 1391
     YOUR_SELECTION_PROMPT_TEXT = commented(
1392
-        '',
1392
+        "",
1393 1393
     )(
1394
-        'Label :: Interactive prompt',
1395
-        'Your selection? (1-{n}, leave empty to abort)',
1396
-        flags='python-brace-format',
1394
+        "Label :: Interactive prompt",
1395
+        "Your selection? (1-{n}, leave empty to abort)",
1396
+        flags="python-brace-format",
1397 1397
     )
1398 1398
     """"""
1399 1399
 
... ...
@@ -1402,25 +1402,25 @@ class DebugMsgTemplate(enum.Enum):
1402 1402
     """Debug messages for the `derivepassphrase` command-line."""
1403 1403
 
1404 1404
     BUCKET_ITEM_FOUND = commented(
1405
-        'This message is emitted by the vault configuration exporter '
1405
+        "This message is emitted by the vault configuration exporter "
1406 1406
         'for "storeroom"-type configuration directories.  '
1407 1407
         'The system stores entries in different "buckets" of a hash table.  '
1408
-        'Here, we report on a single item (path and value) we discovered '
1409
-        'after decrypting the whole bucket.  '
1410
-        '(We ensure the path and value are printable as-is.)',
1408
+        "Here, we report on a single item (path and value) we discovered "
1409
+        "after decrypting the whole bucket.  "
1410
+        "(We ensure the path and value are printable as-is.)",
1411 1411
     )(
1412
-        'Debug message',
1413
-        'Found bucket item: {path} -> {value}',
1414
-        flags='python-brace-format',
1412
+        "Debug message",
1413
+        "Found bucket item: {path} -> {value}",
1414
+        flags="python-brace-format",
1415 1415
     )
1416 1416
     """"""
1417 1417
     DECRYPT_BUCKET_ITEM_INFO = commented(
1418 1418
         '"AES256-CBC" and "PKCS#7" are, in essence, names of formats, '
1419
-        'and should not be translated.  '
1419
+        "and should not be translated.  "
1420 1420
         '"IV" means "initialization vector", and is specifically '
1421 1421
         'a cryptographic term, as are "plaintext" and "ciphertext".',
1422 1422
     )(
1423
-        'Debug message',
1423
+        "Debug message",
1424 1424
         """\
1425 1425
 Decrypt bucket item contents:
1426 1426
 
... ...
@@ -1431,13 +1431,13 @@ Decrypt bucket item contents:
1431 1431
   Encrypted ciphertext: {ciphertext}
1432 1432
   Plaintext: {plaintext}
1433 1433
 """,
1434
-        flags='python-brace-format',
1434
+        flags="python-brace-format",
1435 1435
     )
1436 1436
     """"""
1437 1437
     DECRYPT_BUCKET_ITEM_KEY_INFO = commented(
1438
-        '',
1438
+        "",
1439 1439
     )(
1440
-        'Debug message',
1440
+        "Debug message",
1441 1441
         """\
1442 1442
 Decrypt bucket item:
1443 1443
 
... ...
@@ -1446,20 +1446,20 @@ Decrypt bucket item:
1446 1446
   Encryption key (master key): {enc_key}
1447 1447
   Signing key (master key): {sign_key}
1448 1448
 """,
1449
-        flags='python-brace-format',
1449
+        flags="python-brace-format",
1450 1450
     )
1451 1451
     """"""
1452 1452
     DECRYPT_BUCKET_ITEM_MAC_INFO = commented(
1453 1453
         'The MAC stands for "message authentication code", '
1454
-        'which guarantees the authenticity of the message to anyone '
1455
-        'who holds the corresponding key, similar to a digital signature.  '
1454
+        "which guarantees the authenticity of the message to anyone "
1455
+        "who holds the corresponding key, similar to a digital signature.  "
1456 1456
         'The acronym "MAC" is assumed to be well-known to the '
1457
-        'English target audience, or at least discoverable by them; '
1458
-        'they *are* asking for debug output, after all.  '
1459
-        'Please use your judgement as to whether to translate this term '
1460
-        'or not, expanded or not.',
1457
+        "English target audience, or at least discoverable by them; "
1458
+        "they *are* asking for debug output, after all.  "
1459
+        "Please use your judgement as to whether to translate this term "
1460
+        "or not, expanded or not.",
1461 1461
     )(
1462
-        'Debug message',
1462
+        "Debug message",
1463 1463
         """\
1464 1464
 Decrypt bucket item contents:
1465 1465
 
... ...
@@ -1469,16 +1469,16 @@ Decrypt bucket item contents:
1469 1469
   Claimed MAC value: {claimed_mac}
1470 1470
   Computed MAC value: {actual_mac}
1471 1471
 """,
1472
-        flags='python-brace-format',
1472
+        flags="python-brace-format",
1473 1473
     )
1474 1474
     """"""
1475 1475
     DECRYPT_BUCKET_ITEM_SESSION_KEYS_INFO = commented(
1476 1476
         '"AES256-CBC" and "PKCS#7" are, in essence, names of formats, '
1477
-        'and should not be translated.  '
1477
+        "and should not be translated.  "
1478 1478
         '"IV" means "initialization vector", and is specifically '
1479 1479
         'a cryptographic term, as are "plaintext" and "ciphertext".',
1480 1480
     )(
1481
-        'Debug message',
1481
+        "Debug message",
1482 1482
         """\
1483 1483
 Decrypt bucket item session keys:
1484 1484
 
... ...
@@ -1490,20 +1490,20 @@ Decrypt bucket item session keys:
1490 1490
   Plaintext: {plaintext}
1491 1491
   Parsed plaintext: {code}
1492 1492
 """,
1493
-        flags='python-brace-format',
1493
+        flags="python-brace-format",
1494 1494
     )
1495 1495
     """"""
1496 1496
     DECRYPT_BUCKET_ITEM_SESSION_KEYS_MAC_INFO = commented(
1497 1497
         'The MAC stands for "message authentication code", '
1498
-        'which guarantees the authenticity of the message to anyone '
1499
-        'who holds the corresponding key, similar to a digital signature.  '
1498
+        "which guarantees the authenticity of the message to anyone "
1499
+        "who holds the corresponding key, similar to a digital signature.  "
1500 1500
         'The acronym "MAC" is assumed to be well-known to the '
1501
-        'English target audience, or at least discoverable by them; '
1502
-        'they *are* asking for debug output, after all.  '
1503
-        'Please use your judgement as to whether to translate this term '
1504
-        'or not, expanded or not.',
1501
+        "English target audience, or at least discoverable by them; "
1502
+        "they *are* asking for debug output, after all.  "
1503
+        "Please use your judgement as to whether to translate this term "
1504
+        "or not, expanded or not.",
1505 1505
     )(
1506
-        'Debug message',
1506
+        "Debug message",
1507 1507
         """\
1508 1508
 Decrypt bucket item session keys:
1509 1509
 
... ...
@@ -1513,13 +1513,13 @@ Decrypt bucket item session keys:
1513 1513
   Claimed MAC value: {claimed_mac}
1514 1514
   Computed MAC value: {actual_mac}
1515 1515
 """,
1516
-        flags='python-brace-format',
1516
+        flags="python-brace-format",
1517 1517
     )
1518 1518
     """"""
1519 1519
     DERIVED_MASTER_KEYS_KEYS = commented(
1520
-        '',
1520
+        "",
1521 1521
     )(
1522
-        'Debug message',
1522
+        "Debug message",
1523 1523
         """\
1524 1524
 Derived master keys' keys:
1525 1525
 
... ...
@@ -1529,36 +1529,36 @@ Derived master keys' keys:
1529 1529
   Password: {pw_bytes}
1530 1530
   Function call: pbkdf2(algorithm={algorithm!r}, length={length!r}, salt={salt!r}, iterations={iterations!r})
1531 1531
 """,  # noqa: E501
1532
-        flags='python-brace-format',
1532
+        flags="python-brace-format",
1533 1533
     )
1534 1534
     """"""
1535 1535
     DIRECTORY_CONTENTS_CHECK_OK = commented(
1536
-        'This message is emitted by the vault configuration exporter '
1536
+        "This message is emitted by the vault configuration exporter "
1537 1537
         'for "storeroom"-type configuration directories, '
1538 1538
         'while "assembling" the items stored in the configuration '
1539 1539
         """according to the item's "path".  """
1540 1540
         'Each "directory" in the path contains a list of children '
1541
-        'it claims to contain, and this list must be matched '
1542
-        'against the actual discovered items.  '
1543
-        'Now, at the end, we actually confirm the claim.  '
1544
-        '(We would have already thrown an error here otherwise.)',
1541
+        "it claims to contain, and this list must be matched "
1542
+        "against the actual discovered items.  "
1543
+        "Now, at the end, we actually confirm the claim.  "
1544
+        "(We would have already thrown an error here otherwise.)",
1545 1545
     )(
1546
-        'Debug message',
1547
-        'Directory contents check OK: {path} -> {contents}',
1548
-        flags='python-brace-format',
1546
+        "Debug message",
1547
+        "Directory contents check OK: {path} -> {contents}",
1548
+        flags="python-brace-format",
1549 1549
     )
1550 1550
     """"""
1551 1551
     MASTER_KEYS_DATA_MAC_INFO = commented(
1552 1552
         'The MAC stands for "message authentication code", '
1553
-        'which guarantees the authenticity of the message to anyone '
1554
-        'who holds the corresponding key, similar to a digital signature.  '
1553
+        "which guarantees the authenticity of the message to anyone "
1554
+        "who holds the corresponding key, similar to a digital signature.  "
1555 1555
         'The acronym "MAC" is assumed to be well-known to the '
1556
-        'English target audience, or at least discoverable by them; '
1557
-        'they *are* asking for debug output, after all.  '
1558
-        'Please use your judgement as to whether to translate this term '
1559
-        'or not, expanded or not.',
1556
+        "English target audience, or at least discoverable by them; "
1557
+        "they *are* asking for debug output, after all.  "
1558
+        "Please use your judgement as to whether to translate this term "
1559
+        "or not, expanded or not.",
1560 1560
     )(
1561
-        'Debug message',
1561
+        "Debug message",
1562 1562
         """\
1563 1563
 Master keys data:
1564 1564
 
... ...
@@ -1568,59 +1568,59 @@ Master keys data:
1568 1568
   Claimed MAC value: {claimed_mac}
1569 1569
   Computed MAC value: {actual_mac}
1570 1570
 """,
1571
-        flags='python-brace-format',
1571
+        flags="python-brace-format",
1572 1572
     )
1573 1573
     """"""
1574 1574
     POSTPONING_DIRECTORY_CONTENTS_CHECK = commented(
1575
-        'This message is emitted by the vault configuration exporter '
1575
+        "This message is emitted by the vault configuration exporter "
1576 1576
         'for "storeroom"-type configuration directories, '
1577 1577
         'while "assembling" the items stored in the configuration '
1578 1578
         """according to the item's "path".  """
1579 1579
         'Each "directory" in the path contains a list of children '
1580
-        'it claims to contain, and this list must be matched '
1581
-        'against the actual discovered items.  '
1582
-        'When emitting this message, we merely indicate that we saved '
1580
+        "it claims to contain, and this list must be matched "
1581
+        "against the actual discovered items.  "
1582
+        "When emitting this message, we merely indicate that we saved "
1583 1583
         'the "claimed" list for this directory for later.',
1584 1584
     )(
1585
-        'Debug message',
1586
-        'Postponing directory contents check: {path} -> {contents}',
1587
-        flags='python-brace-format',
1585
+        "Debug message",
1586
+        "Postponing directory contents check: {path} -> {contents}",
1587
+        flags="python-brace-format",
1588 1588
     )
1589 1589
     """"""
1590 1590
     SETTING_CONFIG_STRUCTURE_CONTENTS = commented(
1591
-        'This message is emitted by the vault configuration exporter '
1591
+        "This message is emitted by the vault configuration exporter "
1592 1592
         'for "storeroom"-type configuration directories, '
1593 1593
         'while "assembling" the items stored in the configuration '
1594 1594
         """according to the item's "path".  """
1595
-        'We confirm that we set the entry at the given path '
1596
-        'to the given value.',
1595
+        "We confirm that we set the entry at the given path "
1596
+        "to the given value.",
1597 1597
     )(
1598
-        'Debug message',
1599
-        'Setting contents: {path} -> {value}',
1600
-        flags='python-brace-format',
1598
+        "Debug message",
1599
+        "Setting contents: {path} -> {value}",
1600
+        flags="python-brace-format",
1601 1601
     )
1602 1602
     """"""
1603 1603
     SETTING_CONFIG_STRUCTURE_CONTENTS_EMPTY_DIRECTORY = commented(
1604
-        'This message is emitted by the vault configuration exporter '
1604
+        "This message is emitted by the vault configuration exporter "
1605 1605
         'for "storeroom"-type configuration directories, '
1606 1606
         'while "assembling" the items stored in the configuration '
1607 1607
         """according to the item's "path".  """
1608
-        'We confirm that we set up a currently empty directory '
1609
-        'at the given path.',
1608
+        "We confirm that we set up a currently empty directory "
1609
+        "at the given path.",
1610 1610
     )(
1611
-        'Debug message',
1612
-        'Setting contents (empty directory): {path}',
1613
-        flags='python-brace-format',
1611
+        "Debug message",
1612
+        "Setting contents (empty directory): {path}",
1613
+        flags="python-brace-format",
1614 1614
     )
1615 1615
     """"""
1616 1616
     VAULT_NATIVE_CHECKING_MAC_DETAILS = commented(
1617
-        'This message is emitted by the vault configuration exporter '
1617
+        "This message is emitted by the vault configuration exporter "
1618 1618
         'for "native"-type configuration directories.  '
1619
-        'It is preceded by the info message '
1620
-        'VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC; see the commentary there '
1621
-        'concerning the terms and thoughts on translating them.',
1619
+        "It is preceded by the info message "
1620
+        "VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC; see the commentary there "
1621
+        "concerning the terms and thoughts on translating them.",
1622 1622
     )(
1623
-        'Debug message',
1623
+        "Debug message",
1624 1624
         """\
1625 1625
 MAC details:
1626 1626
 
... ...
@@ -1628,18 +1628,18 @@ MAC details:
1628 1628
   MAC input: {mac_input}
1629 1629
   Expected MAC: {mac}
1630 1630
 """,
1631
-        flags='python-brace-format',
1631
+        flags="python-brace-format",
1632 1632
     )
1633 1633
     """"""
1634 1634
     VAULT_NATIVE_EVP_BYTESTOKEY_INIT = commented(
1635
-        'This message is emitted by the vault configuration exporter '
1635
+        "This message is emitted by the vault configuration exporter "
1636 1636
         'for "native"-type configuration directories: '
1637 1637
         'in v0.2, the non-standard and deprecated "EVP_bytestokey" function '
1638
-        'from OpenSSL must be reimplemented from scratch.  '
1638
+        "from OpenSSL must be reimplemented from scratch.  "
1639 1639
         'The terms "salt" and "IV" (initialization vector) '
1640
-        'are cryptographic terms.',
1640
+        "are cryptographic terms.",
1641 1641
     )(
1642
-        'Debug message',
1642
+        "Debug message",
1643 1643
         """\
1644 1644
 evp_bytestokey_md5 (initialization):
1645 1645
 
... ...
@@ -1651,19 +1651,19 @@ evp_bytestokey_md5 (initialization):
1651 1651
   Buffer length: {buffer_length}
1652 1652
   Buffer: {buffer}
1653 1653
 """,
1654
-        flags='python-brace-format',
1654
+        flags="python-brace-format",
1655 1655
     )
1656 1656
     """"""
1657 1657
     VAULT_NATIVE_EVP_BYTESTOKEY_RESULT = commented(
1658
-        'This message is emitted by the vault configuration exporter '
1658
+        "This message is emitted by the vault configuration exporter "
1659 1659
         'for "native"-type configuration directories: '
1660 1660
         'in v0.2, the non-standard and deprecated "EVP_bytestokey" function '
1661
-        'from OpenSSL must be reimplemented from scratch.  '
1661
+        "from OpenSSL must be reimplemented from scratch.  "
1662 1662
         'The terms "salt" and "IV" (initialization vector) '
1663
-        'are cryptographic terms.'
1664
-        'This function reports on the final results.',
1663
+        "are cryptographic terms."
1664
+        "This function reports on the final results.",
1665 1665
     )(
1666
-        'Debug message',
1666
+        "Debug message",
1667 1667
         """\
1668 1668
 evp_bytestokey_md5 (result):
1669 1669
 
... ...
@@ -1671,20 +1671,20 @@ evp_bytestokey_md5 (result):
1671 1671
   Encryption key: {enc_key}
1672 1672
   IV: {iv}
1673 1673
 """,
1674
-        flags='python-brace-format',
1674
+        flags="python-brace-format",
1675 1675
     )
1676 1676
     """"""
1677 1677
     VAULT_NATIVE_EVP_BYTESTOKEY_ROUND = commented(
1678
-        'This message is emitted by the vault configuration exporter '
1678
+        "This message is emitted by the vault configuration exporter "
1679 1679
         'for "native"-type configuration directories: '
1680 1680
         'in v0.2, the non-standard and deprecated "EVP_bytestokey" function '
1681
-        'from OpenSSL must be reimplemented from scratch.  '
1681
+        "from OpenSSL must be reimplemented from scratch.  "
1682 1682
         'The terms "salt" and "IV" (initialization vector) '
1683
-        'are cryptographic terms.'
1684
-        'This function reports on the updated buffer length and contents '
1685
-        'after executing one round of hashing.',
1683
+        "are cryptographic terms."
1684
+        "This function reports on the updated buffer length and contents "
1685
+        "after executing one round of hashing.",
1686 1686
     )(
1687
-        'Debug message',
1687
+        "Debug message",
1688 1688
         """\
1689 1689
 evp_bytestokey_md5 (round update):
1690 1690
 
... ...
@@ -1692,27 +1692,27 @@ evp_bytestokey_md5 (round update):
1692 1692
   Buffer length: {buffer_length}
1693 1693
   Buffer: {buffer}
1694 1694
 """,
1695
-        flags='python-brace-format',
1695
+        flags="python-brace-format",
1696 1696
     )
1697 1697
     """"""
1698 1698
     VAULT_NATIVE_PADDED_PLAINTEXT = commented(
1699
-        'This message is emitted by the vault configuration exporter '
1699
+        "This message is emitted by the vault configuration exporter "
1700 1700
         'for "native"-type configuration directories.  '
1701 1701
         '"padding" and "plaintext" are cryptographic terms.',
1702 1702
     )(
1703
-        'Debug message',
1704
-        'Padded plaintext: {contents}',
1705
-        flags='python-brace-format',
1703
+        "Debug message",
1704
+        "Padded plaintext: {contents}",
1705
+        flags="python-brace-format",
1706 1706
     )
1707 1707
     """"""
1708 1708
     VAULT_NATIVE_PARSE_BUFFER = commented(
1709
-        'This message is emitted by the vault configuration exporter '
1709
+        "This message is emitted by the vault configuration exporter "
1710 1710
         'for "native"-type configuration directories.  '
1711
-        'It is preceded by the info message '
1712
-        'VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC; see the commentary there '
1713
-        'concerning the terms and thoughts on translating them.',
1711
+        "It is preceded by the info message "
1712
+        "VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC; see the commentary there "
1713
+        "concerning the terms and thoughts on translating them.",
1714 1714
     )(
1715
-        'Debug message',
1715
+        "Debug message",
1716 1716
         """\
1717 1717
 Buffer: {contents}
1718 1718
 
... ...
@@ -1721,13 +1721,13 @@ Buffer: {contents}
1721 1721
   Payload (ciphertext): {payload}
1722 1722
   MAC: {mac}
1723 1723
 """,
1724
-        flags='python-brace-format',
1724
+        flags="python-brace-format",
1725 1725
     )
1726 1726
     """"""
1727 1727
     VAULT_NATIVE_PBKDF2_CALL = commented(
1728
-        '',
1728
+        "",
1729 1729
     )(
1730
-        'Debug message',
1730
+        "Debug message",
1731 1731
         """\
1732 1732
 Master key derivation:
1733 1733
 
... ...
@@ -1736,28 +1736,28 @@ Master key derivation:
1736 1736
   Result (binary): {raw_result}
1737 1737
   Result (hex key): {result_key!r}
1738 1738
 """,  # noqa: E501
1739
-        flags='python-brace-format',
1739
+        flags="python-brace-format",
1740 1740
     )
1741 1741
     """"""
1742 1742
     VAULT_NATIVE_PLAINTEXT = commented(
1743
-        'This message is emitted by the vault configuration exporter '
1743
+        "This message is emitted by the vault configuration exporter "
1744 1744
         'for "native"-type configuration directories.  '
1745 1745
         '"plaintext" is a cryptographic term.',
1746 1746
     )(
1747
-        'Debug message',
1748
-        'Plaintext: {contents}',
1749
-        flags='python-brace-format',
1747
+        "Debug message",
1748
+        "Plaintext: {contents}",
1749
+        flags="python-brace-format",
1750 1750
     )
1751 1751
     """"""
1752 1752
     VAULT_NATIVE_V02_PAYLOAD_MAC_POSTPROCESSING = commented(
1753
-        'This message is emitted by the vault configuration exporter '
1753
+        "This message is emitted by the vault configuration exporter "
1754 1754
         'for "native"-type configuration directories.  '
1755
-        'It is preceded by the info message '
1756
-        'VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC and the debug message '
1757
-        'PARSING_NATIVE_PARSE_BUFFER; see the commentary there concerning '
1758
-        'the terms and thoughts on translating them.',
1755
+        "It is preceded by the info message "
1756
+        "VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC and the debug message "
1757
+        "PARSING_NATIVE_PARSE_BUFFER; see the commentary there concerning "
1758
+        "the terms and thoughts on translating them.",
1759 1759
     )(
1760
-        'Debug message',
1760
+        "Debug message",
1761 1761
         """\
1762 1762
 Postprocessing buffer (v0.2):
1763 1763
 
... ...
@@ -1765,7 +1765,7 @@ Postprocessing buffer (v0.2):
1765 1765
   Payload: {payload} (decoded from base64)
1766 1766
   MAC: {mac} (decoded from hex)
1767 1767
 """,
1768
-        flags='python-brace-format',
1768
+        flags="python-brace-format",
1769 1769
     )
1770 1770
     """"""
1771 1771
 
... ...
@@ -1774,122 +1774,122 @@ class InfoMsgTemplate(enum.Enum):
1774 1774
     """Info messages for the `derivepassphrase` command-line."""
1775 1775
 
1776 1776
     ASSEMBLING_CONFIG_STRUCTURE = commented(
1777
-        'This message is emitted by the vault configuration exporter '
1777
+        "This message is emitted by the vault configuration exporter "
1778 1778
         'for "storeroom"-type configuration directories.  '
1779 1779
         'The system stores entries in different "buckets" of a hash table.  '
1780
-        'After the respective items in the buckets have been decrypted, '
1781
-        'we then have a list of item paths plus contents to populate.  '
1780
+        "After the respective items in the buckets have been decrypted, "
1781
+        "we then have a list of item paths plus contents to populate.  "
1782 1782
         "This must be done in a certain order (we don't yet have an "
1783
-        'existing directory tree to rely on, but rather must '
1783
+        "existing directory tree to rely on, but rather must "
1784 1784
         'build it on-the-fly), hence the term "assembling".',
1785 1785
     )(
1786
-        'Info message',
1787
-        'Assembling config structure.',
1786
+        "Info message",
1787
+        "Assembling config structure.",
1788 1788
     )
1789 1789
     """"""
1790 1790
     CANNOT_LOAD_AS_VAULT_CONFIG = commented(
1791 1791
         '"fmt" is a string such as "v0.2" or "storeroom", '
1792
-        'indicating the format which we tried to load the '
1793
-        'vault configuration as.',
1792
+        "indicating the format which we tried to load the "
1793
+        "vault configuration as.",
1794 1794
     )(
1795
-        'Info message',
1796
-        'Cannot load {path!r} as a {fmt} vault configuration.',
1797
-        flags='python-brace-format',
1795
+        "Info message",
1796
+        "Cannot load {path!r} as a {fmt} vault configuration.",
1797
+        flags="python-brace-format",
1798 1798
     )
1799 1799
     """"""
1800 1800
     CHECKING_CONFIG_STRUCTURE_CONSISTENCY = commented(
1801
-        'This message is emitted by the vault configuration exporter '
1801
+        "This message is emitted by the vault configuration exporter "
1802 1802
         'for "storeroom"-type configuration directories.  '
1803 1803
         'Having "assembled" the configuration items according to '
1804
-        'their claimed paths and contents, we then check if the '
1805
-        'assembled structure is internally consistent.',
1804
+        "their claimed paths and contents, we then check if the "
1805
+        "assembled structure is internally consistent.",
1806 1806
     )(
1807
-        'Info message',
1808
-        'Checking config structure consistency.',
1807
+        "Info message",
1808
+        "Checking config structure consistency.",
1809 1809
     )
1810 1810
     """"""
1811 1811
     DECRYPTING_BUCKET = commented(
1812
-        'This message is emitted by the vault configuration exporter '
1812
+        "This message is emitted by the vault configuration exporter "
1813 1813
         'for "storeroom"-type configuration directories.  '
1814 1814
         'The system stores entries in different "buckets" of a hash table.  '
1815
-        'We parse the directory bucket by bucket.  '
1816
-        'All buckets are numbered in hexadecimal, and typically there are '
1817
-        '32 buckets, so 2-digit hex numbers.',
1815
+        "We parse the directory bucket by bucket.  "
1816
+        "All buckets are numbered in hexadecimal, and typically there are "
1817
+        "32 buckets, so 2-digit hex numbers.",
1818 1818
     )(
1819
-        'Info message',
1820
-        'Decrypting bucket {bucket_number}.',
1821
-        flags='python-brace-format',
1819
+        "Info message",
1820
+        "Decrypting bucket {bucket_number}.",
1821
+        flags="python-brace-format",
1822 1822
     )
1823 1823
     """"""
1824 1824
     PARSING_MASTER_KEYS_DATA = commented(
1825
-        'This message is emitted by the vault configuration exporter '
1825
+        "This message is emitted by the vault configuration exporter "
1826 1826
         'for "storeroom"-type configuration directories.  '
1827
-        '`.keys` is a filename, from which data about the master keys '
1828
-        'for this configuration are loaded.',
1827
+        "`.keys` is a filename, from which data about the master keys "
1828
+        "for this configuration are loaded.",
1829 1829
     )(
1830
-        'Info message',
1831
-        'Parsing master keys data from `.keys`.',
1830
+        "Info message",
1831
+        "Parsing master keys data from `.keys`.",
1832 1832
     )
1833 1833
     """"""
1834 1834
     PIP_INSTALL_EXTRA = commented(
1835
-        'This message immediately follows an error message about '
1836
-        'a missing library that needs to be installed.  '
1837
-        'The Python Package Index (PyPI) supports declaring sets of '
1835
+        "This message immediately follows an error message about "
1836
+        "a missing library that needs to be installed.  "
1837
+        "The Python Package Index (PyPI) supports declaring sets of "
1838 1838
         'optional dependencies as "extras", so users installing from PyPI '
1839 1839
         'can request reinstallation with a named "extra" being enabled.  '
1840
-        'This would then let the installer take care of the '
1841
-        'missing libraries automatically, '
1842
-        'hence this suggestion to PyPI users.',
1840
+        "This would then let the installer take care of the "
1841
+        "missing libraries automatically, "
1842
+        "hence this suggestion to PyPI users.",
1843 1843
     )(
1844
-        'Info message',
1845
-        'For users installing from PyPI, see the {extra_name!r} extra.',
1846
-        flags='python-brace-format',
1844
+        "Info message",
1845
+        "For users installing from PyPI, see the {extra_name!r} extra.",
1846
+        flags="python-brace-format",
1847 1847
     )
1848 1848
     """"""
1849 1849
     SUCCESSFULLY_MIGRATED = commented(
1850
-        'This info message immediately follows the '
1850
+        "This info message immediately follows the "
1851 1851
         '"Using deprecated v0.1-style ..." deprecation warning.',
1852 1852
     )(
1853
-        'Info message',
1854
-        'Successfully migrated to {path!r}.',
1855
-        flags='python-brace-format',
1853
+        "Info message",
1854
+        "Successfully migrated to {path!r}.",
1855
+        flags="python-brace-format",
1856 1856
     )
1857 1857
     """"""
1858 1858
     VAULT_NATIVE_CHECKING_MAC = commented(
1859
-        '',
1859
+        "",
1860 1860
     )(
1861
-        'Info message',
1862
-        'Checking MAC.',
1861
+        "Info message",
1862
+        "Checking MAC.",
1863 1863
     )
1864 1864
     """"""
1865 1865
     VAULT_NATIVE_DECRYPTING_CONTENTS = commented(
1866
-        '',
1866
+        "",
1867 1867
     )(
1868
-        'Info message',
1869
-        'Decrypting contents.',
1868
+        "Info message",
1869
+        "Decrypting contents.",
1870 1870
     )
1871 1871
     """"""
1872 1872
     VAULT_NATIVE_DERIVING_KEYS = commented(
1873
-        '',
1873
+        "",
1874 1874
     )(
1875
-        'Info message',
1876
-        'Deriving an encryption and signing key.',
1875
+        "Info message",
1876
+        "Deriving an encryption and signing key.",
1877 1877
     )
1878 1878
     """"""
1879 1879
     VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC = commented(
1880
-        'This message is emitted by the vault configuration exporter '
1880
+        "This message is emitted by the vault configuration exporter "
1881 1881
         'for "native"-type configuration directories.  '
1882 1882
         '"IV" means "initialization vector", and "MAC" means '
1883 1883
         '"message authentication code".  '
1884 1884
         'They are specifically cryptographic terms, as is "payload".  '
1885 1885
         'The acronyms "IV" and "MAC" are assumed to be well-known to the '
1886
-        'English target audience, or at least discoverable by them; '
1887
-        'they *are* asking for debug output, after all.  '
1888
-        'Please use your judgement as to whether to translate these terms '
1889
-        'or not, expanded or not.',
1886
+        "English target audience, or at least discoverable by them; "
1887
+        "they *are* asking for debug output, after all.  "
1888
+        "Please use your judgement as to whether to translate these terms "
1889
+        "or not, expanded or not.",
1890 1890
     )(
1891
-        'Info message',
1892
-        'Parsing IV, payload and MAC from the file contents.',
1891
+        "Info message",
1892
+        "Parsing IV, payload and MAC from the file contents.",
1893 1893
     )
1894 1894
     """"""
1895 1895
 
... ...
@@ -1898,160 +1898,160 @@ class WarnMsgTemplate(enum.Enum):
1898 1898
     """Warning messages for the `derivepassphrase` command-line."""
1899 1899
 
1900 1900
     EDITING_NOTES_BUT_NOT_STORING_CONFIG = commented(
1901
-        '',
1901
+        "",
1902 1902
     )(
1903
-        'Warning message',
1904
-        'Specifying --notes without --config is ineffective.  '
1905
-        'No notes will be edited.',
1903
+        "Warning message",
1904
+        "Specifying --notes without --config is ineffective.  "
1905
+        "No notes will be edited.",
1906 1906
     )
1907 1907
     EMPTY_SERVICE_NOT_SUPPORTED = commented(
1908
-        '',
1908
+        "",
1909 1909
     )(
1910
-        'Warning message',
1911
-        'An empty {service_metavar} is not supported by vault(1).  '
1912
-        'For compatibility, this will be treated as if '
1913
-        '{service_metavar} was not supplied, i.e., it will error out, '
1914
-        'or operate on global settings.',
1915
-        flags='python-brace-format',
1910
+        "Warning message",
1911
+        "An empty {service_metavar} is not supported by vault(1).  "
1912
+        "For compatibility, this will be treated as if "
1913
+        "{service_metavar} was not supplied, i.e., it will error out, "
1914
+        "or operate on global settings.",
1915
+        flags="python-brace-format",
1916 1916
     )
1917 1917
     """"""
1918 1918
     EMPTY_SERVICE_SETTINGS_INACCESSIBLE = commented(
1919
-        '',
1919
+        "",
1920 1920
     )(
1921
-        'Warning message',
1922
-        'An empty {service_metavar} is not supported by vault(1).  '
1923
-        'The empty-string service settings will be inaccessible '
1924
-        'and ineffective.  '
1925
-        'To ensure that vault(1) and {PROG_NAME} see the settings, '  # noqa: RUF027
1921
+        "Warning message",
1922
+        "An empty {service_metavar} is not supported by vault(1).  "
1923
+        "The empty-string service settings will be inaccessible "
1924
+        "and ineffective.  "
1925
+        "To ensure that vault(1) and {PROG_NAME} see the settings, "  # noqa: RUF027
1926 1926
         'move them into the "global" section.',
1927
-        flags='python-brace-format',
1927
+        flags="python-brace-format",
1928 1928
     )
1929 1929
     """"""
1930 1930
     FAILED_TO_MIGRATE_CONFIG = commented(
1931 1931
         '"error" is supplied by the operating system (errno/strerror).',
1932 1932
     )(
1933
-        'Warning message',
1934
-        'Failed to migrate to {path!r}: {error}: {filename!r}.',
1935
-        flags='python-brace-format',
1933
+        "Warning message",
1934
+        "Failed to migrate to {path!r}: {error}: {filename!r}.",
1935
+        flags="python-brace-format",
1936 1936
     )
1937 1937
     """"""
1938 1938
     GLOBAL_PASSPHRASE_INEFFECTIVE = commented(
1939
-        '',
1939
+        "",
1940 1940
     )(
1941
-        'Warning message',
1942
-        'Setting a global passphrase is ineffective '
1943
-        'because a key is also set.',
1941
+        "Warning message",
1942
+        "Setting a global passphrase is ineffective "
1943
+        "because a key is also set.",
1944 1944
     )
1945 1945
     """"""
1946 1946
     LEGACY_EDITOR_INTERFACE_NOTES_BACKUP = commented(
1947
-        '',
1947
+        "",
1948 1948
     )(
1949
-        'Warning message',
1950
-        'A backup copy of the old notes was saved to {filename!r}.  '
1951
-        'This is a safeguard against editing mistakes, because the '
1952
-        'vault(1)-compatible legacy editor interface does not allow '
1953
-        'aborting mid-edit, and because the notes were actually changed.',
1954
-        flags='python-brace-format',
1949
+        "Warning message",
1950
+        "A backup copy of the old notes was saved to {filename!r}.  "
1951
+        "This is a safeguard against editing mistakes, because the "
1952
+        "vault(1)-compatible legacy editor interface does not allow "
1953
+        "aborting mid-edit, and because the notes were actually changed.",
1954
+        flags="python-brace-format",
1955 1955
     )
1956 1956
     NO_AF_UNIX = commented(
1957
-        '',
1957
+        "",
1958 1958
     )(
1959
-        'Warning message',
1960
-        'Cannot connect to an SSH agent via UNIX domain sockets '
1961
-        'because this Python version does not support them.',
1959
+        "Warning message",
1960
+        "Cannot connect to an SSH agent via UNIX domain sockets "
1961
+        "because this Python version does not support them.",
1962 1962
     )
1963 1963
     """"""
1964 1964
     NO_ANNOYING_OS_NAMED_PIPES = commented(
1965
-        '',
1965
+        "",
1966 1966
     )(
1967
-        'Warning message',
1968
-        'Cannot connect to an SSH agent via Windows named pipes '
1969
-        'because this Python version does not support them.',
1967
+        "Warning message",
1968
+        "Cannot connect to an SSH agent via Windows named pipes "
1969
+        "because this Python version does not support them.",
1970 1970
     )
1971 1971
     """"""
1972 1972
     PASSPHRASE_NOT_NORMALIZED = commented(
1973
-        'The key is a (vault) configuration key, in JSONPath syntax, '
1973
+        "The key is a (vault) configuration key, in JSONPath syntax, "
1974 1974
         'typically "$.global" for the global passphrase or '
1975 1975
         '"$.services.service_name" or "$.services["service with spaces"]" '
1976 1976
         'for the services "service_name" and "service with spaces", '
1977
-        'respectively.  '
1978
-        'Alternatively, it may be the value of '
1979
-        'Label.SETTINGS_ORIGIN_INTERACTIVE if the passphrase was '
1980
-        'entered interactively.  '
1981
-        'The form is one of the four Unicode normalization forms: '
1982
-        'NFC, NFD, NFKC, NFKD.  '
1983
-        'The asterisks are not special.  '
1984
-        'Please feel free to substitute any other appropriate way to '
1977
+        "respectively.  "
1978
+        "Alternatively, it may be the value of "
1979
+        "Label.SETTINGS_ORIGIN_INTERACTIVE if the passphrase was "
1980
+        "entered interactively.  "
1981
+        "The form is one of the four Unicode normalization forms: "
1982
+        "NFC, NFD, NFKC, NFKD.  "
1983
+        "The asterisks are not special.  "
1984
+        "Please feel free to substitute any other appropriate way to "
1985 1985
         'mark up emphasis of the word "displays".',
1986 1986
     )(
1987
-        'Warning message',
1988
-        'The {key} passphrase is not {form}-normalized.  '
1989
-        'Its serialization as a byte string may not be what you '
1990
-        'expect it to be, even if it *displays* correctly.  '
1991
-        'Please make sure to double-check any derived passphrases '
1992
-        'for unexpected results.',
1993
-        flags='python-brace-format',
1987
+        "Warning message",
1988
+        "The {key} passphrase is not {form}-normalized.  "
1989
+        "Its serialization as a byte string may not be what you "
1990
+        "expect it to be, even if it *displays* correctly.  "
1991
+        "Please make sure to double-check any derived passphrases "
1992
+        "for unexpected results.",
1993
+        flags="python-brace-format",
1994 1994
     )
1995 1995
     """"""
1996 1996
     SERVICE_NAME_INCOMPLETABLE = commented(
1997
-        '',
1997
+        "",
1998 1998
     )(
1999
-        'Warning message',
2000
-        'The service name {service!r} contains an ASCII control character, '
2001
-        'which is not supported by our shell completion code.  '
2002
-        'This service name will therefore not be available for completion '
2003
-        'on the command-line.  '
2004
-        'You may of course still type it in manually in whatever format '
2005
-        'your shell accepts, but we highly recommend choosing a different '
2006
-        'service name instead.',
2007
-        flags='python-brace-format',
1999
+        "Warning message",
2000
+        "The service name {service!r} contains an ASCII control character, "
2001
+        "which is not supported by our shell completion code.  "
2002
+        "This service name will therefore not be available for completion "
2003
+        "on the command-line.  "
2004
+        "You may of course still type it in manually in whatever format "
2005
+        "your shell accepts, but we highly recommend choosing a different "
2006
+        "service name instead.",
2007
+        flags="python-brace-format",
2008 2008
     )
2009 2009
     """"""
2010 2010
     SERVICE_PASSPHRASE_INEFFECTIVE = commented(
2011
-        'The key that is set need not necessarily be set at the '
2012
-        'service level; it may be a global key as well.',
2011
+        "The key that is set need not necessarily be set at the "
2012
+        "service level; it may be a global key as well.",
2013 2013
     )(
2014
-        'Warning message',
2015
-        'Setting a service passphrase is ineffective '
2016
-        'because a key is also set: {service}.',
2017
-        flags='python-brace-format',
2014
+        "Warning message",
2015
+        "Setting a service passphrase is ineffective "
2016
+        "because a key is also set: {service}.",
2017
+        flags="python-brace-format",
2018 2018
     )
2019 2019
     """"""
2020 2020
     STEP_REMOVE_INEFFECTIVE_VALUE = commented(
2021
-        '',
2021
+        "",
2022 2022
     )(
2023
-        'Warning message',
2024
-        'Removing ineffective setting {path} = {old}.',
2025
-        flags='python-brace-format',
2023
+        "Warning message",
2024
+        "Removing ineffective setting {path} = {old}.",
2025
+        flags="python-brace-format",
2026 2026
     )
2027 2027
     """"""
2028 2028
     STEP_REPLACE_INVALID_VALUE = commented(
2029
-        '',
2029
+        "",
2030 2030
     )(
2031
-        'Warning message',
2032
-        'Replacing invalid value {old} for key {path} with {new}.',
2033
-        flags='python-brace-format',
2031
+        "Warning message",
2032
+        "Replacing invalid value {old} for key {path} with {new}.",
2033
+        flags="python-brace-format",
2034 2034
     )
2035 2035
     """"""
2036 2036
     V01_STYLE_CONFIG = commented(
2037
-        '',
2037
+        "",
2038 2038
     )(
2039
-        'Warning message :: Deprecation',
2040
-        'Using deprecated v0.1-style config file {old!r}, '
2041
-        'instead of v0.2-style {new!r}.  '
2042
-        'Support for v0.1-style config filenames will be removed in v1.0.',
2043
-        flags='python-brace-format',
2039
+        "Warning message :: Deprecation",
2040
+        "Using deprecated v0.1-style config file {old!r}, "
2041
+        "instead of v0.2-style {new!r}.  "
2042
+        "Support for v0.1-style config filenames will be removed in v1.0.",
2043
+        flags="python-brace-format",
2044 2044
     )
2045 2045
     """"""
2046 2046
     V10_SUBCOMMAND_REQUIRED = commented(
2047
-        'This deprecation warning may be issued at any level, '
2048
-        'i.e. we may actually be talking about subcommands, '
2049
-        'or sub-subcommands, or sub-sub-subcommands, etc., '
2047
+        "This deprecation warning may be issued at any level, "
2048
+        "i.e. we may actually be talking about subcommands, "
2049
+        "or sub-subcommands, or sub-sub-subcommands, etc., "
2050 2050
         'which is what the "here" is supposed to indicate.',
2051 2051
     )(
2052
-        'Warning message :: Deprecation',
2053
-        'A subcommand will be required here in v1.0.  '
2054
-        'See --help for available subcommands.  '
2052
+        "Warning message :: Deprecation",
2053
+        "A subcommand will be required here in v1.0.  "
2054
+        "See --help for available subcommands.  "
2055 2055
         'Defaulting to subcommand "vault".',
2056 2056
     )
2057 2057
     """"""
... ...
@@ -2063,277 +2063,277 @@ class ErrMsgTemplate(enum.Enum):
2063 2063
     AGENT_REFUSED_LIST_KEYS = commented(
2064 2064
         '"loaded keys" being keys loaded into the agent.',
2065 2065
     )(
2066
-        'Error message',
2067
-        'The SSH agent failed to or refused to supply a list of loaded keys.',
2066
+        "Error message",
2067
+        "The SSH agent failed to or refused to supply a list of loaded keys.",
2068 2068
     )
2069 2069
     """"""
2070 2070
     AGENT_REFUSED_SIGNATURE = commented(
2071
-        'The message to be signed is the vault UUID, '
2071
+        "The message to be signed is the vault UUID, "
2072 2072
         "but there's no space to explain that here, "
2073
-        'so ideally the error message does not go into detail.',
2073
+        "so ideally the error message does not go into detail.",
2074 2074
     )(
2075
-        'Error message',
2076
-        'The SSH agent failed to or refused to issue a signature '
2077
-        'with the selected key, necessary for deriving a service passphrase.',
2075
+        "Error message",
2076
+        "The SSH agent failed to or refused to issue a signature "
2077
+        "with the selected key, necessary for deriving a service passphrase.",
2078 2078
     )
2079 2079
     """"""
2080 2080
     CANNOT_CONNECT_TO_AGENT = commented(
2081 2081
         '"error" is supplied by the operating system (errno/strerror).',
2082 2082
     )(
2083
-        'Error message',
2084
-        'Cannot connect to the SSH agent: {error}: {filename!r}.',
2085
-        flags='python-brace-format',
2083
+        "Error message",
2084
+        "Cannot connect to the SSH agent: {error}: {filename!r}.",
2085
+        flags="python-brace-format",
2086 2086
     )
2087 2087
     """"""
2088 2088
     CANNOT_DECODEIMPORT_VAULT_SETTINGS = commented(
2089 2089
         '"error" is supplied by the operating system (errno/strerror).',
2090 2090
     )(
2091
-        'Error message',
2092
-        'Cannot import vault settings: cannot decode JSON: {error}.',
2093
-        flags='python-brace-format',
2091
+        "Error message",
2092
+        "Cannot import vault settings: cannot decode JSON: {error}.",
2093
+        flags="python-brace-format",
2094 2094
     )
2095 2095
     """"""
2096 2096
     CANNOT_EXPORT_VAULT_SETTINGS = commented(
2097 2097
         '"error" is supplied by the operating system (errno/strerror).',
2098 2098
     )(
2099
-        'Error message',
2100
-        'Cannot export vault settings: {error}: {filename!r}.',
2101
-        flags='python-brace-format',
2099
+        "Error message",
2100
+        "Cannot export vault settings: {error}: {filename!r}.",
2101
+        flags="python-brace-format",
2102 2102
     )
2103 2103
     """"""
2104 2104
     CANNOT_IMPORT_VAULT_SETTINGS = commented(
2105 2105
         '"error" is supplied by the operating system (errno/strerror).',
2106 2106
     )(
2107
-        'Error message',
2108
-        'Cannot import vault settings: {error}: {filename!r}.',
2109
-        flags='python-brace-format',
2107
+        "Error message",
2108
+        "Cannot import vault settings: {error}: {filename!r}.",
2109
+        flags="python-brace-format",
2110 2110
     )
2111 2111
     """"""
2112 2112
     CANNOT_LOAD_USER_CONFIG = commented(
2113 2113
         '"error" is supplied by the operating system (errno/strerror).',
2114 2114
     )(
2115
-        'Error message',
2116
-        'Cannot load user config: {error}: {filename!r}.',
2117
-        flags='python-brace-format',
2115
+        "Error message",
2116
+        "Cannot load user config: {error}: {filename!r}.",
2117
+        flags="python-brace-format",
2118 2118
     )
2119 2119
     """"""
2120 2120
     CANNOT_LOAD_VAULT_SETTINGS = commented(
2121 2121
         '"error" is supplied by the operating system (errno/strerror).',
2122 2122
     )(
2123
-        'Error message',
2124
-        'Cannot load vault settings: {error}: {filename!r}.',
2125
-        flags='python-brace-format',
2123
+        "Error message",
2124
+        "Cannot load vault settings: {error}: {filename!r}.",
2125
+        flags="python-brace-format",
2126 2126
     )
2127 2127
     """"""
2128 2128
     CANNOT_PARSE_AS_VAULT_CONFIG = commented(
2129 2129
         'Unlike the "Cannot load {path!r} as a {fmt} '
2130 2130
         'vault configuration." message, *this* error message is emitted '
2131
-        'when we have tried loading the path in each of our '
2132
-        'supported formats, and failed.  '
2131
+        "when we have tried loading the path in each of our "
2132
+        "supported formats, and failed.  "
2133 2133
         'The user will thus see the above "Cannot load ..." warning message '
2134
-        'potentially multiple times, '
2135
-        'and this error message at the very bottom.',
2134
+        "potentially multiple times, "
2135
+        "and this error message at the very bottom.",
2136 2136
     )(
2137
-        'Error message',
2138
-        'Cannot parse {path!r} as a valid vault-native '
2139
-        'configuration file/directory.',
2140
-        flags='python-brace-format',
2137
+        "Error message",
2138
+        "Cannot parse {path!r} as a valid vault-native "
2139
+        "configuration file/directory.",
2140
+        flags="python-brace-format",
2141 2141
     )
2142 2142
     """"""
2143 2143
     CANNOT_PARSE_AS_VAULT_CONFIG_OSERROR = commented(
2144 2144
         '"error" is supplied by the operating system (errno/strerror).',
2145 2145
     )(
2146
-        'Error message',
2147
-        r'Cannot parse {path!r} as a valid vault-native '
2148
-        'configuration file/directory: {error}: {filename!r}.',
2149
-        flags='python-brace-format',
2146
+        "Error message",
2147
+        r"Cannot parse {path!r} as a valid vault-native "
2148
+        "configuration file/directory: {error}: {filename!r}.",
2149
+        flags="python-brace-format",
2150 2150
     )
2151 2151
     """"""
2152 2152
     CANNOT_STORE_VAULT_SETTINGS = commented(
2153 2153
         '"error" is supplied by the operating system (errno/strerror).',
2154 2154
     )(
2155
-        'Error message',
2156
-        'Cannot store vault settings: {error}: {filename!r}.',
2157
-        flags='python-brace-format',
2155
+        "Error message",
2156
+        "Cannot store vault settings: {error}: {filename!r}.",
2157
+        flags="python-brace-format",
2158 2158
     )
2159 2159
     """"""
2160 2160
     CANNOT_UNDERSTAND_AGENT = commented(
2161
-        'This error message is used whenever we cannot make '
2162
-        'any sense of a response from the SSH agent '
2163
-        'because the response is ill-formed '
2164
-        '(truncated, improperly encoded, etc.) '
2165
-        'or otherwise violates the communications protocol.  '
2166
-        'Well-formed responses that adhere to the protocol, '
2167
-        'even if they indicate that the requested operation failed, '
2168
-        'are handled with a different error message.',
2169
-    )(
2170
-        'Error message',
2161
+        "This error message is used whenever we cannot make "
2162
+        "any sense of a response from the SSH agent "
2163
+        "because the response is ill-formed "
2164
+        "(truncated, improperly encoded, etc.) "
2165
+        "or otherwise violates the communications protocol.  "
2166
+        "Well-formed responses that adhere to the protocol, "
2167
+        "even if they indicate that the requested operation failed, "
2168
+        "are handled with a different error message.",
2169
+    )(
2170
+        "Error message",
2171 2171
         "Cannot understand the SSH agent's response because it "
2172
-        'violates the communication protocol.',
2172
+        "violates the communication protocol.",
2173 2173
     )
2174 2174
     """"""
2175 2175
     CANNOT_UPDATE_SETTINGS_NO_SETTINGS = commented(
2176
-        'The settings_type metavar contains translations for '
2176
+        "The settings_type metavar contains translations for "
2177 2177
         'either "global settings" or "service-specific settings"; '
2178
-        'see the CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_GLOBAL and '
2179
-        'CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_SERVICE entries.  '
2180
-        'The first sentence will thus read either '
2178
+        "see the CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_GLOBAL and "
2179
+        "CANNOT_UPDATE_SETTINGS_METAVAR_SETTINGS_TYPE_SERVICE entries.  "
2180
+        "The first sentence will thus read either "
2181 2181
         '"Cannot update the global settings without any given settings." or '
2182 2182
         '"Cannot update the service-specific settings without any '
2183 2183
         'given settings.".  '
2184
-        'You may update this entry, and the two metavar entries, '
2185
-        'in any way you see fit that achieves the desired translations '
2186
-        'of the first sentence.',
2184
+        "You may update this entry, and the two metavar entries, "
2185
+        "in any way you see fit that achieves the desired translations "
2186
+        "of the first sentence.",
2187 2187
     )(
2188
-        'Error message',
2189
-        'Cannot update the {settings_type} without any given settings.  '
2190
-        'You must specify at least one of --lower, ..., --symbol, --notes, '
2191
-        'or --phrase or --key.',
2192
-        flags='python-brace-format',
2188
+        "Error message",
2189
+        "Cannot update the {settings_type} without any given settings.  "
2190
+        "You must specify at least one of --lower, ..., --symbol, --notes, "
2191
+        "or --phrase or --key.",
2192
+        flags="python-brace-format",
2193 2193
     )
2194 2194
     """"""
2195 2195
     INVALID_USER_CONFIG = commented(
2196 2196
         '"error" is supplied by the operating system (errno/strerror).',
2197 2197
     )(
2198
-        'Error message',
2199
-        'The user configuration file is invalid.  {error}: {filename!r}.',
2200
-        flags='python-brace-format',
2198
+        "Error message",
2199
+        "The user configuration file is invalid.  {error}: {filename!r}.",
2200
+        flags="python-brace-format",
2201 2201
     )
2202 2202
     """"""
2203 2203
     INVALID_VAULT_CONFIG = commented(
2204
-        'This error message is a reaction to a validator function '
2205
-        'saying *that* the configuration is not valid, '
2206
-        'but not *how* it is not valid.  '
2207
-        'The configuration file is principally parsable, however.',
2204
+        "This error message is a reaction to a validator function "
2205
+        "saying *that* the configuration is not valid, "
2206
+        "but not *how* it is not valid.  "
2207
+        "The configuration file is principally parsable, however.",
2208 2208
     )(
2209
-        'Error message',
2210
-        'Invalid vault config: {config!r}.',
2211
-        flags='python-brace-format',
2209
+        "Error message",
2210
+        "Invalid vault config: {config!r}.",
2211
+        flags="python-brace-format",
2212 2212
     )
2213 2213
     """"""
2214 2214
     MISSING_MODULE = commented(
2215
-        '',
2215
+        "",
2216 2216
     )(
2217
-        'Error message',
2218
-        'Cannot load the required Python module {module!r}.',
2219
-        flags='python-brace-format',
2217
+        "Error message",
2218
+        "Cannot load the required Python module {module!r}.",
2219
+        flags="python-brace-format",
2220 2220
     )
2221 2221
     """"""
2222 2222
     NO_AGENT_SUPPORT = commented(
2223
-        '',
2223
+        "",
2224 2224
     )(
2225
-        'Error message',
2226
-        'Cannot connect to an SSH agent because this Python version '
2227
-        'does not support communicating with it.',
2225
+        "Error message",
2226
+        "Cannot connect to an SSH agent because this Python version "
2227
+        "does not support communicating with it.",
2228 2228
     )
2229 2229
     """"""
2230 2230
     NO_KEY_OR_PHRASE = commented(
2231
-        '',
2231
+        "",
2232 2232
     )(
2233
-        'Error message',
2234
-        'No passphrase or key was given in the configuration.  '
2235
-        'In this case, the --phrase or --key argument is required.',
2233
+        "Error message",
2234
+        "No passphrase or key was given in the configuration.  "
2235
+        "In this case, the --phrase or --key argument is required.",
2236 2236
     )
2237 2237
     """"""
2238 2238
     NO_SSH_AGENT_FOUND = commented(
2239
-        '',
2239
+        "",
2240 2240
     )(
2241
-        'Error message',
2242
-        'Cannot find any running SSH agent because SSH_AUTH_SOCK is not set.',
2241
+        "Error message",
2242
+        "Cannot find any running SSH agent because SSH_AUTH_SOCK is not set.",
2243 2243
     )
2244 2244
     """"""
2245 2245
     NO_SUITABLE_SSH_KEYS = commented(
2246
-        '',
2246
+        "",
2247 2247
     )(
2248
-        'Error message',
2249
-        'The SSH agent contains no keys suitable for {PROG_NAME}.',  # noqa: RUF027
2250
-        flags='python-brace-format',
2248
+        "Error message",
2249
+        "The SSH agent contains no keys suitable for {PROG_NAME}.",  # noqa: RUF027
2250
+        flags="python-brace-format",
2251 2251
     )
2252 2252
     """"""
2253 2253
     PARAMS_MUTUALLY_EXCLUSIVE = commented(
2254
-        'The params are long-form command-line option names.  '
2254
+        "The params are long-form command-line option names.  "
2255 2255
         'Typical example: "--key is mutually exclusive with --phrase."',
2256 2256
     )(
2257
-        'Error message',
2258
-        '{param1} is mutually exclusive with {param2}.',
2259
-        flags='python-brace-format',
2257
+        "Error message",
2258
+        "{param1} is mutually exclusive with {param2}.",
2259
+        flags="python-brace-format",
2260 2260
     )
2261 2261
     """"""
2262 2262
     PARAMS_NEEDS_SERVICE = commented(
2263
-        'The param is a long-form command-line option name, '
2264
-        'the metavar is Label.VAULT_METAVAR_SERVICE.',
2263
+        "The param is a long-form command-line option name, "
2264
+        "the metavar is Label.VAULT_METAVAR_SERVICE.",
2265 2265
     )(
2266
-        'Error message',
2267
-        '{param} requires a {service_metavar}.',
2268
-        flags='python-brace-format',
2266
+        "Error message",
2267
+        "{param} requires a {service_metavar}.",
2268
+        flags="python-brace-format",
2269 2269
     )
2270 2270
     """"""
2271 2271
     PARAMS_NEEDS_SERVICE_OR_CONFIG = commented(
2272
-        'The param is a long-form command-line option name, '
2273
-        'the metavar is Label.VAULT_METAVAR_SERVICE.',
2272
+        "The param is a long-form command-line option name, "
2273
+        "the metavar is Label.VAULT_METAVAR_SERVICE.",
2274 2274
     )(
2275
-        'Error message',
2276
-        '{param} requires a {service_metavar} or --config.',
2277
-        flags='python-brace-format',
2275
+        "Error message",
2276
+        "{param} requires a {service_metavar} or --config.",
2277
+        flags="python-brace-format",
2278 2278
     )
2279 2279
     """"""
2280 2280
     PARAMS_NO_SERVICE = commented(
2281
-        'The param is a long-form command-line option name, '
2282
-        'the metavar is Label.VAULT_METAVAR_SERVICE.',
2281
+        "The param is a long-form command-line option name, "
2282
+        "the metavar is Label.VAULT_METAVAR_SERVICE.",
2283 2283
     )(
2284
-        'Error message',
2285
-        '{param} does not take a {service_metavar} argument.',
2286
-        flags='python-brace-format',
2284
+        "Error message",
2285
+        "{param} does not take a {service_metavar} argument.",
2286
+        flags="python-brace-format",
2287 2287
     )
2288 2288
     """"""
2289 2289
     SERVICE_REQUIRED = commented(
2290
-        'The metavar is Label.VAULT_METAVAR_SERVICE.',
2290
+        "The metavar is Label.VAULT_METAVAR_SERVICE.",
2291 2291
     )(
2292
-        'Error message',
2293
-        'Deriving a passphrase requires a {service_metavar}.',
2294
-        flags='python-brace-format',
2292
+        "Error message",
2293
+        "Deriving a passphrase requires a {service_metavar}.",
2294
+        flags="python-brace-format",
2295 2295
     )
2296 2296
     """"""
2297 2297
     SET_AND_UNSET_SAME_SETTING = commented(
2298
-        'The rephrasing '
2298
+        "The rephrasing "
2299 2299
         '"Attempted to unset and set the same setting '
2300 2300
         '(--unset={setting} --{setting}=...) at the same time."'
2301
-        'may or may not be more suitable as a basis for translation instead.',
2301
+        "may or may not be more suitable as a basis for translation instead.",
2302 2302
     )(
2303
-        'Error message',
2304
-        'Attempted to unset and set --{setting} at the same time.',
2305
-        flags='python-brace-format',
2303
+        "Error message",
2304
+        "Attempted to unset and set --{setting} at the same time.",
2305
+        flags="python-brace-format",
2306 2306
     )
2307 2307
     """"""
2308 2308
     SSH_KEY_NOT_LOADED = commented(
2309
-        '',
2309
+        "",
2310 2310
     )(
2311
-        'Error message',
2312
-        'The requested SSH key is not loaded into the agent.',
2311
+        "Error message",
2312
+        "The requested SSH key is not loaded into the agent.",
2313 2313
     )
2314 2314
     """"""
2315 2315
     USER_ABORTED_EDIT = commented(
2316
-        'The user requested to edit the notes for a service, '
2317
-        'but aborted the request mid-editing.',
2316
+        "The user requested to edit the notes for a service, "
2317
+        "but aborted the request mid-editing.",
2318 2318
     )(
2319
-        'Error message',
2320
-        'Not saving any new notes: the user aborted the request.',
2319
+        "Error message",
2320
+        "Not saving any new notes: the user aborted the request.",
2321 2321
     )
2322 2322
     """"""
2323 2323
     USER_ABORTED_PASSPHRASE = commented(
2324
-        'The user was prompted for a master passphrase, '
2325
-        'but aborted the request.',
2324
+        "The user was prompted for a master passphrase, "
2325
+        "but aborted the request.",
2326 2326
     )(
2327
-        'Error message',
2328
-        'No passphrase was given; the user aborted the request.',
2327
+        "Error message",
2328
+        "No passphrase was given; the user aborted the request.",
2329 2329
     )
2330 2330
     """"""
2331 2331
     USER_ABORTED_SSH_KEY_SELECTION = commented(
2332
-        'The user was prompted to select a master SSH key, '
2333
-        'but aborted the request.',
2332
+        "The user was prompted to select a master SSH key, "
2333
+        "but aborted the request.",
2334 2334
     )(
2335
-        'Error message',
2336
-        'No SSH key was selected; the user aborted the request.',
2335
+        "Error message",
2336
+        "No SSH key was selected; the user aborted the request.",
2337 2337
     )
2338 2338
     """"""
2339 2339
 
... ...
@@ -2381,7 +2381,7 @@ def _write_po_file(  # noqa: C901,PLR0912
2381 2381
     entries: dict[str, dict[str, MsgTemplate]] = {}
2382 2382
     for enum_class in MSG_TEMPLATE_CLASSES:
2383 2383
         for member in enum_class.__members__.values():
2384
-            value = cast('TranslatableString', member.value)
2384
+            value = cast("TranslatableString", member.value)
2385 2385
             ctx = value.l10n_context
2386 2386
             msg = value.singular
2387 2387
             if (
... ...
@@ -2389,15 +2389,15 @@ def _write_po_file(  # noqa: C901,PLR0912
2389 2389
                 and entries[ctx][msg] != member
2390 2390
             ):
2391 2391
                 raise AssertionError(  # noqa: TRY003
2392
-                    f'Duplicate entry for ({ctx!r}, {msg!r}): '  # noqa: EM102
2393
-                    f'{entries[ctx][msg]!r} and {member!r}'
2392
+                    f"Duplicate entry for ({ctx!r}, {msg!r}): "  # noqa: EM102
2393
+                    f"{entries[ctx][msg]!r} and {member!r}"
2394 2394
                 )
2395 2395
             entries[ctx][msg] = member
2396
-    if build_time is None and os.environ.get('SOURCE_DATE_EPOCH'):
2396
+    if build_time is None and os.environ.get("SOURCE_DATE_EPOCH"):
2397 2397
         try:
2398
-            source_date_epoch = int(os.environ['SOURCE_DATE_EPOCH'])
2398
+            source_date_epoch = int(os.environ["SOURCE_DATE_EPOCH"])
2399 2399
         except ValueError as exc:
2400
-            err_msg = 'Cannot parse SOURCE_DATE_EPOCH'
2400
+            err_msg = "Cannot parse SOURCE_DATE_EPOCH"
2401 2401
             raise RuntimeError(err_msg) from exc
2402 2402
         else:
2403 2403
             build_time = datetime.datetime.fromtimestamp(
... ...
@@ -2410,65 +2410,65 @@ def _write_po_file(  # noqa: C901,PLR0912
2410 2410
         header = (
2411 2411
             inspect.cleandoc(rf"""
2412 2412
             # English translation for {PROG_NAME}.
2413
-            # Copyright (C) {build_time.strftime('%Y')} AUTHOR
2413
+            # Copyright (C) {build_time.strftime("%Y")} AUTHOR
2414 2414
             # This file is distributed under the same license as {PROG_NAME}.
2415
-            # AUTHOR <someone@example.com>, {build_time.strftime('%Y')}.
2415
+            # AUTHOR <someone@example.com>, {build_time.strftime("%Y")}.
2416 2416
             #
2417 2417
             msgid ""
2418 2418
             msgstr ""
2419
-            """).removesuffix('\n')
2420
-            + '\n'
2419
+            """).removesuffix("\n")
2420
+            + "\n"
2421 2421
         )
2422 2422
     else:
2423 2423
         header = (
2424 2424
             inspect.cleandoc(rf"""
2425 2425
             # English debug translation for {PROG_NAME}.
2426
-            # Copyright (C) {build_time.strftime('%Y')} {AUTHOR}
2426
+            # Copyright (C) {build_time.strftime("%Y")} {AUTHOR}
2427 2427
             # This file is distributed under the same license as {PROG_NAME}.
2428 2428
             #
2429 2429
             msgid ""
2430 2430
             msgstr ""
2431
-            """).removesuffix('\n')
2432
-            + '\n'
2431
+            """).removesuffix("\n")
2432
+            + "\n"
2433 2433
         )
2434 2434
     fileobj.write(header)
2435 2435
     po_info = {
2436
-        'Project-Id-Version': f'{PROG_NAME} {version}',
2437
-        'Report-Msgid-Bugs-To': 'software@the13thletter.info',
2438
-        'PO-Revision-Date': build_time.strftime('%Y-%m-%d %H:%M%z'),
2439
-        'MIME-Version': '1.0',
2440
-        'Content-Type': 'text/plain; charset=UTF-8',
2441
-        'Content-Transfer-Encoding': '8bit',
2442
-        'Plural-Forms': 'nplurals=2; plural=(n != 1);',
2436
+        "Project-Id-Version": f"{PROG_NAME} {version}",
2437
+        "Report-Msgid-Bugs-To": "software@the13thletter.info",
2438
+        "PO-Revision-Date": build_time.strftime("%Y-%m-%d %H:%M%z"),
2439
+        "MIME-Version": "1.0",
2440
+        "Content-Type": "text/plain; charset=UTF-8",
2441
+        "Content-Transfer-Encoding": "8bit",
2442
+        "Plural-Forms": "nplurals=2; plural=(n != 1);",
2443 2443
     }
2444 2444
     if is_template:
2445 2445
         po_info.update({
2446
-            'POT-Creation-Date': build_time.strftime('%Y-%m-%d %H:%M%z'),
2447
-            'Last-Translator': 'AUTHOR <someone@example.com>',
2448
-            'Language': 'en',
2449
-            'Language-Team': 'English',
2446
+            "POT-Creation-Date": build_time.strftime("%Y-%m-%d %H:%M%z"),
2447
+            "Last-Translator": "AUTHOR <someone@example.com>",
2448
+            "Language": "en",
2449
+            "Language-Team": "English",
2450 2450
         })
2451 2451
     else:
2452 2452
         po_info.update({
2453
-            'Last-Translator': AUTHOR,
2454
-            'Language': 'en_US@DEBUG',
2455
-            'Language-Team': 'English',
2453
+            "Last-Translator": AUTHOR,
2454
+            "Language": "en_US@DEBUG",
2455
+            "Language-Team": "English",
2456 2456
         })
2457
-    print(*_format_po_info(po_info), sep='\n', end='\n', file=fileobj)
2457
+    print(*_format_po_info(po_info), sep="\n", end="\n", file=fileobj)
2458 2458
 
2459 2459
     context_class = {
2460
-        'Label': Label,
2461
-        'Debug message': DebugMsgTemplate,
2462
-        'Info message': InfoMsgTemplate,
2463
-        'Warning message': WarnMsgTemplate,
2464
-        'Error message': ErrMsgTemplate,
2460
+        "Label": Label,
2461
+        "Debug message": DebugMsgTemplate,
2462
+        "Info message": InfoMsgTemplate,
2463
+        "Warning message": WarnMsgTemplate,
2464
+        "Error message": ErrMsgTemplate,
2465 2465
     }
2466 2466
 
2467 2467
     def _sort_position_msg_template_class(
2468 2468
         item: tuple[str, Any],
2469 2469
         /,
2470 2470
     ) -> tuple[int, str]:
2471
-        context_type = item[0].split(' :: ')[0]
2471
+        context_type = item[0].split(" :: ")[0]
2472 2472
         return (
2473 2473
             MSG_TEMPLATE_CLASSES.index(context_class[context_type]),
2474 2474
             item[0],
... ...
@@ -2480,7 +2480,7 @@ def _write_po_file(  # noqa: C901,PLR0912
2480 2480
         for _msg, enum_value in sorted(
2481 2481
             subdict.items(), key=lambda kv: str(kv[1])
2482 2482
         ):
2483
-            value = cast('TranslatableString', enum_value.value)
2483
+            value = cast("TranslatableString", enum_value.value)
2484 2484
             value2 = value.maybe_without_filename()
2485 2485
             fileobj.writelines(
2486 2486
                 _format_po_entry(
... ...
@@ -2503,29 +2503,29 @@ def _format_po_info(
2503 2503
 ) -> Iterator[str]:  # pragma: no cover [internal]
2504 2504
     """"""  # noqa: D419
2505 2505
     sortorder = [
2506
-        'project-id-version',
2507
-        'report-msgid-bugs-to',
2508
-        'pot-creation-date',
2509
-        'po-revision-date',
2510
-        'last-translator',
2511
-        'language',
2512
-        'language-team',
2513
-        'mime-version',
2514
-        'content-type',
2515
-        'content-transfer-encoding',
2516
-        'plural-forms',
2506
+        "project-id-version",
2507
+        "report-msgid-bugs-to",
2508
+        "pot-creation-date",
2509
+        "po-revision-date",
2510
+        "last-translator",
2511
+        "language",
2512
+        "language-team",
2513
+        "mime-version",
2514
+        "content-type",
2515
+        "content-transfer-encoding",
2516
+        "plural-forms",
2517 2517
     ]
2518 2518
 
2519 2519
     def _sort_position(s: str, /) -> int:
2520 2520
         n = len(sortorder)
2521 2521
         for i, x in enumerate(sortorder):
2522
-            if s.lower().rstrip(':') == x:
2522
+            if s.lower().rstrip(":") == x:
2523 2523
                 return i
2524 2524
         return n
2525 2525
 
2526 2526
     for key in sorted(data.keys(), key=_sort_position):
2527 2527
         value = data[key]
2528
-        line = f'{key}: {value}\n'
2528
+        line = f"{key}: {value}\n"
2529 2529
         yield _cstr(line)
2530 2530
 
2531 2531
 
... ...
@@ -2537,27 +2537,27 @@ def _format_po_entry(
2537 2537
     transformed_string: TranslatableString | None = None,
2538 2538
 ) -> tuple[str, ...]:  # pragma: no cover [internal]
2539 2539
     """"""  # noqa: D419
2540
-    ret: list[str] = ['\n']
2541
-    ts = transformed_string or cast('TranslatableString', enum_value.value)
2540
+    ret: list[str] = ["\n"]
2541
+    ts = transformed_string or cast("TranslatableString", enum_value.value)
2542 2542
     if ts.translator_comments:
2543 2543
         comments = ts.translator_comments.splitlines(False)  # noqa: FBT003
2544
-        comments.extend(['', f'Message-ID: {enum_value}'])
2544
+        comments.extend(["", f"Message-ID: {enum_value}"])
2545 2545
     else:
2546
-        comments = [f'TRANSLATORS: Message-ID: {enum_value}']
2547
-    ret.extend(f'#. {line}\n' for line in comments)
2546
+        comments = [f"TRANSLATORS: Message-ID: {enum_value}"]
2547
+    ret.extend(f"#. {line}\n" for line in comments)
2548 2548
     if ts.flags:
2549
-        ret.append(f'#, {", ".join(sorted(ts.flags))}\n')
2549
+        ret.append(f"#, {', '.join(sorted(ts.flags))}\n")
2550 2550
     if ts.l10n_context:
2551
-        ret.append(f'msgctxt {_cstr(ts.l10n_context)}\n')
2552
-    ret.append(f'msgid {_cstr(ts.singular)}\n')
2551
+        ret.append(f"msgctxt {_cstr(ts.l10n_context)}\n")
2552
+    ret.append(f"msgid {_cstr(ts.singular)}\n")
2553 2553
     if ts.plural:
2554
-        ret.append(f'msgid_plural {_cstr(ts.plural)}\n')
2554
+        ret.append(f"msgid_plural {_cstr(ts.plural)}\n")
2555 2555
     value = (
2556 2556
         DebugTranslations().pgettext(ts.l10n_context, ts.singular)
2557 2557
         if is_debug_translation
2558
-        else ''
2558
+        else ""
2559 2559
     )
2560
-    ret.append(f'msgstr {_cstr(value)}\n')
2560
+    ret.append(f"msgstr {_cstr(value)}\n")
2561 2561
     return tuple(ret)
2562 2562
 
2563 2563
 
... ...
@@ -2566,75 +2566,75 @@ def _cstr(s: str) -> str:  # pragma: no cover [internal]
2566 2566
 
2567 2567
     def escape(string: str) -> str:
2568 2568
         return string.translate({
2569
-            0: r'\000',
2570
-            1: r'\001',
2571
-            2: r'\002',
2572
-            3: r'\003',
2573
-            4: r'\004',
2574
-            5: r'\005',
2575
-            6: r'\006',
2576
-            7: r'\007',
2577
-            8: r'\b',
2578
-            9: r'\t',
2579
-            10: r'\n',
2580
-            11: r'\013',
2581
-            12: r'\f',
2582
-            13: r'\r',
2583
-            14: r'\016',
2584
-            15: r'\017',
2585
-            ord('"'): r'\"',
2586
-            ord('\\'): r'\\',
2587
-            127: r'\177',
2569
+            0: r"\000",
2570
+            1: r"\001",
2571
+            2: r"\002",
2572
+            3: r"\003",
2573
+            4: r"\004",
2574
+            5: r"\005",
2575
+            6: r"\006",
2576
+            7: r"\007",
2577
+            8: r"\b",
2578
+            9: r"\t",
2579
+            10: r"\n",
2580
+            11: r"\013",
2581
+            12: r"\f",
2582
+            13: r"\r",
2583
+            14: r"\016",
2584
+            15: r"\017",
2585
+            ord('"'): r"\"",
2586
+            ord("\\"): r"\\",
2587
+            127: r"\177",
2588 2588
         })
2589 2589
 
2590
-    return '\n'.join(
2590
+    return "\n".join(
2591 2591
         f'"{escape(line)}"'
2592
-        for line in s.splitlines(True) or ['']  # noqa: FBT003
2592
+        for line in s.splitlines(True) or [""]  # noqa: FBT003
2593 2593
     )
2594 2594
 
2595 2595
 
2596
-if __name__ == '__main__':
2596
+if __name__ == "__main__":
2597 2597
     import argparse
2598 2598
 
2599 2599
     def validate_build_time(value: str | None) -> datetime.datetime | None:
2600 2600
         if value is None:
2601 2601
             return None
2602 2602
         ret = datetime.datetime.fromisoformat(value)
2603
-        if ret.isoformat(sep=' ', timespec='seconds') != value:
2604
-            raise ValueError(f'invalid time specification: {value}')  # noqa: EM102,TRY003
2603
+        if ret.isoformat(sep=" ", timespec="seconds") != value:
2604
+            raise ValueError(f"invalid time specification: {value}")  # noqa: EM102,TRY003
2605 2605
         return ret
2606 2606
 
2607 2607
     ap = argparse.ArgumentParser()
2608 2608
     ex = ap.add_mutually_exclusive_group()
2609 2609
     ex.add_argument(
2610
-        '--template',
2611
-        action='store_true',
2612
-        dest='is_template',
2610
+        "--template",
2611
+        action="store_true",
2612
+        dest="is_template",
2613 2613
         default=True,
2614
-        help='Generate a template file (default)',
2614
+        help="Generate a template file (default)",
2615 2615
     )
2616 2616
     ex.add_argument(
2617
-        '--debug-translation',
2618
-        action='store_false',
2619
-        dest='is_template',
2617
+        "--debug-translation",
2618
+        action="store_false",
2619
+        dest="is_template",
2620 2620
         default=True,
2621 2621
         help='Generate a "debug" translation file',
2622 2622
     )
2623 2623
     ap.add_argument(
2624
-        '--set-version',
2625
-        action='store',
2626
-        dest='version',
2624
+        "--set-version",
2625
+        action="store",
2626
+        dest="version",
2627 2627
         default=VERSION,
2628
-        help='Override declared software version',
2628
+        help="Override declared software version",
2629 2629
     )
2630 2630
     ap.add_argument(
2631
-        '--set-build-time',
2632
-        action='store',
2633
-        dest='build_time',
2631
+        "--set-build-time",
2632
+        action="store",
2633
+        dest="build_time",
2634 2634
         default=None,
2635 2635
         type=validate_build_time,
2636
-        help='Override the time of build (YYYY-MM-DD HH:MM:SS+HH:MM format, '
2637
-        'default: $SOURCE_DATE_EPOCH, or the current time)',
2636
+        help="Override the time of build (YYYY-MM-DD HH:MM:SS+HH:MM format, "
2637
+        "default: $SOURCE_DATE_EPOCH, or the current time)",
2638 2638
     )
2639 2639
     args = ap.parse_args()
2640 2640
     _write_po_file(
... ...
@@ -36,11 +36,11 @@ if TYPE_CHECKING:
36 36
     )
37 37
 
38 38
 __all__ = (
39
-    'SSH_AGENT',
40
-    'SSH_AGENTC',
41
-    'SSHKeyCommentPair',
42
-    'VaultConfig',
43
-    'is_vault_config',
39
+    "SSH_AGENT",
40
+    "SSH_AGENTC",
41
+    "SSHKeyCommentPair",
42
+    "VaultConfig",
43
+    "is_vault_config",
44 44
 )
45 45
 
46 46
 
... ...
@@ -49,7 +49,7 @@ class _Omitted:
49 49
         return False
50 50
 
51 51
     def __repr__(self) -> str:
52
-        return '...'
52
+        return "..."
53 53
 
54 54
 
55 55
 class VaultConfigGlobalSettings(TypedDict, total=False):
... ...
@@ -95,7 +95,7 @@ class VaultConfigGlobalSettings(TypedDict, total=False):
95 95
     phrase: NotRequired[str]
96 96
     """"""
97 97
     unicode_normalization_form: NotRequired[
98
-        Literal['NFC', 'NFD', 'NFKC', 'NFKD']
98
+        Literal["NFC", "NFD", "NFKC", "NFKD"]
99 99
     ]
100 100
     """"""
101 101
     length: NotRequired[int]
... ...
@@ -153,8 +153,8 @@ class VaultConfigServicesSettings(VaultConfigGlobalSettings, total=False):
153 153
 
154 154
 
155 155
 _VaultConfig = TypedDict(
156
-    '_VaultConfig',
157
-    {'global': NotRequired[VaultConfigGlobalSettings]},
156
+    "_VaultConfig",
157
+    {"global": NotRequired[VaultConfigGlobalSettings]},
158 158
     total=False,
159 159
 )
160 160
 
... ...
@@ -193,15 +193,15 @@ def json_path(path: Sequence[str | int], /) -> str:
193 193
         JSON value.
194 194
 
195 195
     Examples:
196
-        >>> json_path(['global', 'phrase'])
196
+        >>> json_path(["global", "phrase"])
197 197
         '$.global.phrase'
198
-        >>> json_path(['services', 'service name with spaces', 'length'])
198
+        >>> json_path(["services", "service name with spaces", "length"])
199 199
         '$.services["service name with spaces"].length'
200
-        >>> json_path(['services', 'special\u000acharacters', 'notes'])
200
+        >>> json_path(["services", "special\u000acharacters", "notes"])
201 201
         '$.services["special\\ncharacters"].notes'
202
-        >>> print(json_path(['services', 'special\u000acharacters', 'notes']))
202
+        >>> print(json_path(["services", "special\u000acharacters", "notes"]))
203 203
         $.services["special\ncharacters"].notes
204
-        >>> json_path(['custom_array', 2, 0])
204
+        >>> json_path(["custom_array", 2, 0])
205 205
         '$.custom_array[2][0]'
206 206
 
207 207
     """
... ...
@@ -210,7 +210,7 @@ def json_path(path: Sequence[str | int], /) -> str:
210 210
         initial = (
211 211
             frozenset(string.ascii_lowercase)
212 212
             | frozenset(string.ascii_uppercase)
213
-            | frozenset('_')
213
+            | frozenset("_")
214 214
         )
215 215
         chars = initial | frozenset(string.digits)
216 216
         return not (
... ...
@@ -220,15 +220,15 @@ def json_path(path: Sequence[str | int], /) -> str:
220 220
             and x[:1] in initial
221 221
         )
222 222
 
223
-    chunks = ['$']
223
+    chunks = ["$"]
224 224
     chunks.extend(
225
-        f'[{json.dumps(x)}]' if needs_longhand(x) else f'.{x}' for x in path
225
+        f"[{json.dumps(x)}]" if needs_longhand(x) else f".{x}" for x in path
226 226
     )
227
-    return ''.join(chunks)
227
+    return "".join(chunks)
228 228
 
229 229
 
230 230
 class _VaultConfigValidator:
231
-    INVALID_CONFIG_ERROR = 'vault config is invalid'
231
+    INVALID_CONFIG_ERROR = "vault config is invalid"
232 232
 
233 233
     def __init__(self, maybe_config: Any) -> None:  # noqa: ANN401
234 234
         self.maybe_config = maybe_config
... ...
@@ -242,86 +242,86 @@ class _VaultConfigValidator:
242 242
     def walk_subconfigs(
243 243
         self,
244 244
     ) -> Iterator[tuple[tuple[str] | tuple[str, str], str, Any]]:
245
-        obj = cast('dict[str, dict[str, Any]]', self.maybe_config)
246
-        if isinstance(obj.get('global', False), dict):
247
-            for k, v in list(obj['global'].items()):
248
-                yield ('global',), k, v
249
-        for sv_name, sv_obj in list(obj['services'].items()):
245
+        obj = cast("dict[str, dict[str, Any]]", self.maybe_config)
246
+        if isinstance(obj.get("global", False), dict):
247
+            for k, v in list(obj["global"].items()):
248
+                yield ("global",), k, v
249
+        for sv_name, sv_obj in list(obj["services"].items()):
250 250
             for k, v in list(sv_obj.items()):
251
-                yield ('services', sv_name), k, v
251
+                yield ("services", sv_name), k, v
252 252
 
253 253
     def validate(  # noqa: C901,PLR0912
254 254
         self,
255 255
         *,
256 256
         allow_unknown_settings: bool = False,
257 257
     ) -> None:
258
-        err_obj_not_a_dict = 'vault config is not a dict'
258
+        err_obj_not_a_dict = "vault config is not a dict"
259 259
         err_non_str_service_name = (
260
-            'vault config contains non-string service name {sv_name!r}'
260
+            "vault config contains non-string service name {sv_name!r}"
261 261
         )
262
-        err_not_a_dict = 'vault config entry {json_path_str} is not a dict'
263
-        err_not_a_string = 'vault config entry {json_path_str} is not a string'
264
-        err_not_an_int = 'vault config entry {json_path_str} is not an integer'
262
+        err_not_a_dict = "vault config entry {json_path_str} is not a dict"
263
+        err_not_a_string = "vault config entry {json_path_str} is not a string"
264
+        err_not_an_int = "vault config entry {json_path_str} is not an integer"
265 265
         err_unknown_setting = (
266
-            'vault config entry {json_path_str} uses unknown setting {key!r}'
266
+            "vault config entry {json_path_str} uses unknown setting {key!r}"
267 267
         )
268
-        err_bad_number0 = 'vault config entry {json_path_str} is negative'
269
-        err_bad_number1 = 'vault config entry {json_path_str} is not positive'
268
+        err_bad_number0 = "vault config entry {json_path_str} is negative"
269
+        err_bad_number1 = "vault config entry {json_path_str} is not positive"
270 270
 
271 271
         kwargs: dict[str, Any] = {
272
-            'allow_unknown_settings': allow_unknown_settings,
272
+            "allow_unknown_settings": allow_unknown_settings,
273 273
         }
274 274
         if not isinstance(self.maybe_config, dict):
275 275
             raise TypeError(err_obj_not_a_dict.format(**kwargs))
276
-        if 'global' in self.maybe_config:
277
-            o_global = self.maybe_config['global']
276
+        if "global" in self.maybe_config:
277
+            o_global = self.maybe_config["global"]
278 278
             if not isinstance(o_global, dict):
279
-                kwargs['json_path_str'] = json_path(['global'])
279
+                kwargs["json_path_str"] = json_path(["global"])
280 280
                 raise TypeError(err_not_a_dict.format(**kwargs))
281
-        if not isinstance(self.maybe_config.get('services'), dict):
282
-            kwargs['json_path_str'] = json_path(['services'])
281
+        if not isinstance(self.maybe_config.get("services"), dict):
282
+            kwargs["json_path_str"] = json_path(["services"])
283 283
             raise TypeError(err_not_a_dict.format(**kwargs))
284
-        for sv_name, service in self.maybe_config['services'].items():
284
+        for sv_name, service in self.maybe_config["services"].items():
285 285
             if not isinstance(sv_name, str):
286
-                kwargs['sv_name'] = sv_name
286
+                kwargs["sv_name"] = sv_name
287 287
                 raise TypeError(err_non_str_service_name.format(**kwargs))
288 288
             if not isinstance(service, dict):
289
-                kwargs['json_path_str'] = json_path(['services', sv_name])
289
+                kwargs["json_path_str"] = json_path(["services", sv_name])
290 290
                 raise TypeError(err_not_a_dict.format(**kwargs))
291 291
         for path, key, value in self.walk_subconfigs():
292
-            kwargs['path'] = path
293
-            kwargs['key'] = key
294
-            kwargs['value'] = value
295
-            kwargs['json_path_str'] = json_path([*path, key])
292
+            kwargs["path"] = path
293
+            kwargs["key"] = key
294
+            kwargs["value"] = value
295
+            kwargs["json_path_str"] = json_path([*path, key])
296 296
             # TODO(the-13th-letter): Rewrite using structural pattern
297 297
             # matching.
298 298
             # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9
299
-            if key in {'key', 'phrase'}:
299
+            if key in {"key", "phrase"}:
300 300
                 if not isinstance(value, str):
301 301
                     raise TypeError(err_not_a_string.format(**kwargs))
302
-            elif key == 'unicode_normalization_form' and path == ('global',):
302
+            elif key == "unicode_normalization_form" and path == ("global",):
303 303
                 if not isinstance(value, str):
304 304
                     raise TypeError(err_not_a_string.format(**kwargs))
305 305
                 if not allow_unknown_settings:
306 306
                     raise ValueError(err_unknown_setting.format(**kwargs))
307
-            elif key == 'notes' and path != ('global',):
307
+            elif key == "notes" and path != ("global",):
308 308
                 if not isinstance(value, str):
309 309
                     raise TypeError(err_not_a_string.format(**kwargs))
310 310
             elif key in {
311
-                'length',
312
-                'repeat',
313
-                'lower',
314
-                'upper',
315
-                'number',
316
-                'space',
317
-                'dash',
318
-                'symbol',
311
+                "length",
312
+                "repeat",
313
+                "lower",
314
+                "upper",
315
+                "number",
316
+                "space",
317
+                "dash",
318
+                "symbol",
319 319
             }:
320 320
                 if not isinstance(value, int):
321 321
                     raise TypeError(err_not_an_int.format(**kwargs))
322
-                if key == 'length' and value < 1:
322
+                if key == "length" and value < 1:
323 323
                     raise ValueError(err_bad_number1.format(**kwargs))
324
-                if key != 'length' and value < 0:
324
+                if key != "length" and value < 0:
325 325
                     raise ValueError(err_bad_number0.format(**kwargs))
326 326
             elif not allow_unknown_settings:
327 327
                 raise ValueError(err_unknown_setting.format(**kwargs))
... ...
@@ -330,19 +330,19 @@ class _VaultConfigValidator:
330 330
         obj = self.maybe_config
331 331
         if (
332 332
             not isinstance(obj, dict)
333
-            or 'services' not in obj
334
-            or not isinstance(obj['services'], dict)
333
+            or "services" not in obj
334
+            or not isinstance(obj["services"], dict)
335 335
         ):
336 336
             raise ValueError(
337 337
                 self.INVALID_CONFIG_ERROR
338 338
             )  # pragma: no cover [failsafe]
339
-        if 'global' in obj and not isinstance(obj['global'], dict):
339
+        if "global" in obj and not isinstance(obj["global"], dict):
340 340
             raise ValueError(
341 341
                 self.INVALID_CONFIG_ERROR
342 342
             )  # pragma: no cover [failsafe]
343 343
         if not all(
344 344
             isinstance(service_obj, dict)
345
-            for service_obj in obj['services'].values()
345
+            for service_obj in obj["services"].values()
346 346
         ):
347 347
             raise ValueError(
348 348
                 self.INVALID_CONFIG_ERROR
... ...
@@ -357,60 +357,60 @@ class _VaultConfigValidator:
357 357
             )
358 358
 
359 359
         def falsy_but_not_string(value: Any) -> bool:  # noqa: ANN401
360
-            return not js_truthiness(value) and value != ''  # noqa: PLC1901
360
+            return not js_truthiness(value) and value != ""  # noqa: PLC1901
361 361
 
362 362
         for path, key, value in self.walk_subconfigs():
363 363
             service_obj = self.traverse_path(path)
364 364
             # TODO(the-13th-letter): Rewrite using structural pattern
365 365
             # matching.
366 366
             # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9
367
-            if key == 'phrase' and falsy_but_not_string(value):
367
+            if key == "phrase" and falsy_but_not_string(value):
368 368
                 yield CleanupStep(
369
-                    (*path, key), service_obj[key], 'replace', ''
369
+                    (*path, key), service_obj[key], "replace", ""
370 370
                 )
371
-                service_obj[key] = ''
372
-            elif key == 'notes' and falsy(value):
371
+                service_obj[key] = ""
372
+            elif key == "notes" and falsy(value):
373 373
                 yield CleanupStep(
374
-                    (*path, key), service_obj[key], 'remove', None
374
+                    (*path, key), service_obj[key], "remove", None
375 375
                 )
376 376
                 service_obj.pop(key)
377
-            elif key == 'key' and falsy(value):
378
-                if path == ('global',):
377
+            elif key == "key" and falsy(value):
378
+                if path == ("global",):
379 379
                     yield CleanupStep(
380
-                        (*path, key), service_obj[key], 'remove', None
380
+                        (*path, key), service_obj[key], "remove", None
381 381
                     )
382 382
                     service_obj.pop(key)
383 383
                 else:
384 384
                     yield CleanupStep(
385
-                        (*path, key), service_obj[key], 'replace', ''
385
+                        (*path, key), service_obj[key], "replace", ""
386 386
                     )
387
-                    service_obj[key] = ''
388
-            elif key == 'length' and falsy(value):
387
+                    service_obj[key] = ""
388
+            elif key == "length" and falsy(value):
389 389
                 yield CleanupStep(
390
-                    (*path, key), service_obj[key], 'replace', 20
390
+                    (*path, key), service_obj[key], "replace", 20
391 391
                 )
392 392
                 service_obj[key] = 20
393
-            elif key == 'repeat' and falsy_but_not_zero(value):
394
-                yield CleanupStep((*path, key), service_obj[key], 'replace', 0)
393
+            elif key == "repeat" and falsy_but_not_zero(value):
394
+                yield CleanupStep((*path, key), service_obj[key], "replace", 0)
395 395
                 service_obj[key] = 0
396 396
             elif key in {
397
-                'lower',
398
-                'upper',
399
-                'number',
400
-                'space',
401
-                'dash',
402
-                'symbol',
397
+                "lower",
398
+                "upper",
399
+                "number",
400
+                "space",
401
+                "dash",
402
+                "symbol",
403 403
             } and falsy_but_not_zero(value):
404 404
                 yield CleanupStep(
405
-                    (*path, key), service_obj[key], 'remove', None
405
+                    (*path, key), service_obj[key], "remove", None
406 406
                 )
407 407
                 service_obj.pop(key)
408 408
 
409 409
 
410 410
 @overload
411 411
 @deprecated(
412
-    'allow_derivepassphrase_extensions argument is deprecated since v0.4.0, '
413
-    'to be removed in v1.0: no extensions are defined'
412
+    "allow_derivepassphrase_extensions argument is deprecated since v0.4.0, "
413
+    "to be removed in v1.0: no extensions are defined"
414 414
 )
415 415
 def validate_vault_config(
416 416
     obj: Any,  # noqa: ANN401
... ...
@@ -496,7 +496,7 @@ def is_vault_config(obj: Any) -> TypeIs[VaultConfig]:  # noqa: ANN401
496 496
             allow_unknown_settings=True,
497 497
         )
498 498
     except (TypeError, ValueError) as exc:
499
-        if 'vault config ' not in str(exc):  # pragma: no cover [failsafe]
499
+        if "vault config " not in str(exc):  # pragma: no cover [failsafe]
500 500
             raise
501 501
         return False
502 502
     return True
... ...
@@ -532,7 +532,7 @@ def js_truthiness(value: Any, /) -> bool:  # noqa: ANN401
532 532
 
533 533
     """  # noqa: RUF002
534 534
     try:
535
-        if value in {None, False, 0, 0.0, ''}:  # noqa: B033
535
+        if value in {None, False, 0, 0.0, ""}:  # noqa: B033
536 536
             return False
537 537
     except TypeError:
538 538
         # All falsy values are hashable, so this can't be falsy.
... ...
@@ -561,7 +561,7 @@ class CleanupStep(NamedTuple):
561 561
     """"""
562 562
     old_value: Any
563 563
     """"""
564
-    action: Literal['replace', 'remove']
564
+    action: Literal["replace", "remove"]
565 565
     """"""
566 566
     new_value: Any
567 567
     """"""
... ...
@@ -605,7 +605,7 @@ def clean_up_falsy_vault_config_values(
605 605
 
606 606
 # TODO(the-13th-letter): Use type variables local to each class.
607 607
 # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.11
608
-T_Buffer = TypeVar('T_Buffer', bound=Buffer)
608
+T_Buffer = TypeVar("T_Buffer", bound=Buffer)
609 609
 """
610 610
 A [`TypeVar`][] for classes implementing the [`Buffer`][] interface.
611 611
 
... ...
@@ -805,7 +805,7 @@ class PEP508Extra(str, enum.Enum):
805 805
 
806 806
     """
807 807
 
808
-    EXPORT = 'export'
808
+    EXPORT = "export"
809 809
     """"""
810 810
 
811 811
     @_feature_test_function
... ...
@@ -814,7 +814,7 @@ class PEP508Extra(str, enum.Enum):
814 814
         """Return true if [`PEP508Extra.EXPORT`][] is currently supported."""
815 815
         import importlib.util  # noqa: PLC0415
816 816
 
817
-        return importlib.util.find_spec('cryptography') is not None
817
+        return importlib.util.find_spec("cryptography") is not None
818 818
 
819 819
     def test(self, *_args: Any, **_kwargs: Any) -> bool:  # noqa: ANN401
820 820
         """Return true if this extra is enabled."""
... ...
@@ -840,7 +840,7 @@ class Feature(str, enum.Enum):
840 840
 
841 841
     """
842 842
 
843
-    SSH_KEY = 'master SSH key'
843
+    SSH_KEY = "master SSH key"
844 844
     """"""
845 845
 
846 846
     @_feature_test_function
... ...
@@ -896,7 +896,7 @@ class DerivationScheme(str, enum.Enum):
896 896
 
897 897
     """
898 898
 
899
-    VAULT = 'vault'
899
+    VAULT = "vault"
900 900
     """"""
901 901
 
902 902
     def test(self, *_args: Any, **_kwargs: Any) -> bool:  # noqa: ANN401
... ...
@@ -923,7 +923,7 @@ class ForeignConfigurationFormat(str, enum.Enum):
923 923
 
924 924
     """
925 925
 
926
-    VAULT_STOREROOM = 'vault storeroom'
926
+    VAULT_STOREROOM = "vault storeroom"
927 927
     """"""
928 928
 
929 929
     @_feature_test_function
... ...
@@ -934,9 +934,9 @@ class ForeignConfigurationFormat(str, enum.Enum):
934 934
 
935 935
         return not storeroom.STUBBED
936 936
 
937
-    VAULT_V02 = 'vault v0.2'
937
+    VAULT_V02 = "vault v0.2"
938 938
     """"""
939
-    VAULT_V03 = 'vault v0.3'
939
+    VAULT_V03 = "vault v0.3"
940 940
     """"""
941 941
 
942 942
     @_feature_test_function
... ...
@@ -971,7 +971,7 @@ class ExportSubcommand(str, enum.Enum):
971 971
 
972 972
     """
973 973
 
974
-    VAULT = 'vault'
974
+    VAULT = "vault"
975 975
     """"""
976 976
 
977 977
     def test(self, *_args: Any, **_kwargs: Any) -> bool:  # noqa: ANN401
... ...
@@ -993,9 +993,9 @@ class Subcommand(str, enum.Enum):
993 993
 
994 994
     """
995 995
 
996
-    EXPORT = 'export'
996
+    EXPORT = "export"
997 997
     """"""
998
-    VAULT = 'vault'
998
+    VAULT = "vault"
999 999
     """"""
1000 1000
 
1001 1001
     def test(self, *_args: Any, **_kwargs: Any) -> bool:  # noqa: ANN401
... ...
@@ -1033,7 +1033,7 @@ class SSHAgentSocket(Protocol):
1033 1033
     def recv(self, data: int, flags: int = 0, /) -> bytes: ...
1034 1034
 
1035 1035
 
1036
-SSHAgentSocketProvider: TypeAlias = 'Callable[[], SSHAgentSocket]'
1036
+SSHAgentSocketProvider: TypeAlias = "Callable[[], SSHAgentSocket]"
1037 1037
 """A callable that provides an SSH agent socket."""
1038 1038
 
1039 1039
 
... ...
@@ -38,7 +38,7 @@ if TYPE_CHECKING:
38 38
     from collections.abc import Set as AbstractSet
39 39
     from contextlib import AbstractContextManager
40 40
 
41
-__all__ = ('derivepassphrase',)
41
+__all__ = ("derivepassphrase",)
42 42
 
43 43
 PROG_NAME = _internals.PROG_NAME
44 44
 VERSION = _internals.VERSION
... ...
@@ -46,9 +46,9 @@ VERSION = _internals.VERSION
46 46
 
47 47
 @click.group(
48 48
     context_settings={
49
-        'help_option_names': ['-h', '--help'],
50
-        'ignore_unknown_options': True,
51
-        'allow_interspersed_args': False,
49
+        "help_option_names": ["-h", "--help"],
50
+        "ignore_unknown_options": True,
51
+        "allow_interspersed_args": False,
52 52
     },
53 53
     epilog=_msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EPILOG_01),
54 54
     invoke_without_command=True,
... ...
@@ -79,18 +79,18 @@ def derivepassphrase(ctx: click.Context, /) -> None:
79 79
     """
80 80
     # TODO(the-13th-letter): Turn this callback into a no-op in v1.0.
81 81
     # https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#v1.0-implied-subcommands
82
-    deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
82
+    deprecation = logging.getLogger(f"{PROG_NAME}.deprecation")
83 83
     if ctx.invoked_subcommand is None:
84 84
         deprecation.warning(
85 85
             _msg.TranslatedString(
86 86
                 _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
87 87
             ),
88
-            extra={'color': ctx.color},
88
+            extra={"color": ctx.color},
89 89
         )
90 90
         # See definition of click.Group.invoke, non-chained case.
91 91
         with ctx:
92 92
             sub_ctx = derivepassphrase_vault.make_context(
93
-                'vault', ctx.args, parent=ctx
93
+                "vault", ctx.args, parent=ctx
94 94
             )
95 95
             with sub_ctx:
96 96
                 return derivepassphrase_vault.invoke(sub_ctx)
... ...
@@ -102,11 +102,11 @@ def derivepassphrase(ctx: click.Context, /) -> None:
102 102
 
103 103
 
104 104
 @derivepassphrase.group(
105
-    'export',
105
+    "export",
106 106
     context_settings={
107
-        'help_option_names': ['-h', '--help'],
108
-        'ignore_unknown_options': True,
109
-        'allow_interspersed_args': False,
107
+        "help_option_names": ["-h", "--help"],
108
+        "ignore_unknown_options": True,
109
+        "allow_interspersed_args": False,
110 110
     },
111 111
     invoke_without_command=True,
112 112
     cls=cli_machinery.DefaultToVaultGroup,
... ...
@@ -134,18 +134,18 @@ def derivepassphrase_export(ctx: click.Context, /) -> None:
134 134
     """
135 135
     # TODO(the-13th-letter): Turn this callback into a no-op in v1.0.
136 136
     # https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#v1.0-implied-subcommands
137
-    deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
137
+    deprecation = logging.getLogger(f"{PROG_NAME}.deprecation")
138 138
     if ctx.invoked_subcommand is None:
139 139
         deprecation.warning(
140 140
             _msg.TranslatedString(
141 141
                 _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
142 142
             ),
143
-            extra={'color': ctx.color},
143
+            extra={"color": ctx.color},
144 144
         )
145 145
         # See definition of click.Group.invoke, non-chained case.
146 146
         with ctx:
147 147
             sub_ctx = derivepassphrase_export_vault.make_context(
148
-                'vault', ctx.args, parent=ctx
148
+                "vault", ctx.args, parent=ctx
149 149
             )
150 150
             # Constructing the subcontext above will usually already
151 151
             # lead to a click.UsageError, so this block typically won't
... ...
@@ -156,8 +156,8 @@ def derivepassphrase_export(ctx: click.Context, /) -> None:
156 156
 
157 157
 
158 158
 @derivepassphrase_export.command(
159
-    'vault',
160
-    context_settings={'help_option_names': ['-h', '--help']},
159
+    "vault",
160
+    context_settings={"help_option_names": ["-h", "--help"]},
161 161
     cls=cli_machinery.CommandWithHelpGroups,
162 162
     help=(
163 163
         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_01),
... ...
@@ -176,13 +176,13 @@ def derivepassphrase_export(ctx: click.Context, /) -> None:
176 176
     ),
177 177
 )
178 178
 @click.option(
179
-    '-f',
180
-    '--format',
181
-    'formats',
179
+    "-f",
180
+    "--format",
181
+    "formats",
182 182
     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_FORMAT_METAVAR_FMT),
183 183
     multiple=True,
184
-    default=('v0.3', 'v0.2', 'storeroom'),
185
-    type=click.Choice(['v0.2', 'v0.3', 'storeroom']),
184
+    default=("v0.3", "v0.2", "storeroom"),
185
+    type=click.Choice(["v0.2", "v0.3", "storeroom"]),
186 186
     help=_msg.TranslatedString(
187 187
         _msg.Label.EXPORT_VAULT_FORMAT_HELP_TEXT,
188 188
         defaults_hint=_msg.TranslatedString(
... ...
@@ -195,8 +195,8 @@ def derivepassphrase_export(ctx: click.Context, /) -> None:
195 195
     cls=cli_machinery.StandardOption,
196 196
 )
197 197
 @click.option(
198
-    '-k',
199
-    '--key',
198
+    "-k",
199
+    "--key",
200 200
     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_KEY_METAVAR_K),
201 201
     help=_msg.TranslatedString(
202 202
         _msg.Label.EXPORT_VAULT_KEY_HELP_TEXT,
... ...
@@ -213,7 +213,7 @@ def derivepassphrase_export(ctx: click.Context, /) -> None:
213 213
 @cli_machinery.color_forcing_pseudo_option
214 214
 @cli_machinery.standard_logging_options
215 215
 @click.argument(
216
-    'path',
216
+    "path",
217 217
     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_METAVAR_PATH),
218 218
     required=True,
219 219
     shell_complete=cli_helpers.shell_complete_path,
... ...
@@ -224,7 +224,7 @@ def derivepassphrase_export_vault(
224 224
     /,
225 225
     *,
226 226
     path: str | bytes | os.PathLike[str] | None,
227
-    formats: Sequence[Literal['v0.2', 'v0.3', 'storeroom']] = (),
227
+    formats: Sequence[Literal["v0.2", "v0.3", "storeroom"]] = (),
228 228
     key: str | bytes | None = None,
229 229
 ) -> None:
230 230
     """Export a vault-native configuration to standard output.
... ...
@@ -239,10 +239,10 @@ def derivepassphrase_export_vault(
239 239
 
240 240
     """
241 241
     logger = logging.getLogger(PROG_NAME)
242
-    if path in {'VAULT_PATH', b'VAULT_PATH'}:
242
+    if path in {"VAULT_PATH", b"VAULT_PATH"}:
243 243
         path = None
244 244
     if isinstance(key, str):  # pragma: no branch
245
-        key = key.encode('utf-8')
245
+        key = key.encode("utf-8")
246 246
     for fmt in formats:
247 247
         try:
248 248
             config = exporter.export_vault_config_data(path, key, format=fmt)
... ...
@@ -258,7 +258,7 @@ def derivepassphrase_export_vault(
258 258
                     path=path or exporter.get_vault_path(),
259 259
                     fmt=fmt,
260 260
                 ),
261
-                extra={'color': ctx.color},
261
+                extra={"color": ctx.color},
262 262
             )
263 263
             continue
264 264
         except OSError as exc:
... ...
@@ -269,23 +269,23 @@ def derivepassphrase_export_vault(
269 269
                     error=exc.strerror,
270 270
                     filename=exc.filename,
271 271
                 ).maybe_without_filename(),
272
-                extra={'color': ctx.color},
272
+                extra={"color": ctx.color},
273 273
             )
274 274
             ctx.exit(1)
275 275
         except ModuleNotFoundError:
276 276
             logger.error(
277 277
                 _msg.TranslatedString(
278 278
                     _msg.ErrMsgTemplate.MISSING_MODULE,
279
-                    module='cryptography',
279
+                    module="cryptography",
280 280
                 ),
281
-                extra={'color': ctx.color},
281
+                extra={"color": ctx.color},
282 282
             )
283 283
             logger.info(
284 284
                 _msg.TranslatedString(
285 285
                     _msg.InfoMsgTemplate.PIP_INSTALL_EXTRA,
286
-                    extra_name='export',
286
+                    extra_name="export",
287 287
                 ),
288
-                extra={'color': ctx.color},
288
+                extra={"color": ctx.color},
289 289
             )
290 290
             ctx.exit(1)
291 291
         else:
... ...
@@ -295,7 +295,7 @@ def derivepassphrase_export_vault(
295 295
                         _msg.ErrMsgTemplate.INVALID_VAULT_CONFIG,
296 296
                         config=config,
297 297
                     ),
298
-                    extra={'color': ctx.color},
298
+                    extra={"color": ctx.color},
299 299
                 )
300 300
                 ctx.exit(1)
301 301
             click.echo(
... ...
@@ -311,7 +311,7 @@ def derivepassphrase_export_vault(
311 311
                 _msg.ErrMsgTemplate.CANNOT_PARSE_AS_VAULT_CONFIG,
312 312
                 path=path,
313 313
             ).maybe_without_filename(),
314
-            extra={'color': ctx.color},
314
+            extra={"color": ctx.color},
315 315
         )
316 316
         ctx.exit(1)
317 317
 
... ...
@@ -355,26 +355,26 @@ class _VaultContext:  # noqa: PLR0904
355 355
 
356 356
     logger: Final = logging.getLogger(PROG_NAME)
357 357
     """"""
358
-    deprecation: Final = logging.getLogger(PROG_NAME + '.deprecation')
358
+    deprecation: Final = logging.getLogger(PROG_NAME + ".deprecation")
359 359
     """"""
360 360
     ctx: Final[click.Context]
361 361
     """"""
362 362
     all_ops: tuple[str, ...] = (
363
-        'delete_service_settings',
364
-        'delete_globals',
365
-        'clear_all_settings',
366
-        'import_settings',
367
-        'export_settings',
368
-        'store_config_only',
363
+        "delete_service_settings",
364
+        "delete_globals",
365
+        "clear_all_settings",
366
+        "import_settings",
367
+        "export_settings",
368
+        "store_config_only",
369 369
         # The default op "derive_passphrase" must be last!
370
-        'derive_passphrase',
370
+        "derive_passphrase",
371 371
     )
372 372
     readwrite_ops: AbstractSet[str] = frozenset({
373
-        'delete_service_settings',
374
-        'delete_globals',
375
-        'clear_all_settings',
376
-        'import_settings',
377
-        'store_config_only',
373
+        "delete_service_settings",
374
+        "delete_globals",
375
+        "clear_all_settings",
376
+        "import_settings",
377
+        "store_config_only",
378 378
     })
379 379
     options_in_group: dict[type[click.Option], list[click.Option]]
380 380
     params_by_str: dict[str, click.Parameter]
... ...
@@ -408,7 +408,7 @@ class _VaultContext:  # noqa: PLR0904
408 408
                             group = class_
409 409
                             break
410 410
                     else:  # pragma: no cover [failsafe]
411
-                        assert False, f'Unknown option group for {param!r}'  # noqa: B011,PT015
411
+                        assert False, f"Unknown option group for {param!r}"  # noqa: B011,PT015
412 412
                 else:
413 413
                     group = click.Option
414 414
                 self.options_in_group.setdefault(group, []).append(param)
... ...
@@ -439,7 +439,7 @@ class _VaultContext:  # noqa: PLR0904
439 439
         """
440 440
         param = self.params_by_str[param] if isinstance(param, str) else param
441 441
         names = [param.human_readable_name, *param.opts, *param.secondary_opts]
442
-        option_names = [n for n in names if n.startswith('--')]
442
+        option_names = [n for n in names if n.startswith("--")]
443 443
         return min(option_names, key=len)
444 444
 
445 445
     def check_incompatible_options(
... ...
@@ -486,10 +486,10 @@ class _VaultContext:  # noqa: PLR0904
486 486
         is logged.
487 487
 
488 488
         """
489
-        stacklevel = kwargs.pop('stacklevel', 1)
489
+        stacklevel = kwargs.pop("stacklevel", 1)
490 490
         stacklevel += 1
491
-        extra = kwargs.pop('extra', {})
492
-        extra.setdefault('color', self.ctx.color)
491
+        extra = kwargs.pop("extra", {})
492
+        extra.setdefault("color", self.ctx.color)
493 493
         self.logger.error(msg, stacklevel=stacklevel, extra=extra, **kwargs)
494 494
         self.ctx.exit(1)
495 495
 
... ...
@@ -500,10 +500,10 @@ class _VaultContext:  # noqa: PLR0904
500 500
         warning is logged.
501 501
 
502 502
         """
503
-        stacklevel = kwargs.pop('stacklevel', 1)
503
+        stacklevel = kwargs.pop("stacklevel", 1)
504 504
         stacklevel += 1
505
-        extra = kwargs.pop('extra', {})
506
-        extra.setdefault('color', self.ctx.color)
505
+        extra = kwargs.pop("extra", {})
506
+        extra.setdefault("color", self.ctx.color)
507 507
         self.logger.warning(msg, stacklevel=stacklevel, extra=extra, **kwargs)
508 508
 
509 509
     def deprecation_warning(self, msg: Any, /, **kwargs: Any) -> None:  # noqa: ANN401
... ...
@@ -513,10 +513,10 @@ class _VaultContext:  # noqa: PLR0904
513 513
         warning is logged.
514 514
 
515 515
         """
516
-        stacklevel = kwargs.pop('stacklevel', 1)
516
+        stacklevel = kwargs.pop("stacklevel", 1)
517 517
         stacklevel += 1
518
-        extra = kwargs.pop('extra', {})
519
-        extra.setdefault('color', self.ctx.color)
518
+        extra = kwargs.pop("extra", {})
519
+        extra.setdefault("color", self.ctx.color)
520 520
         self.deprecation.warning(
521 521
             msg, stacklevel=stacklevel, extra=extra, **kwargs
522 522
         )
... ...
@@ -528,10 +528,10 @@ class _VaultContext:  # noqa: PLR0904
528 528
         warning is logged.
529 529
 
530 530
         """
531
-        stacklevel = kwargs.pop('stacklevel', 1)
531
+        stacklevel = kwargs.pop("stacklevel", 1)
532 532
         stacklevel += 1
533
-        extra = kwargs.pop('extra', {})
534
-        extra.setdefault('color', self.ctx.color)
533
+        extra = kwargs.pop("extra", {})
534
+        extra.setdefault("color", self.ctx.color)
535 535
         self.deprecation.info(
536 536
             msg, stacklevel=stacklevel, extra=extra, **kwargs
537 537
         )
... ...
@@ -554,11 +554,11 @@ class _VaultContext:  # noqa: PLR0904
554 554
             try:
555 555
                 backup_config, exc = cli_helpers.migrate_and_load_old_config()
556 556
             except FileNotFoundError:
557
-                return {'services': {}}
557
+                return {"services": {}}
558 558
             old_name = cli_helpers.config_filename(
559
-                subsystem='old settings.json'
559
+                subsystem="old settings.json"
560 560
             ).name
561
-            new_name = cli_helpers.config_filename(subsystem='vault').name
561
+            new_name = cli_helpers.config_filename(subsystem="vault").name
562 562
             self.deprecation_warning(
563 563
                 _msg.TranslatedString(
564 564
                     _msg.WarnMsgTemplate.V01_STYLE_CONFIG,
... ...
@@ -662,15 +662,15 @@ class _VaultContext:  # noqa: PLR0904
662 662
 
663 663
         """
664 664
         param: click.Parameter
665
-        self.check_incompatible_options('--phrase', '--key')
665
+        self.check_incompatible_options("--phrase", "--key")
666 666
         for group in (
667 667
             cli_machinery.ConfigurationOption,
668 668
             cli_machinery.StorageManagementOption,
669 669
         ):
670 670
             for opt in self.options_in_group[group]:
671 671
                 if opt not in {
672
-                    self.params_by_str['--config'],
673
-                    self.params_by_str['--notes'],
672
+                    self.params_by_str["--config"],
673
+                    self.params_by_str["--notes"],
674 674
                 }:
675 675
                     for other_opt in self.options_in_group[
676 676
                         cli_machinery.PassphraseGenerationOption
... ...
@@ -686,15 +686,15 @@ class _VaultContext:  # noqa: PLR0904
686 686
                     cli_machinery.ConfigurationOption
687 687
                 ]:
688 688
                     if {opt, other_opt} != {
689
-                        self.params_by_str['--config'],
690
-                        self.params_by_str['--notes'],
689
+                        self.params_by_str["--config"],
690
+                        self.params_by_str["--notes"],
691 691
                     }:
692 692
                         self.check_incompatible_options(opt, other_opt)
693 693
                 for other_opt in self.options_in_group[
694 694
                     cli_machinery.StorageManagementOption
695 695
                 ]:
696 696
                     self.check_incompatible_options(opt, other_opt)
697
-        service: str | None = self.ctx.params['service']
697
+        service: str | None = self.ctx.params["service"]
698 698
         service_metavar = _msg.TranslatedString(
699 699
             _msg.Label.VAULT_METAVAR_SERVICE
700 700
         )
... ...
@@ -704,7 +704,7 @@ class _VaultContext:  # noqa: PLR0904
704 704
         for param in sv_or_global_options:
705 705
             if self.is_param_set(param) and not (
706 706
                 service is not None
707
-                or self.is_param_set(self.params_by_str['--config'])
707
+                or self.is_param_set(self.params_by_str["--config"])
708 708
             ):
709 709
                 err_msg = _msg.TranslatedString(
710 710
                     _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE_OR_CONFIG,
... ...
@@ -713,8 +713,8 @@ class _VaultContext:  # noqa: PLR0904
713 713
                 )
714 714
                 raise click.UsageError(str(err_msg))
715 715
         sv_options = [
716
-            self.params_by_str['--notes'],
717
-            self.params_by_str['--delete'],
716
+            self.params_by_str["--notes"],
717
+            self.params_by_str["--delete"],
718 718
         ]
719 719
         for param in sv_options:
720 720
             if self.is_param_set(param) and not service is not None:
... ...
@@ -725,8 +725,8 @@ class _VaultContext:  # noqa: PLR0904
725 725
                 )
726 726
                 raise click.UsageError(str(err_msg))
727 727
         no_sv_options = [
728
-            self.params_by_str['--delete-globals'],
729
-            self.params_by_str['--clear'],
728
+            self.params_by_str["--delete-globals"],
729
+            self.params_by_str["--clear"],
730 730
             *self.options_in_group[cli_machinery.StorageManagementOption],
731 731
         ]
732 732
         for param in no_sv_options:
... ...
@@ -771,15 +771,15 @@ class _VaultContext:  # noqa: PLR0904
771 771
         service_metavar = _msg.TranslatedString(
772 772
             _msg.Label.VAULT_METAVAR_SERVICE
773 773
         )
774
-        if self.ctx.params['service'] == '':  # noqa: PLC1901
774
+        if self.ctx.params["service"] == "":  # noqa: PLC1901
775 775
             self.warning(
776 776
                 _msg.TranslatedString(
777 777
                     _msg.WarnMsgTemplate.EMPTY_SERVICE_NOT_SUPPORTED,
778 778
                     service_metavar=service_metavar,
779 779
                 ),
780 780
             )
781
-        if self.ctx.params.get('edit_notes') and not self.ctx.params.get(
782
-            'store_config_only'
781
+        if self.ctx.params.get("edit_notes") and not self.ctx.params.get(
782
+            "store_config_only"
783 783
         ):
784 784
             self.warning(
785 785
                 _msg.TranslatedString(
... ...
@@ -795,28 +795,28 @@ class _VaultContext:  # noqa: PLR0904
795 795
         else:
796 796
             op = self.all_ops[-1]
797 797
         with self.get_mutex(op):
798
-            op_func = getattr(self, 'run_op_' + op)
798
+            op_func = getattr(self, "run_op_" + op)
799 799
             return op_func()
800 800
 
801 801
     def run_op_delete_service_settings(self) -> None:
802 802
         """Delete settings for a specific service."""
803
-        service = self.ctx.params['service']
803
+        service = self.ctx.params["service"]
804 804
         assert service is not None
805 805
         configuration = self.get_config()
806
-        if service in configuration['services']:
807
-            del configuration['services'][service]
806
+        if service in configuration["services"]:
807
+            del configuration["services"][service]
808 808
             self.put_config(configuration)
809 809
 
810 810
     def run_op_delete_globals(self) -> None:
811 811
         """Delete the global settings."""
812 812
         configuration = self.get_config()
813
-        if 'global' in configuration:
814
-            del configuration['global']
813
+        if "global" in configuration:
814
+            del configuration["global"]
815 815
             self.put_config(configuration)
816 816
 
817 817
     def run_op_clear_all_settings(self) -> None:
818 818
         """Clear all settings."""
819
-        self.put_config({'services': {}})
819
+        self.put_config({"services": {}})
820 820
 
821 821
     def run_op_import_settings(self) -> None:  # noqa: C901,PLR0912
822 822
         """Import settings from a given file.
... ...
@@ -832,17 +832,17 @@ class _VaultContext:  # noqa: PLR0904
832 832
             _msg.Label.VAULT_METAVAR_SERVICE
833 833
         )
834 834
         user_config = self.get_user_config()
835
-        import_settings = self.ctx.params['import_settings']
836
-        overwrite_config = self.ctx.params['overwrite_config']
835
+        import_settings = self.ctx.params["import_settings"]
836
+        overwrite_config = self.ctx.params["overwrite_config"]
837 837
         try:
838 838
             # TODO(the-13th-letter): keep track of auto-close; try
839 839
             # os.dup if feasible
840 840
             infile = cast(
841
-                'TextIO',
841
+                "TextIO",
842 842
                 (
843 843
                     import_settings
844
-                    if hasattr(import_settings, 'close')
845
-                    else click.open_file(os.fspath(import_settings), 'rt')
844
+                    if hasattr(import_settings, "close")
845
+                    else click.open_file(os.fspath(import_settings), "rt")
846 846
                 ),
847 847
             )
848 848
             # Don't specifically catch TypeError or ValueError here if
... ...
@@ -884,7 +884,7 @@ class _VaultContext:  # noqa: PLR0904
884 884
             # These are never fatal errors, because the semantics of
885 885
             # vault upon encountering these settings are ill-specified,
886 886
             # but not ill-defined.
887
-            if step.action == 'replace':
887
+            if step.action == "replace":
888 888
                 self.warning(
889 889
                     _msg.TranslatedString(
890 890
                         _msg.WarnMsgTemplate.STEP_REPLACE_INVALID_VALUE,
... ...
@@ -901,7 +901,7 @@ class _VaultContext:  # noqa: PLR0904
901 901
                         old=json.dumps(step.old_value),
902 902
                     ),
903 903
                 )
904
-        if '' in maybe_config['services']:
904
+        if "" in maybe_config["services"]:
905 905
             self.warning(
906 906
                 _msg.TranslatedString(
907 907
                     _msg.WarnMsgTemplate.EMPTY_SERVICE_SETTINGS_INACCESSIBLE,
... ...
@@ -909,7 +909,7 @@ class _VaultContext:  # noqa: PLR0904
909 909
                     PROG_NAME=PROG_NAME,
910 910
                 ),
911 911
             )
912
-        for service_name in sorted(maybe_config['services'].keys()):
912
+        for service_name in sorted(maybe_config["services"].keys()):
913 913
             if not cli_helpers.is_completable_item(service_name):
914 914
                 self.warning(
915 915
                     _msg.TranslatedString(
... ...
@@ -919,15 +919,15 @@ class _VaultContext:  # noqa: PLR0904
919 919
                 )
920 920
         try:
921 921
             cli_helpers.check_for_misleading_passphrase(
922
-                ('global',),
923
-                cast('dict[str, Any]', maybe_config.get('global', {})),
922
+                ("global",),
923
+                cast("dict[str, Any]", maybe_config.get("global", {})),
924 924
                 main_config=user_config,
925 925
                 ctx=self.ctx,
926 926
             )
927
-            for key, value in maybe_config['services'].items():
927
+            for key, value in maybe_config["services"].items():
928 928
                 cli_helpers.check_for_misleading_passphrase(
929
-                    ('services', key),
930
-                    cast('dict[str, Any]', value),
929
+                    ("services", key),
930
+                    cast("dict[str, Any]", value),
931 931
                     main_config=user_config,
932 932
                     ctx=self.ctx,
933 933
                 )
... ...
@@ -939,22 +939,22 @@ class _VaultContext:  # noqa: PLR0904
939 939
                     filename=None,
940 940
                 ).maybe_without_filename(),
941 941
             )
942
-        global_obj = maybe_config.get('global', {})
943
-        has_key = _types.js_truthiness(global_obj.get('key'))
944
-        has_phrase = _types.js_truthiness(global_obj.get('phrase'))
942
+        global_obj = maybe_config.get("global", {})
943
+        has_key = _types.js_truthiness(global_obj.get("key"))
944
+        has_phrase = _types.js_truthiness(global_obj.get("phrase"))
945 945
         if has_key and has_phrase:
946 946
             self.warning(
947 947
                 _msg.TranslatedString(
948 948
                     _msg.WarnMsgTemplate.GLOBAL_PASSPHRASE_INEFFECTIVE,
949 949
                 ),
950 950
             )
951
-        for service_name, service_obj in maybe_config['services'].items():
951
+        for service_name, service_obj in maybe_config["services"].items():
952 952
             has_key = _types.js_truthiness(
953
-                service_obj.get('key')
954
-            ) or _types.js_truthiness(global_obj.get('key'))
953
+                service_obj.get("key")
954
+            ) or _types.js_truthiness(global_obj.get("key"))
955 955
             has_phrase = _types.js_truthiness(
956
-                service_obj.get('phrase')
957
-            ) or _types.js_truthiness(global_obj.get('phrase'))
956
+                service_obj.get("phrase")
957
+            ) or _types.js_truthiness(global_obj.get("phrase"))
958 958
             if has_key and has_phrase:
959 959
                 self.warning(
960 960
                     _msg.TranslatedString(
... ...
@@ -969,16 +969,16 @@ class _VaultContext:  # noqa: PLR0904
969 969
             merged_config: collections.ChainMap[str, Any] = (
970 970
                 collections.ChainMap(
971 971
                     {
972
-                        'services': collections.ChainMap(
973
-                            maybe_config['services'],
974
-                            configuration['services'],
972
+                        "services": collections.ChainMap(
973
+                            maybe_config["services"],
974
+                            configuration["services"],
975 975
                         ),
976 976
                     },
977
-                    {'global': maybe_config['global']}
978
-                    if 'global' in maybe_config
977
+                    {"global": maybe_config["global"]}
978
+                    if "global" in maybe_config
979 979
                     else {},
980
-                    {'global': configuration['global']}
981
-                    if 'global' in configuration
980
+                    {"global": configuration["global"]}
981
+                    if "global" in configuration
982 982
                     else {},
983 983
                 )
984 984
             )
... ...
@@ -996,18 +996,18 @@ class _VaultContext:  # noqa: PLR0904
996 996
         configuration to the file.
997 997
 
998 998
         """
999
-        export_settings = self.ctx.params['export_settings']
1000
-        export_as = self.ctx.params['export_as']
999
+        export_settings = self.ctx.params["export_settings"]
1000
+        export_as = self.ctx.params["export_as"]
1001 1001
         configuration = self.get_config()
1002 1002
         try:
1003 1003
             # TODO(the-13th-letter): keep track of auto-close; try
1004 1004
             # os.dup if feasible
1005 1005
             outfile = cast(
1006
-                'TextIO',
1006
+                "TextIO",
1007 1007
                 (
1008 1008
                     export_settings
1009
-                    if hasattr(export_settings, 'close')
1010
-                    else click.open_file(os.fspath(export_settings), 'wt')
1009
+                    if hasattr(export_settings, "close")
1010
+                    else click.open_file(os.fspath(export_settings), "wt")
1011 1011
                 ),
1012 1012
             )
1013 1013
             # Don't specifically catch TypeError or ValueError here if
... ...
@@ -1016,10 +1016,10 @@ class _VaultContext:  # noqa: PLR0904
1016 1016
             # and for programmatic use, our caller may want accurate
1017 1017
             # error information.
1018 1018
             with outfile:
1019
-                if export_as == 'sh':
1019
+                if export_as == "sh":
1020 1020
                     this_ctx = self.ctx
1021 1021
                     prog_name_pieces = collections.deque([
1022
-                        this_ctx.info_name or 'vault',
1022
+                        this_ctx.info_name or "vault",
1023 1023
                     ])
1024 1024
                     while (
1025 1025
                         this_ctx.parent is not None
... ...
@@ -1094,20 +1094,20 @@ class _VaultContext:  # noqa: PLR0904
1094 1094
             entered master passphrase for Unicode normalization issues.
1095 1095
 
1096 1096
         """
1097
-        service = self.ctx.params['service']
1098
-        use_key = self.ctx.params['use_key']
1099
-        use_phrase = self.ctx.params['use_phrase']
1097
+        service = self.ctx.params["service"]
1098
+        use_key = self.ctx.params["use_key"]
1099
+        use_phrase = self.ctx.params["use_phrase"]
1100 1100
         if configuration is None:
1101 1101
             configuration = self.get_config()
1102 1102
         service_keys_on_commandline = {
1103
-            'length',
1104
-            'repeat',
1105
-            'lower',
1106
-            'upper',
1107
-            'number',
1108
-            'space',
1109
-            'dash',
1110
-            'symbol',
1103
+            "length",
1104
+            "repeat",
1105
+            "lower",
1106
+            "upper",
1107
+            "number",
1108
+            "space",
1109
+            "dash",
1110
+            "symbol",
1111 1111
         }
1112 1112
         settings: collections.ChainMap[str, Any] = collections.ChainMap(
1113 1113
             {
... ...
@@ -1116,10 +1116,10 @@ class _VaultContext:  # noqa: PLR0904
1116 1116
                 if (v := self.ctx.params.get(k)) is not None
1117 1117
             },
1118 1118
             cast(
1119
-                'dict[str, Any]',
1120
-                configuration['services'].get(service, {}) if service else {},
1119
+                "dict[str, Any]",
1120
+                configuration["services"].get(service, {}) if service else {},
1121 1121
             ),
1122
-            cast('dict[str, Any]', configuration.get('global', {})),
1122
+            cast("dict[str, Any]", configuration.get("global", {})),
1123 1123
         )
1124 1124
         if not service and not empty_service_permitted:
1125 1125
             err_msg = _msg.TranslatedString(
... ...
@@ -1130,13 +1130,13 @@ class _VaultContext:  # noqa: PLR0904
1130 1130
             )
1131 1131
             raise click.UsageError(str(err_msg))
1132 1132
         if use_key:
1133
-            settings.maps[0]['key'] = base64.standard_b64encode(
1133
+            settings.maps[0]["key"] = base64.standard_b64encode(
1134 1134
                 cli_helpers.select_ssh_key(
1135 1135
                     ctx=self.ctx,
1136 1136
                     error_callback=self.err,
1137 1137
                     warning_callback=self.warning,
1138 1138
                 )
1139
-            ).decode('ASCII')
1139
+            ).decode("ASCII")
1140 1140
         elif use_phrase:
1141 1141
             maybe_phrase = cli_helpers.prompt_for_passphrase()
1142 1142
             if not maybe_phrase:
... ...
@@ -1146,7 +1146,7 @@ class _VaultContext:  # noqa: PLR0904
1146 1146
                     )
1147 1147
                 )
1148 1148
             else:
1149
-                settings.maps[0]['phrase'] = maybe_phrase
1149
+                settings.maps[0]["phrase"] = maybe_phrase
1150 1150
         return settings
1151 1151
 
1152 1152
     def run_op_store_config_only(self) -> None:  # noqa: C901,PLR0912,PLR0914,PLR0915
... ...
@@ -1173,13 +1173,13 @@ class _VaultContext:  # noqa: PLR0904
1173 1173
                 and set.
1174 1174
 
1175 1175
         """
1176
-        service = self.ctx.params['service']
1177
-        use_key = self.ctx.params['use_key']
1178
-        use_phrase = self.ctx.params['use_phrase']
1179
-        unset_settings = self.ctx.params['unset_settings']
1180
-        overwrite_config = self.ctx.params['overwrite_config']
1181
-        edit_notes = self.ctx.params['edit_notes']
1182
-        modern_editor_interface = self.ctx.params['modern_editor_interface']
1176
+        service = self.ctx.params["service"]
1177
+        use_key = self.ctx.params["use_key"]
1178
+        use_phrase = self.ctx.params["use_phrase"]
1179
+        unset_settings = self.ctx.params["unset_settings"]
1180
+        overwrite_config = self.ctx.params["overwrite_config"]
1181
+        edit_notes = self.ctx.params["edit_notes"]
1182
+        modern_editor_interface = self.ctx.params["modern_editor_interface"]
1183 1183
         configuration = self.get_config()
1184 1184
         user_config = self.get_user_config()
1185 1185
         settings = self.run_subop_query_phrase_or_key_change(
... ...
@@ -1193,12 +1193,12 @@ class _VaultContext:  # noqa: PLR0904
1193 1193
             else collections.ChainMap(settings.maps[0], settings.maps[2])
1194 1194
         )
1195 1195
         if use_key:
1196
-            view['key'] = overrides['key']
1196
+            view["key"] = overrides["key"]
1197 1197
         elif use_phrase:
1198
-            view['phrase'] = overrides['phrase']
1198
+            view["phrase"] = overrides["phrase"]
1199 1199
             try:
1200 1200
                 cli_helpers.check_for_misleading_passphrase(
1201
-                    ('services', service) if service else ('global',),
1201
+                    ("services", service) if service else ("global",),
1202 1202
                     overrides,
1203 1203
                     main_config=user_config,
1204 1204
                     ctx=self.ctx,
... ...
@@ -1211,7 +1211,7 @@ class _VaultContext:  # noqa: PLR0904
1211 1211
                         filename=None,
1212 1212
                     ).maybe_without_filename(),
1213 1213
                 )
1214
-            if 'key' in settings:
1214
+            if "key" in settings:
1215 1215
                 if service:
1216 1216
                     w_msg = _msg.TranslatedString(
1217 1217
                         _msg.WarnMsgTemplate.SERVICE_PASSPHRASE_INEFFECTIVE,
... ...
@@ -1247,9 +1247,9 @@ class _VaultContext:  # noqa: PLR0904
1247 1247
                 ),
1248 1248
             )
1249 1249
         subtree: dict[str, Any] = (
1250
-            configuration['services'].setdefault(service, {})  # type: ignore[assignment]
1250
+            configuration["services"].setdefault(service, {})  # type: ignore[assignment]
1251 1251
             if service
1252
-            else configuration.setdefault('global', {})
1252
+            else configuration.setdefault("global", {})
1253 1253
         )
1254 1254
         if overwrite_config:
1255 1255
             subtree.clear()
... ...
@@ -1258,7 +1258,7 @@ class _VaultContext:  # noqa: PLR0904
1258 1258
                 subtree.pop(setting, None)
1259 1259
         subtree.update(view)
1260 1260
         assert _types.is_vault_config(configuration), (
1261
-            f'Invalid vault configuration: {configuration!r}'
1261
+            f"Invalid vault configuration: {configuration!r}"
1262 1262
         )
1263 1263
         if edit_notes:
1264 1264
             assert service is not None
... ...
@@ -1271,9 +1271,9 @@ class _VaultContext:  # noqa: PLR0904
1271 1271
             notes_legacy_instructions = _msg.TranslatedString(
1272 1272
                 _msg.Label.DERIVEPASSPHRASE_VAULT_NOTES_LEGACY_INSTRUCTION_TEXT
1273 1273
             )
1274
-            old_notes_value = subtree.get('notes', '')
1274
+            old_notes_value = subtree.get("notes", "")
1275 1275
             if modern_editor_interface:
1276
-                text = '\n'.join([
1276
+                text = "\n".join([
1277 1277
                     str(notes_instructions),
1278 1278
                     str(notes_marker),
1279 1279
                     old_notes_value,
... ...
@@ -1287,16 +1287,16 @@ class _VaultContext:  # noqa: PLR0904
1287 1287
                 and notes_value.strip() != old_notes_value.strip()
1288 1288
             ):
1289 1289
                 backup_file = cli_helpers.config_filename(
1290
-                    subsystem='notes backup'
1290
+                    subsystem="notes backup"
1291 1291
                 )
1292
-                backup_file.write_text(old_notes_value, encoding='UTF-8')
1292
+                backup_file.write_text(old_notes_value, encoding="UTF-8")
1293 1293
                 self.warning(
1294 1294
                     _msg.TranslatedString(
1295 1295
                         _msg.WarnMsgTemplate.LEGACY_EDITOR_INTERFACE_NOTES_BACKUP,
1296 1296
                         filename=str(backup_file),
1297 1297
                     ),
1298 1298
                 )
1299
-                subtree['notes'] = notes_value.strip()
1299
+                subtree["notes"] = notes_value.strip()
1300 1300
             elif (
1301 1301
                 modern_editor_interface and notes_value.strip() != text.strip()
1302 1302
             ):
... ...
@@ -1306,7 +1306,7 @@ class _VaultContext:  # noqa: PLR0904
1306 1306
                 while notes_lines:
1307 1307
                     line = notes_lines.popleft()
1308 1308
                     if line.startswith(str(notes_marker)):
1309
-                        notes_value = ''.join(notes_lines)
1309
+                        notes_value = "".join(notes_lines)
1310 1310
                         break
1311 1311
                 else:
1312 1312
                     if not notes_value.strip():
... ...
@@ -1315,7 +1315,7 @@ class _VaultContext:  # noqa: PLR0904
1315 1315
                                 _msg.ErrMsgTemplate.USER_ABORTED_EDIT
1316 1316
                             )
1317 1317
                         )
1318
-                subtree['notes'] = notes_value.strip()
1318
+                subtree["notes"] = notes_value.strip()
1319 1319
         self.put_config(configuration)
1320 1320
 
1321 1321
     def run_op_derive_passphrase(self) -> None:
... ...
@@ -1338,10 +1338,10 @@ class _VaultContext:  # noqa: PLR0904
1338 1338
                 No master passphrase or master SSH key was given on both
1339 1339
                 the command-line and in the vault configuration on disk.
1340 1340
         """
1341
-        service = self.ctx.params['service']
1342
-        use_key = self.ctx.params['use_key']
1343
-        use_phrase = self.ctx.params['use_phrase']
1344
-        print_notes_before = self.ctx.params['print_notes_before']
1341
+        service = self.ctx.params["service"]
1342
+        use_key = self.ctx.params["use_key"]
1343
+        use_phrase = self.ctx.params["use_phrase"]
1344
+        print_notes_before = self.ctx.params["print_notes_before"]
1345 1345
         user_config = self.get_user_config()
1346 1346
         settings = self.run_subop_query_phrase_or_key_change(
1347 1347
             empty_service_permitted=False
... ...
@@ -1350,7 +1350,7 @@ class _VaultContext:  # noqa: PLR0904
1350 1350
             try:
1351 1351
                 cli_helpers.check_for_misleading_passphrase(
1352 1352
                     cli_helpers.ORIGIN.INTERACTIVE,
1353
-                    {'phrase': settings['phrase']},
1353
+                    {"phrase": settings["phrase"]},
1354 1354
                     main_config=user_config,
1355 1355
                     ctx=self.ctx,
1356 1356
                 )
... ...
@@ -1363,7 +1363,7 @@ class _VaultContext:  # noqa: PLR0904
1363 1363
                     ).maybe_without_filename(),
1364 1364
                 )
1365 1365
         phrase: str | bytes
1366
-        overrides = cast('dict[str, int | str]', settings.maps[0])
1366
+        overrides = cast("dict[str, int | str]", settings.maps[0])
1367 1367
         # If either --key or --phrase are given, use that setting.
1368 1368
         # Otherwise, if both key and phrase are set in the config,
1369 1369
         # use the key.  Otherwise, if only one of key and phrase is
... ...
@@ -1372,53 +1372,53 @@ class _VaultContext:  # noqa: PLR0904
1372 1372
         # a key is given.  Finally, if nothing is set, error out.
1373 1373
         if use_key:
1374 1374
             phrase = cli_helpers.key_to_phrase(
1375
-                cast('str', overrides['key']),
1375
+                cast("str", overrides["key"]),
1376 1376
                 error_callback=self.err,
1377 1377
                 warning_callback=self.warning,
1378 1378
             )
1379 1379
         elif use_phrase:
1380
-            phrase = cast('str', overrides['phrase'])
1381
-        elif settings.get('key'):
1380
+            phrase = cast("str", overrides["phrase"])
1381
+        elif settings.get("key"):
1382 1382
             phrase = cli_helpers.key_to_phrase(
1383
-                cast('str', settings['key']), error_callback=self.err
1383
+                cast("str", settings["key"]), error_callback=self.err
1384 1384
             )
1385
-        elif settings.get('phrase'):
1386
-            phrase = cast('str', settings['phrase'])
1385
+        elif settings.get("phrase"):
1386
+            phrase = cast("str", settings["phrase"])
1387 1387
         else:
1388 1388
             err_msg = _msg.TranslatedString(
1389 1389
                 _msg.ErrMsgTemplate.NO_KEY_OR_PHRASE
1390 1390
             )
1391 1391
             raise click.UsageError(str(err_msg))
1392
-        overrides.pop('key', '')
1393
-        overrides.pop('phrase', '')
1392
+        overrides.pop("key", "")
1393
+        overrides.pop("phrase", "")
1394 1394
         assert service is not None
1395 1395
         vault_service_keys = {
1396
-            'length',
1397
-            'repeat',
1398
-            'lower',
1399
-            'upper',
1400
-            'number',
1401
-            'space',
1402
-            'dash',
1403
-            'symbol',
1396
+            "length",
1397
+            "repeat",
1398
+            "lower",
1399
+            "upper",
1400
+            "number",
1401
+            "space",
1402
+            "dash",
1403
+            "symbol",
1404 1404
         }
1405 1405
         kwargs = {
1406
-            cast('str', k): cast('int', settings[k])
1406
+            cast("str", k): cast("int", settings[k])
1407 1407
             for k in vault_service_keys
1408 1408
             if k in settings
1409 1409
         }
1410 1410
         result = vault.Vault(phrase=phrase, **kwargs).generate(service)
1411
-        service_notes = cast('str', settings.get('notes', '')).strip()
1411
+        service_notes = cast("str", settings.get("notes", "")).strip()
1412 1412
         if print_notes_before and service_notes.strip():
1413
-            click.echo(f'{service_notes}\n', err=True, color=self.ctx.color)
1414
-        click.echo(result.decode('ASCII'), color=self.ctx.color)
1413
+            click.echo(f"{service_notes}\n", err=True, color=self.ctx.color)
1414
+        click.echo(result.decode("ASCII"), color=self.ctx.color)
1415 1415
         if not print_notes_before and service_notes.strip():
1416
-            click.echo(f'\n{service_notes}\n', err=True, color=self.ctx.color)
1416
+            click.echo(f"\n{service_notes}\n", err=True, color=self.ctx.color)
1417 1417
 
1418 1418
 
1419 1419
 @derivepassphrase.command(
1420
-    'vault',
1421
-    context_settings={'help_option_names': ['-h', '--help']},
1420
+    "vault",
1421
+    context_settings={"help_option_names": ["-h", "--help"]},
1422 1422
     cls=cli_machinery.CommandWithHelpGroups,
1423 1423
     help=(
1424 1424
         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_01),
... ...
@@ -1435,9 +1435,9 @@ class _VaultContext:  # noqa: PLR0904
1435 1435
     ),
1436 1436
 )
1437 1437
 @click.option(
1438
-    '-p',
1439
-    '--phrase',
1440
-    'use_phrase',
1438
+    "-p",
1439
+    "--phrase",
1440
+    "use_phrase",
1441 1441
     is_flag=True,
1442 1442
     help=_msg.TranslatedString(
1443 1443
         _msg.Label.DERIVEPASSPHRASE_VAULT_PHRASE_HELP_TEXT
... ...
@@ -1445,9 +1445,9 @@ class _VaultContext:  # noqa: PLR0904
1445 1445
     cls=cli_machinery.PassphraseGenerationOption,
1446 1446
 )
1447 1447
 @click.option(
1448
-    '-k',
1449
-    '--key',
1450
-    'use_key',
1448
+    "-k",
1449
+    "--key",
1450
+    "use_key",
1451 1451
     is_flag=True,
1452 1452
     help=_msg.TranslatedString(
1453 1453
         _msg.Label.DERIVEPASSPHRASE_VAULT_KEY_HELP_TEXT
... ...
@@ -1455,8 +1455,8 @@ class _VaultContext:  # noqa: PLR0904
1455 1455
     cls=cli_machinery.PassphraseGenerationOption,
1456 1456
 )
1457 1457
 @click.option(
1458
-    '-l',
1459
-    '--length',
1458
+    "-l",
1459
+    "--length",
1460 1460
     metavar=_msg.TranslatedString(
1461 1461
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1462 1462
     ),
... ...
@@ -1470,8 +1470,8 @@ class _VaultContext:  # noqa: PLR0904
1470 1470
     cls=cli_machinery.PassphraseGenerationOption,
1471 1471
 )
1472 1472
 @click.option(
1473
-    '-r',
1474
-    '--repeat',
1473
+    "-r",
1474
+    "--repeat",
1475 1475
     metavar=_msg.TranslatedString(
1476 1476
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1477 1477
     ),
... ...
@@ -1485,7 +1485,7 @@ class _VaultContext:  # noqa: PLR0904
1485 1485
     cls=cli_machinery.PassphraseGenerationOption,
1486 1486
 )
1487 1487
 @click.option(
1488
-    '--lower',
1488
+    "--lower",
1489 1489
     metavar=_msg.TranslatedString(
1490 1490
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1491 1491
     ),
... ...
@@ -1499,7 +1499,7 @@ class _VaultContext:  # noqa: PLR0904
1499 1499
     cls=cli_machinery.PassphraseGenerationOption,
1500 1500
 )
1501 1501
 @click.option(
1502
-    '--upper',
1502
+    "--upper",
1503 1503
     metavar=_msg.TranslatedString(
1504 1504
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1505 1505
     ),
... ...
@@ -1513,7 +1513,7 @@ class _VaultContext:  # noqa: PLR0904
1513 1513
     cls=cli_machinery.PassphraseGenerationOption,
1514 1514
 )
1515 1515
 @click.option(
1516
-    '--number',
1516
+    "--number",
1517 1517
     metavar=_msg.TranslatedString(
1518 1518
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1519 1519
     ),
... ...
@@ -1527,7 +1527,7 @@ class _VaultContext:  # noqa: PLR0904
1527 1527
     cls=cli_machinery.PassphraseGenerationOption,
1528 1528
 )
1529 1529
 @click.option(
1530
-    '--space',
1530
+    "--space",
1531 1531
     metavar=_msg.TranslatedString(
1532 1532
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1533 1533
     ),
... ...
@@ -1541,7 +1541,7 @@ class _VaultContext:  # noqa: PLR0904
1541 1541
     cls=cli_machinery.PassphraseGenerationOption,
1542 1542
 )
1543 1543
 @click.option(
1544
-    '--dash',
1544
+    "--dash",
1545 1545
     metavar=_msg.TranslatedString(
1546 1546
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1547 1547
     ),
... ...
@@ -1555,7 +1555,7 @@ class _VaultContext:  # noqa: PLR0904
1555 1555
     cls=cli_machinery.PassphraseGenerationOption,
1556 1556
 )
1557 1557
 @click.option(
1558
-    '--symbol',
1558
+    "--symbol",
1559 1559
     metavar=_msg.TranslatedString(
1560 1560
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1561 1561
     ),
... ...
@@ -1569,9 +1569,9 @@ class _VaultContext:  # noqa: PLR0904
1569 1569
     cls=cli_machinery.PassphraseGenerationOption,
1570 1570
 )
1571 1571
 @click.option(
1572
-    '-n',
1573
-    '--notes',
1574
-    'edit_notes',
1572
+    "-n",
1573
+    "--notes",
1574
+    "edit_notes",
1575 1575
     is_flag=True,
1576 1576
     help=_msg.TranslatedString(
1577 1577
         _msg.Label.DERIVEPASSPHRASE_VAULT_NOTES_HELP_TEXT,
... ...
@@ -1582,9 +1582,9 @@ class _VaultContext:  # noqa: PLR0904
1582 1582
     cls=cli_machinery.ConfigurationOption,
1583 1583
 )
1584 1584
 @click.option(
1585
-    '-c',
1586
-    '--config',
1587
-    'store_config_only',
1585
+    "-c",
1586
+    "--config",
1587
+    "store_config_only",
1588 1588
     is_flag=True,
1589 1589
     help=_msg.TranslatedString(
1590 1590
         _msg.Label.DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT,
... ...
@@ -1595,9 +1595,9 @@ class _VaultContext:  # noqa: PLR0904
1595 1595
     cls=cli_machinery.ConfigurationOption,
1596 1596
 )
1597 1597
 @click.option(
1598
-    '-x',
1599
-    '--delete',
1600
-    'delete_service_settings',
1598
+    "-x",
1599
+    "--delete",
1600
+    "delete_service_settings",
1601 1601
     is_flag=True,
1602 1602
     help=_msg.TranslatedString(
1603 1603
         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_HELP_TEXT,
... ...
@@ -1608,7 +1608,7 @@ class _VaultContext:  # noqa: PLR0904
1608 1608
     cls=cli_machinery.ConfigurationOption,
1609 1609
 )
1610 1610
 @click.option(
1611
-    '--delete-globals',
1611
+    "--delete-globals",
1612 1612
     is_flag=True,
1613 1613
     help=_msg.TranslatedString(
1614 1614
         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_GLOBALS_HELP_TEXT,
... ...
@@ -1616,9 +1616,9 @@ class _VaultContext:  # noqa: PLR0904
1616 1616
     cls=cli_machinery.ConfigurationOption,
1617 1617
 )
1618 1618
 @click.option(
1619
-    '-X',
1620
-    '--clear',
1621
-    'clear_all_settings',
1619
+    "-X",
1620
+    "--clear",
1621
+    "clear_all_settings",
1622 1622
     is_flag=True,
1623 1623
     help=_msg.TranslatedString(
1624 1624
         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_ALL_HELP_TEXT,
... ...
@@ -1626,9 +1626,9 @@ class _VaultContext:  # noqa: PLR0904
1626 1626
     cls=cli_machinery.ConfigurationOption,
1627 1627
 )
1628 1628
 @click.option(
1629
-    '-e',
1630
-    '--export',
1631
-    'export_settings',
1629
+    "-e",
1630
+    "--export",
1631
+    "export_settings",
1632 1632
     metavar=_msg.TranslatedString(
1633 1633
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1634 1634
     ),
... ...
@@ -1642,9 +1642,9 @@ class _VaultContext:  # noqa: PLR0904
1642 1642
     shell_complete=cli_helpers.shell_complete_path,
1643 1643
 )
1644 1644
 @click.option(
1645
-    '-i',
1646
-    '--import',
1647
-    'import_settings',
1645
+    "-i",
1646
+    "--import",
1647
+    "import_settings",
1648 1648
     metavar=_msg.TranslatedString(
1649 1649
         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1650 1650
     ),
... ...
@@ -1658,8 +1658,8 @@ class _VaultContext:  # noqa: PLR0904
1658 1658
     shell_complete=cli_helpers.shell_complete_path,
1659 1659
 )
1660 1660
 @click.option(
1661
-    '--overwrite-existing/--merge-existing',
1662
-    'overwrite_config',
1661
+    "--overwrite-existing/--merge-existing",
1662
+    "overwrite_config",
1663 1663
     default=False,
1664 1664
     help=_msg.TranslatedString(
1665 1665
         _msg.Label.DERIVEPASSPHRASE_VAULT_OVERWRITE_HELP_TEXT
... ...
@@ -1667,21 +1667,21 @@ class _VaultContext:  # noqa: PLR0904
1667 1667
     cls=cli_machinery.CompatibilityOption,
1668 1668
 )
1669 1669
 @click.option(
1670
-    '--unset',
1671
-    'unset_settings',
1670
+    "--unset",
1671
+    "unset_settings",
1672 1672
     multiple=True,
1673 1673
     type=click.Choice([
1674
-        'phrase',
1675
-        'key',
1676
-        'length',
1677
-        'repeat',
1678
-        'lower',
1679
-        'upper',
1680
-        'number',
1681
-        'space',
1682
-        'dash',
1683
-        'symbol',
1684
-        'notes',
1674
+        "phrase",
1675
+        "key",
1676
+        "length",
1677
+        "repeat",
1678
+        "lower",
1679
+        "upper",
1680
+        "number",
1681
+        "space",
1682
+        "dash",
1683
+        "symbol",
1684
+        "notes",
1685 1685
     ]),
1686 1686
     help=_msg.TranslatedString(
1687 1687
         _msg.Label.DERIVEPASSPHRASE_VAULT_UNSET_HELP_TEXT
... ...
@@ -1689,17 +1689,17 @@ class _VaultContext:  # noqa: PLR0904
1689 1689
     cls=cli_machinery.CompatibilityOption,
1690 1690
 )
1691 1691
 @click.option(
1692
-    '--export-as',
1693
-    type=click.Choice(['json', 'sh']),
1694
-    default='json',
1692
+    "--export-as",
1693
+    type=click.Choice(["json", "sh"]),
1694
+    default="json",
1695 1695
     help=_msg.TranslatedString(
1696 1696
         _msg.Label.DERIVEPASSPHRASE_VAULT_EXPORT_AS_HELP_TEXT
1697 1697
     ),
1698 1698
     cls=cli_machinery.CompatibilityOption,
1699 1699
 )
1700 1700
 @click.option(
1701
-    '--modern-editor-interface/--vault-legacy-editor-interface',
1702
-    'modern_editor_interface',
1701
+    "--modern-editor-interface/--vault-legacy-editor-interface",
1702
+    "modern_editor_interface",
1703 1703
     default=False,
1704 1704
     help=_msg.TranslatedString(
1705 1705
         _msg.Label.DERIVEPASSPHRASE_VAULT_EDITOR_INTERFACE_HELP_TEXT
... ...
@@ -1707,8 +1707,8 @@ class _VaultContext:  # noqa: PLR0904
1707 1707
     cls=cli_machinery.CompatibilityOption,
1708 1708
 )
1709 1709
 @click.option(
1710
-    '--print-notes-before/--print-notes-after',
1711
-    'print_notes_before',
1710
+    "--print-notes-before/--print-notes-after",
1711
+    "print_notes_before",
1712 1712
     default=False,
1713 1713
     help=_msg.TranslatedString(
1714 1714
         _msg.Label.DERIVEPASSPHRASE_VAULT_PRINT_NOTES_BEFORE_HELP_TEXT,
... ...
@@ -1722,7 +1722,7 @@ class _VaultContext:  # noqa: PLR0904
1722 1722
 @cli_machinery.color_forcing_pseudo_option
1723 1723
 @cli_machinery.standard_logging_options
1724 1724
 @click.argument(
1725
-    'service',
1725
+    "service",
1726 1726
     metavar=_msg.TranslatedString(_msg.Label.VAULT_METAVAR_SERVICE),
1727 1727
     required=False,
1728 1728
     default=None,
... ...
@@ -1843,5 +1843,5 @@ def derivepassphrase_vault(
1843 1843
     vault_context.dispatch_op()
1844 1844
 
1845 1845
 
1846
-if __name__ == '__main__':
1846
+if __name__ == "__main__":
1847 1847
     derivepassphrase()
... ...
@@ -21,7 +21,7 @@ __all__ = ()
21 21
 
22 22
 
23 23
 INVALID_VAULT_NATIVE_CONFIGURATION_FORMAT = (
24
-    'Invalid vault native configuration format: {fmt!r}'
24
+    "Invalid vault native configuration format: {fmt!r}"
25 25
 )
26 26
 
27 27
 
... ...
@@ -39,11 +39,11 @@ class NotAVaultConfigError(ValueError):
39 39
     def __str__(self) -> str:  # pragma: no cover [failsafe]
40 40
         """"""  # noqa: D419
41 41
         formatted_format = (
42
-            f'vault {self.format} configuration'
42
+            f"vault {self.format} configuration"
43 43
             if self.format
44
-            else 'vault configuration'
44
+            else "vault configuration"
45 45
         )
46
-        return f'Not a {formatted_format}: {self.path!r}'
46
+        return f"Not a {formatted_format}: {self.path!r}"
47 47
 
48 48
 
49 49
 def get_vault_key() -> bytes:
... ...
@@ -66,22 +66,22 @@ def get_vault_key() -> bytes:
66 66
     """
67 67
 
68 68
     def getenv_environb(env_var: str) -> bytes:  # pragma: no cover [external]
69
-        return os.environb.get(env_var.encode('UTF-8'), b'')  # type: ignore[attr-defined]
69
+        return os.environb.get(env_var.encode("UTF-8"), b"")  # type: ignore[attr-defined]
70 70
 
71 71
     def getenv_environ(env_var: str) -> bytes:  # pragma: no cover [external]
72
-        return os.environ.get(env_var, '').encode('UTF-8')
72
+        return os.environ.get(env_var, "").encode("UTF-8")
73 73
 
74 74
     getenv: Callable[[str], bytes] = (
75 75
         getenv_environb if os.supports_bytes_environ else getenv_environ
76 76
     )
77 77
     username = (
78
-        getenv('VAULT_KEY')
79
-        or getenv('LOGNAME')
80
-        or getenv('USER')
81
-        or getenv('USERNAME')
78
+        getenv("VAULT_KEY")
79
+        or getenv("LOGNAME")
80
+        or getenv("USER")
81
+        or getenv("USERNAME")
82 82
     )
83 83
     if not username:
84
-        env_var = 'VAULT_KEY'
84
+        env_var = "VAULT_KEY"
85 85
         raise KeyError(env_var)
86 86
     return username
87 87
 
... ...
@@ -104,7 +104,7 @@ def get_vault_path() -> pathlib.Path:
104 104
 
105 105
     """
106 106
     return pathlib.Path(
107
-        '~', os.environ.get('VAULT_PATH', '.vault')
107
+        "~", os.environ.get("VAULT_PATH", ".vault")
108 108
     ).expanduser()
109 109
 
110 110
 
... ...
@@ -181,10 +181,10 @@ def register_export_vault_config_data_handler(
181 181
     *names: str,
182 182
 ) -> Callable[[ExportVaultConfigDataFunction], ExportVaultConfigDataFunction]:
183 183
     if not names:
184
-        msg = 'No names given to export_data handler registry'
184
+        msg = "No names given to export_data handler registry"
185 185
         raise ValueError(msg)
186
-    if '' in names:
187
-        msg = 'Cannot register export_data handler under an empty name'
186
+    if "" in names:
187
+        msg = "Cannot register export_data handler under an empty name"
188 188
         raise ValueError(msg)
189 189
 
190 190
     def wrapper(
... ...
@@ -192,7 +192,7 @@ def register_export_vault_config_data_handler(
192 192
     ) -> ExportVaultConfigDataFunction:
193 193
         for name in names:
194 194
             if name in _export_vault_config_data_registry:
195
-                msg = f'export_data handler already registered: {name!r}'
195
+                msg = f"export_data handler already registered: {name!r}"
196 196
                 raise ValueError(msg)
197 197
             _export_vault_config_data_registry[name] = f
198 198
         return f
... ...
@@ -214,8 +214,8 @@ def find_vault_config_data_handlers() -> None:
214 214
     # imports.  The modules themselves contain function definitions that
215 215
     # register themselves automatically with
216 216
     # `_export_vault_config_data_registry`.
217
-    importlib.import_module('derivepassphrase.exporter.storeroom')
218
-    importlib.import_module('derivepassphrase.exporter.vault_native')
217
+    importlib.import_module("derivepassphrase.exporter.storeroom")
218
+    importlib.import_module("derivepassphrase.exporter.vault_native")
219 219
 
220 220
 
221 221
 def export_vault_config_data(
... ...
@@ -50,7 +50,7 @@ if TYPE_CHECKING:
50 50
     STUBBED = False
51 51
 else:
52 52
     try:
53
-        importlib.import_module('cryptography')
53
+        importlib.import_module("cryptography")
54 54
     except ModuleNotFoundError as exc:
55 55
 
56 56
         class _DummyModule:
... ...
@@ -78,24 +78,24 @@ else:
78 78
 
79 79
         STUBBED = False
80 80
 
81
-STOREROOM_MASTER_KEYS_UUID = b'35b7c7ed-f71e-4adf-9051-02fb0f1e0e17'
82
-VAULT_CIPHER_UUID = b'73e69e8a-cb05-4b50-9f42-59d76a511299'
81
+STOREROOM_MASTER_KEYS_UUID = b"35b7c7ed-f71e-4adf-9051-02fb0f1e0e17"
82
+VAULT_CIPHER_UUID = b"73e69e8a-cb05-4b50-9f42-59d76a511299"
83 83
 IV_SIZE = 16
84 84
 KEY_SIZE = MAC_SIZE = 32
85 85
 ENCRYPTED_KEYPAIR_SIZE = 128
86 86
 VERSION_SIZE = 1
87 87
 
88
-__all__ = ('export_storeroom_data',)
88
+__all__ = ("export_storeroom_data",)
89 89
 
90 90
 logger = logging.getLogger(__name__)
91 91
 
92 92
 
93
-@exporter.register_export_vault_config_data_handler('storeroom')
93
+@exporter.register_export_vault_config_data_handler("storeroom")
94 94
 def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
95 95
     path: str | bytes | os.PathLike | None = None,
96 96
     key: str | Buffer | None = None,
97 97
     *,
98
-    format: str = 'storeroom',  # noqa: A002
98
+    format: str = "storeroom",  # noqa: A002
99 99
 ) -> dict[str, Any]:
100 100
     """Export the full configuration stored in the storeroom.
101 101
 
... ...
@@ -108,39 +108,39 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
108 108
 
109 109
     """  # noqa: DOC201,DOC501
110 110
     # Trigger import errors if necessary.
111
-    importlib.import_module('cryptography')
111
+    importlib.import_module("cryptography")
112 112
     if path is None:
113 113
         path = exporter.get_vault_path()
114 114
     else:
115 115
         path = pathlib.Path(os.fsdecode(path))
116 116
     if key is None:
117 117
         key = exporter.get_vault_key()
118
-    if format != 'storeroom':  # pragma: no cover [failsafe]
118
+    if format != "storeroom":  # pragma: no cover [failsafe]
119 119
         msg = exporter.INVALID_VAULT_NATIVE_CONFIGURATION_FORMAT.format(
120 120
             fmt=format
121 121
         )
122 122
         raise ValueError(msg)
123 123
     try:
124
-        master_keys_file = pathlib.Path(path, '.keys').open(  # noqa: SIM115
125
-            encoding='utf-8',
124
+        master_keys_file = pathlib.Path(path, ".keys").open(  # noqa: SIM115
125
+            encoding="utf-8",
126 126
         )
127 127
     except FileNotFoundError as exc:
128
-        raise exporter.NotAVaultConfigError(path, format='storeroom') from exc
128
+        raise exporter.NotAVaultConfigError(path, format="storeroom") from exc
129 129
     with master_keys_file:
130 130
         header = json.loads(master_keys_file.readline())
131
-        if header != {'version': 1}:
132
-            msg = 'bad or unsupported keys version header'
131
+        if header != {"version": 1}:
132
+            msg = "bad or unsupported keys version header"
133 133
             raise RuntimeError(msg)
134 134
         raw_keys_data = base64.standard_b64decode(master_keys_file.readline())
135 135
         encrypted_keys_params, encrypted_keys = struct.unpack(
136
-            f'B {len(raw_keys_data) - 1}s', raw_keys_data
136
+            f"B {len(raw_keys_data) - 1}s", raw_keys_data
137 137
         )
138 138
         if master_keys_file.read():
139
-            msg = 'trailing data; cannot make sense of .keys file'
139
+            msg = "trailing data; cannot make sense of .keys file"
140 140
             raise RuntimeError(msg)
141 141
     encrypted_keys_version = encrypted_keys_params >> 4
142 142
     if encrypted_keys_version != 1:
143
-        msg = f'cannot handle version {encrypted_keys_version} encrypted keys'
143
+        msg = f"cannot handle version {encrypted_keys_version} encrypted keys"
144 144
         raise RuntimeError(msg)
145 145
     logger.info(
146 146
         _msg.TranslatedString(_msg.InfoMsgTemplate.PARSING_MASTER_KEYS_DATA)
... ...
@@ -151,7 +151,7 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
151 151
 
152 152
     config_structure: dict[str, Any] = {}
153 153
     json_contents: dict[str, bytes] = {}
154
-    valid_hashdirs = list(path.glob('[01][0-9a-f]'))
154
+    valid_hashdirs = list(path.glob("[01][0-9a-f]"))
155 155
     for file in valid_hashdirs:
156 156
         logger.info(
157 157
             _msg.TranslatedString(
... ...
@@ -178,12 +178,12 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
178 178
         _msg.TranslatedString(_msg.InfoMsgTemplate.ASSEMBLING_CONFIG_STRUCTURE)
179 179
     )
180 180
     for item_path, json_content in sorted(json_contents.items()):
181
-        if item_path.endswith('/'):
181
+        if item_path.endswith("/"):
182 182
             logger.debug(
183 183
                 _msg.TranslatedString(
184 184
                     _msg.DebugMsgTemplate.POSTPONING_DIRECTORY_CONTENTS_CHECK,
185 185
                     path=item_path,
186
-                    contents=json_content.decode('utf-8'),
186
+                    contents=json_content.decode("utf-8"),
187 187
                 )
188 188
             )
189 189
             json_payload = json.loads(json_content)
... ...
@@ -191,8 +191,8 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
191 191
                 not isinstance(x, str) for x in json_payload
192 192
             ):
193 193
                 msg = (
194
-                    f'Directory index is not actually an index: '
195
-                    f'{json_content!r}'
194
+                    f"Directory index is not actually an index: "
195
+                    f"{json_content!r}"
196 196
                 )
197 197
                 raise RuntimeError(msg)
198 198
             dirs_to_check[item_path] = json_payload
... ...
@@ -202,13 +202,13 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
202 202
                     path=item_path,
203 203
                 ),
204 204
             )
205
-            _store(config_structure, item_path, b'{}')
205
+            _store(config_structure, item_path, b"{}")
206 206
         else:
207 207
             logger.debug(
208 208
                 _msg.TranslatedString(
209 209
                     _msg.DebugMsgTemplate.SETTING_CONFIG_STRUCTURE_CONTENTS,
210 210
                     path=item_path,
211
-                    value=json_content.decode('utf-8'),
211
+                    value=json_content.decode("utf-8"),
212 212
                 ),
213 213
             )
214 214
             _store(config_structure, item_path, json_content)
... ...
@@ -219,9 +219,9 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
219 219
     )
220 220
     # Sorted order is important; see `maybe_obj` below.
221 221
     for dir_, namelist_ in sorted(dirs_to_check.items()):
222
-        namelist = [x.rstrip('/') for x in namelist_]
222
+        namelist = [x.rstrip("/") for x in namelist_]
223 223
         obj: dict[Any, Any] = config_structure
224
-        for part in dir_.split('/'):
224
+        for part in dir_.split("/"):
225 225
             if part:
226 226
                 # Because we iterate paths in sorted order, parent
227 227
                 # directories are encountered before child directories.
... ...
@@ -232,11 +232,11 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
232 232
                 # this, so we need to use assertions anyway.
233 233
                 maybe_obj = obj.get(part)
234 234
                 assert isinstance(maybe_obj, dict), (
235
-                    f'Cannot traverse storage path {dir_!r}'
235
+                    f"Cannot traverse storage path {dir_!r}"
236 236
                 )
237 237
                 obj = maybe_obj
238 238
         if set(obj.keys()) != set(namelist):
239
-            msg = f'Object key mismatch for path {dir_!r}'
239
+            msg = f"Object key mismatch for path {dir_!r}"
240 240
             raise RuntimeError(msg)
241 241
         logger.debug(
242 242
             _msg.TranslatedString(
... ...
@@ -249,7 +249,7 @@ def export_storeroom_data(  # noqa: C901,D417,PLR0912,PLR0914,PLR0915
249 249
 
250 250
 
251 251
 def _h(bs: Buffer) -> str:
252
-    return '<{}>'.format(memoryview(bs).hex(' '))
252
+    return "<{}>".format(memoryview(bs).hex(" "))
253 253
 
254 254
 
255 255
 def _derive_master_keys_keys(
... ...
@@ -284,7 +284,7 @@ def _derive_master_keys_keys(
284 284
 
285 285
     """
286 286
     if isinstance(password, str):
287
-        password = password.encode('ASCII')
287
+        password = password.encode("ASCII")
288 288
     master_keys_keys_blob = pbkdf2.PBKDF2HMAC(
289 289
         algorithm=hashes.SHA1(),
290 290
         length=2 * KEY_SIZE,
... ...
@@ -292,7 +292,7 @@ def _derive_master_keys_keys(
292 292
         iterations=iterations,
293 293
     ).derive(bytes(password))
294 294
     encryption_key, signing_key = struct.unpack(
295
-        f'{KEY_SIZE}s {KEY_SIZE}s', master_keys_keys_blob
295
+        f"{KEY_SIZE}s {KEY_SIZE}s", master_keys_keys_blob
296 296
     )
297 297
     logger.debug(
298 298
         _msg.TranslatedString(
... ...
@@ -300,7 +300,7 @@ def _derive_master_keys_keys(
300 300
             enc_key=_h(encryption_key),
301 301
             sign_key=_h(signing_key),
302 302
             pw_bytes=_h(password),
303
-            algorithm='SHA256',
303
+            algorithm="SHA256",
304 304
             length=64,
305 305
             salt=STOREROOM_MASTER_KEYS_UUID,
306 306
             iterations=iterations,
... ...
@@ -362,10 +362,10 @@ def _decrypt_master_keys_data(
362 362
         removal.
363 363
 
364 364
     """
365
-    data = memoryview(data).toreadonly().cast('c')
365
+    data = memoryview(data).toreadonly().cast("c")
366 366
     keys = keys.toreadonly()
367 367
     ciphertext, claimed_mac = struct.unpack(
368
-        f'{len(data) - MAC_SIZE}s {MAC_SIZE}s', data
368
+        f"{len(data) - MAC_SIZE}s {MAC_SIZE}s", data
369 369
     )
370 370
     actual_mac = hmac.HMAC(keys.signing_key, hashes.SHA256())
371 371
     actual_mac.update(ciphertext)
... ...
@@ -382,7 +382,7 @@ def _decrypt_master_keys_data(
382 382
 
383 383
     try:
384 384
         iv, payload = struct.unpack(
385
-            f'{IV_SIZE}s {len(ciphertext) - IV_SIZE}s', ciphertext
385
+            f"{IV_SIZE}s {len(ciphertext) - IV_SIZE}s", ciphertext
386 386
         )
387 387
         decryptor = ciphers.Cipher(
388 388
             algorithms.AES256(keys.encryption_key), modes.CBC(iv)
... ...
@@ -395,10 +395,10 @@ def _decrypt_master_keys_data(
395 395
         plaintext.extend(unpadder.update(padded_plaintext))
396 396
         plaintext.extend(unpadder.finalize())
397 397
         hashing_key, encryption_key, signing_key = struct.unpack(
398
-            f'{KEY_SIZE}s {KEY_SIZE}s {KEY_SIZE}s', plaintext
398
+            f"{KEY_SIZE}s {KEY_SIZE}s {KEY_SIZE}s", plaintext
399 399
         )
400 400
     except (ValueError, struct.error) as exc:
401
-        msg = 'Invalid encrypted master keys payload'
401
+        msg = "Invalid encrypted master keys payload"
402 402
         raise ValueError(msg) from exc
403 403
     return _types.StoreroomMasterKeys(
404 404
         hashing_key=hashing_key,
... ...
@@ -455,10 +455,10 @@ def _decrypt_session_keys(
455 455
         removal.
456 456
 
457 457
     """
458
-    data = memoryview(data).toreadonly().cast('c')
458
+    data = memoryview(data).toreadonly().cast("c")
459 459
     master_keys = master_keys.toreadonly()
460 460
     ciphertext, claimed_mac = struct.unpack(
461
-        f'{len(data) - MAC_SIZE}s {MAC_SIZE}s', data
461
+        f"{len(data) - MAC_SIZE}s {MAC_SIZE}s", data
462 462
     )
463 463
     actual_mac = hmac.HMAC(master_keys.signing_key, hashes.SHA256())
464 464
     actual_mac.update(ciphertext)
... ...
@@ -475,7 +475,7 @@ def _decrypt_session_keys(
475 475
 
476 476
     try:
477 477
         iv, payload = struct.unpack(
478
-            f'{IV_SIZE}s {len(ciphertext) - IV_SIZE}s', ciphertext
478
+            f"{IV_SIZE}s {len(ciphertext) - IV_SIZE}s", ciphertext
479 479
         )
480 480
         decryptor = ciphers.Cipher(
481 481
             algorithms.AES256(master_keys.encryption_key), modes.CBC(iv)
... ...
@@ -488,10 +488,10 @@ def _decrypt_session_keys(
488 488
         plaintext.extend(unpadder.update(padded_plaintext))
489 489
         plaintext.extend(unpadder.finalize())
490 490
         session_encryption_key, session_signing_key = struct.unpack(
491
-            f'{KEY_SIZE}s {KEY_SIZE}s', plaintext
491
+            f"{KEY_SIZE}s {KEY_SIZE}s", plaintext
492 492
         )
493 493
     except (ValueError, struct.error) as exc:
494
-        msg = 'Invalid encrypted session keys payload'
494
+        msg = "Invalid encrypted session keys payload"
495 495
         raise ValueError(msg) from exc
496 496
 
497 497
     session_keys = _types.StoreroomKeyPair(
... ...
@@ -507,10 +507,10 @@ def _decrypt_session_keys(
507 507
             ciphertext=_h(payload),
508 508
             plaintext=_h(plaintext),
509 509
             code=_msg.TranslatedString(
510
-                'StoreroomKeyPair(encryption_key=bytes.fromhex({enc_key!r}), '
511
-                'signing_key=bytes.fromhex({sign_key!r}))',
512
-                enc_key=session_keys.encryption_key.hex(' '),
513
-                sign_key=session_keys.signing_key.hex(' '),
510
+                "StoreroomKeyPair(encryption_key=bytes.fromhex({enc_key!r}), "
511
+                "signing_key=bytes.fromhex({sign_key!r}))",
512
+                enc_key=session_keys.encryption_key.hex(" "),
513
+                sign_key=session_keys.signing_key.hex(" "),
514 514
             ),
515 515
         ),
516 516
     )
... ...
@@ -562,10 +562,10 @@ def _decrypt_contents(
562 562
         removal.
563 563
 
564 564
     """
565
-    data = memoryview(data).toreadonly().cast('c')
565
+    data = memoryview(data).toreadonly().cast("c")
566 566
     session_keys = session_keys.toreadonly()
567 567
     ciphertext, claimed_mac = struct.unpack(
568
-        f'{len(data) - MAC_SIZE}s {MAC_SIZE}s', data
568
+        f"{len(data) - MAC_SIZE}s {MAC_SIZE}s", data
569 569
     )
570 570
     actual_mac = hmac.HMAC(session_keys.signing_key, hashes.SHA256())
571 571
     actual_mac.update(ciphertext)
... ...
@@ -581,7 +581,7 @@ def _decrypt_contents(
581 581
     actual_mac.verify(claimed_mac)
582 582
 
583 583
     iv, payload = struct.unpack(
584
-        f'{IV_SIZE}s {len(ciphertext) - IV_SIZE}s', ciphertext
584
+        f"{IV_SIZE}s {len(ciphertext) - IV_SIZE}s", ciphertext
585 585
     )
586 586
     decryptor = ciphers.Cipher(
587 587
         algorithms.AES256(session_keys.encryption_key), modes.CBC(iv)
... ...
@@ -638,7 +638,7 @@ def _decrypt_bucket_item(
638 638
         removal.
639 639
 
640 640
     """
641
-    bucket_item = memoryview(bucket_item).toreadonly().cast('c')
641
+    bucket_item = memoryview(bucket_item).toreadonly().cast("c")
642 642
     master_keys = master_keys.toreadonly()
643 643
     logger.debug(
644 644
         _msg.TranslatedString(
... ...
@@ -650,13 +650,13 @@ def _decrypt_bucket_item(
650 650
     )
651 651
     data_version, encrypted_session_keys, data_contents = struct.unpack(
652 652
         (
653
-            f'B {ENCRYPTED_KEYPAIR_SIZE}s '
654
-            f'{len(bucket_item) - 1 - ENCRYPTED_KEYPAIR_SIZE}s'
653
+            f"B {ENCRYPTED_KEYPAIR_SIZE}s "
654
+            f"{len(bucket_item) - 1 - ENCRYPTED_KEYPAIR_SIZE}s"
655 655
         ),
656 656
         bucket_item,
657 657
     )
658 658
     if data_version != 1:
659
-        msg = f'Cannot handle version {data_version} encrypted data'
659
+        msg = f"Cannot handle version {data_version} encrypted data"
660 660
         raise ValueError(msg)
661 661
     session_keys = _decrypt_session_keys(encrypted_session_keys, master_keys)
662 662
     return _decrypt_contents(data_contents, session_keys)
... ...
@@ -666,7 +666,7 @@ def _decrypt_bucket_file(
666 666
     filename: str | bytes | os.PathLike,
667 667
     master_keys: _types.StoreroomMasterKeys,
668 668
     *,
669
-    root_dir: str | bytes | os.PathLike = '.',
669
+    root_dir: str | bytes | os.PathLike = ".",
670 670
 ) -> Iterator[Buffer]:
671 671
     """Decrypt a complete bucket.
672 672
 
... ...
@@ -701,15 +701,15 @@ def _decrypt_bucket_file(
701 701
     master_keys = master_keys.toreadonly()
702 702
     root_dir = pathlib.Path(os.fsdecode(root_dir))
703 703
     filename = pathlib.Path(os.fsdecode(filename))
704
-    with (root_dir / filename).open('rb') as bucket_file:
704
+    with (root_dir / filename).open("rb") as bucket_file:
705 705
         header_line = bucket_file.readline()
706 706
         try:
707 707
             header = json.loads(header_line)
708 708
         except ValueError as exc:
709
-            msg = f'Invalid bucket file: {filename}'
709
+            msg = f"Invalid bucket file: {filename}"
710 710
             raise ValueError(msg) from exc
711
-        if header != {'version': 1}:
712
-            msg = f'Invalid bucket file: {filename}'
711
+        if header != {"version": 1}:
712
+            msg = f"Invalid bucket file: {filename}"
713 713
             raise ValueError(msg) from None
714 714
         for line in bucket_file:
715 715
             yield _decrypt_bucket_item(
... ...
@@ -740,14 +740,14 @@ def _store(config: dict[str, Any], path: str, json_contents: bytes) -> None:
740 740
 
741 741
     """
742 742
     contents = json.loads(json_contents)
743
-    path_parts = [part for part in path.split('/') if part]
743
+    path_parts = [part for part in path.split("/") if part]
744 744
     for part in path_parts[:-1]:
745 745
         config = config.setdefault(part, {})
746 746
     if path_parts:
747 747
         config[path_parts[-1]] = contents
748 748
 
749 749
 
750
-if __name__ == '__main__':
751
-    logging.basicConfig(level=('DEBUG' if os.getenv('DEBUG') else 'WARNING'))
752
-    config_structure = export_storeroom_data(format='storeroom')
750
+if __name__ == "__main__":
751
+    logging.basicConfig(level=("DEBUG" if os.getenv("DEBUG") else "WARNING"))
752
+    config_structure = export_storeroom_data(format="storeroom")
753 753
     print(json.dumps(config_structure, indent=2, sort_keys=True))  # noqa: T201
... ...
@@ -54,7 +54,7 @@ if TYPE_CHECKING:
54 54
     STUBBED = False
55 55
 else:
56 56
     try:
57
-        importlib.import_module('cryptography')
57
+        importlib.import_module("cryptography")
58 58
     except ModuleNotFoundError as exc:
59 59
 
60 60
         class _DummyModule:
... ...
@@ -85,12 +85,12 @@ else:
85 85
 
86 86
         STUBBED = False
87 87
 
88
-__all__ = ('export_vault_native_data',)
88
+__all__ = ("export_vault_native_data",)
89 89
 
90 90
 logger = logging.getLogger(__name__)
91 91
 
92 92
 
93
-@exporter.register_export_vault_config_data_handler('v0.2', 'v0.3')
93
+@exporter.register_export_vault_config_data_handler("v0.2", "v0.3")
94 94
 def export_vault_native_data(  # noqa: D417
95 95
     path: str | bytes | os.PathLike | None = None,
96 96
     key: str | Buffer | None = None,
... ...
@@ -108,18 +108,18 @@ def export_vault_native_data(  # noqa: D417
108 108
 
109 109
     """  # noqa: DOC201,DOC501
110 110
     # Trigger import errors if necessary.
111
-    importlib.import_module('cryptography')
111
+    importlib.import_module("cryptography")
112 112
     if path is None:
113 113
         path = exporter.get_vault_path()
114 114
     else:
115 115
         path = pathlib.Path(os.fsdecode(path))
116
-    with path.open('rb') as infile:
116
+    with path.open("rb") as infile:
117 117
         contents = base64.standard_b64decode(infile.read())
118 118
     if key is None:
119 119
         key = exporter.get_vault_key()
120 120
     parser_class: type[VaultNativeConfigParser] | None = {
121
-        'v0.2': VaultNativeV02ConfigParser,
122
-        'v0.3': VaultNativeV03ConfigParser,
121
+        "v0.2": VaultNativeV02ConfigParser,
122
+        "v0.3": VaultNativeV03ConfigParser,
123 123
     }.get(format)
124 124
     if parser_class is None:  # pragma: no cover [failsafe]
125 125
         msg = exporter.INVALID_VAULT_NATIVE_CONFIGURATION_FORMAT.format(
... ...
@@ -133,7 +133,7 @@ def export_vault_native_data(  # noqa: D417
133 133
 
134 134
 
135 135
 def _h(bs: Buffer) -> str:
136
-    return '<{}>'.format(memoryview(bs).hex(' '))
136
+    return "<{}>".format(memoryview(bs).hex(" "))
137 137
 
138 138
 
139 139
 class VaultNativeConfigParser(abc.ABC):
... ...
@@ -175,20 +175,20 @@ class VaultNativeConfigParser(abc.ABC):
175 175
 
176 176
         """
177 177
         if not password:
178
-            msg = 'Password must not be empty'
178
+            msg = "Password must not be empty"
179 179
             raise ValueError(msg)
180 180
         self._consistency_lock = threading.RLock()
181 181
         self._contents = bytes(contents)
182 182
         self._iv_size = 0
183 183
         self._mac_size = 0
184
-        self._encryption_key = b''
184
+        self._encryption_key = b""
185 185
         self._encryption_key_size = 0
186
-        self._signing_key = b''
186
+        self._signing_key = b""
187 187
         self._signing_key_size = 0
188
-        self._message = b''
189
-        self._message_tag = b''
190
-        self._iv = b''
191
-        self._payload = b''
188
+        self._message = b""
189
+        self._message_tag = b""
190
+        self._iv = b""
191
+        self._payload = b""
192 192
         self._password = password
193 193
         self._sentinel: object = object()
194 194
         self._data: Any = self._sentinel
... ...
@@ -247,14 +247,14 @@ class VaultNativeConfigParser(abc.ABC):
247 247
 
248 248
         """
249 249
         if isinstance(password, str):
250
-            password = password.encode('utf-8')
250
+            password = password.encode("utf-8")
251 251
         raw_key = pbkdf2.PBKDF2HMAC(
252 252
             algorithm=hashes.SHA1(),
253 253
             length=key_size // 2,
254 254
             salt=vault.Vault.UUID,
255 255
             iterations=iterations,
256 256
         ).derive(bytes(password))
257
-        result_key = raw_key.hex().lower().encode('ASCII')
257
+        result_key = raw_key.hex().lower().encode("ASCII")
258 258
         logger.debug(
259 259
             _msg.TranslatedString(
260 260
                 _msg.DebugMsgTemplate.VAULT_NATIVE_PBKDF2_CALL,
... ...
@@ -262,9 +262,9 @@ class VaultNativeConfigParser(abc.ABC):
262 262
                 salt=vault.Vault.UUID,
263 263
                 iterations=iterations,
264 264
                 key_size=key_size // 2,
265
-                algorithm='sha1',
265
+                algorithm="sha1",
266 266
                 raw_result=raw_key,
267
-                result_key=result_key.decode('ASCII'),
267
+                result_key=result_key.decode("ASCII"),
268 268
             ),
269 269
         )
270 270
         return result_key
... ...
@@ -295,7 +295,7 @@ class VaultNativeConfigParser(abc.ABC):
295 295
             mac_size = self._mac_size
296 296
 
297 297
             if len(contents) < iv_size + 16 + mac_size:
298
-                msg = 'Invalid vault configuration file: file is truncated'
298
+                msg = "Invalid vault configuration file: file is truncated"
299 299
                 raise ValueError(msg)
300 300
 
301 301
             cutpos1 = len(contents) - mac_size
... ...
@@ -333,10 +333,10 @@ class VaultNativeConfigParser(abc.ABC):
333 333
         with self._consistency_lock:
334 334
             self._generate_keys()
335 335
             assert len(self._encryption_key) == self._encryption_key_size, (
336
-                'Derived encryption key is invalid'
336
+                "Derived encryption key is invalid"
337 337
             )
338 338
             assert len(self._signing_key) == self._signing_key_size, (
339
-                'Derived signing key is invalid'
339
+                "Derived signing key is invalid"
340 340
             )
341 341
 
342 342
     @abc.abstractmethod
... ...
@@ -384,7 +384,7 @@ class VaultNativeConfigParser(abc.ABC):
384 384
         try:
385 385
             mac.verify(mac_expected)
386 386
         except crypt_exceptions.InvalidSignature:
387
-            msg = 'File does not contain a valid signature'
387
+            msg = "File does not contain a valid signature"
388 388
             raise ValueError(msg) from None
389 389
 
390 390
     @abc.abstractmethod
... ...
@@ -513,7 +513,7 @@ class VaultNativeV03ConfigParser(VaultNativeConfigParser):
513 513
         This includes hexadecimal encoding of the message payload.
514 514
 
515 515
         """
516
-        return self._message.hex().lower().encode('ASCII')
516
+        return self._message.hex().lower().encode("ASCII")
517 517
 
518 518
     def _make_decryptor(self) -> ciphers.CipherContext:
519 519
         """Return the cipher context object used for decryption.
... ...
@@ -575,7 +575,7 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser):
575 575
             super()._parse_contents()
576 576
             payload = self._payload = base64.standard_b64decode(self._payload)
577 577
             message_tag = self._message_tag = bytes.fromhex(
578
-                self._message_tag.decode('ASCII')
578
+                self._message_tag.decode("ASCII")
579 579
             )
580 580
         logger.debug(
581 581
             _msg.TranslatedString(
... ...
@@ -647,7 +647,7 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser):
647 647
             value (if any):
648 648
 
649 649
             ~~~~ python
650
-            data = block_input = b''.join([previous_block, input_string, salt])
650
+            data = block_input = b"".join([previous_block, input_string, salt])
651 651
             for i in range(iteration_count):
652 652
                 data = message_digest(data)
653 653
             block = data
... ...
@@ -683,8 +683,8 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser):
683 683
         """
684 684
         total_size = key_size + iv_size
685 685
         buffer = bytearray()
686
-        last_block = b''
687
-        salt = b''
686
+        last_block = b""
687
+        salt = b""
688 688
         logger.debug(
689 689
             _msg.TranslatedString(
690 690
                 _msg.DebugMsgTemplate.VAULT_NATIVE_EVP_BYTESTOKEY_INIT,
... ...
@@ -699,7 +699,7 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser):
699 699
         while len(buffer) < total_size:
700 700
             with warnings.catch_warnings():
701 701
                 warnings.simplefilter(
702
-                    'ignore', crypt_utils.CryptographyDeprecationWarning
702
+                    "ignore", crypt_utils.CryptographyDeprecationWarning
703 703
                 )
704 704
                 block = hashes.Hash(hashes.MD5())
705 705
             block.update(last_block)
... ...
@@ -753,11 +753,11 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser):
753 753
         ).decryptor()
754 754
 
755 755
 
756
-if __name__ == '__main__':
756
+if __name__ == "__main__":
757 757
     import os
758 758
 
759
-    logging.basicConfig(level=('DEBUG' if os.getenv('DEBUG') else 'WARNING'))
760
-    with exporter.get_vault_path().open('rb') as infile:
759
+    logging.basicConfig(level=("DEBUG" if os.getenv("DEBUG") else "WARNING"))
760
+    with exporter.get_vault_path().open("rb") as infile:
761 761
         contents = base64.standard_b64decode(infile.read())
762 762
     password = exporter.get_vault_key()
763 763
     try:
... ...
@@ -31,7 +31,7 @@ from typing_extensions import assert_type
31 31
 if TYPE_CHECKING:
32 32
     from collections.abc import Iterator, Sequence
33 33
 
34
-__all__ = ('Sequin', 'SequinExhaustedError')
34
+__all__ = ("Sequin", "SequinExhaustedError")
35 35
 
36 36
 
37 37
 class Sequin:
... ...
@@ -85,7 +85,7 @@ class Sequin:
85 85
                 range.
86 86
 
87 87
         """
88
-        msg = 'sequence item out of range'
88
+        msg = "sequence item out of range"
89 89
 
90 90
         def uint8_to_bits(value: int) -> Iterator[int]:
91 91
             """Yield individual bits of an 8-bit number, MSB first."""
... ...
@@ -94,7 +94,7 @@ class Sequin:
94 94
 
95 95
         if isinstance(sequence, str):
96 96
             try:
97
-                sequence = tuple(sequence.encode('iso-8859-1'))
97
+                sequence = tuple(sequence.encode("iso-8859-1"))
98 98
             except UnicodeError as e:
99 99
                 raise ValueError(msg) from e
100 100
         else:
... ...
@@ -204,7 +204,7 @@ class Sequin:
204 204
 
205 205
         """  # noqa: DOC501
206 206
         if base < 2:  # noqa: PLR2004
207
-            msg = f'invalid base: {base!r}'
207
+            msg = f"invalid base: {base!r}"
208 208
             raise ValueError(msg)
209 209
         ret = 0
210 210
         allowed_range = range(base)
... ...
@@ -213,10 +213,10 @@ class Sequin:
213 213
             i2 = (n - 1) - i
214 214
             x = digits[i]
215 215
             if not isinstance(x, int):
216
-                msg = f'not an integer: {x!r}'
216
+                msg = f"not an integer: {x!r}"
217 217
                 raise TypeError(msg)
218 218
             if x not in allowed_range:
219
-                msg = f'invalid base {base!r} digit: {x!r}'
219
+                msg = f"invalid base {base!r} digit: {x!r}"
220 220
                 raise ValueError(msg)
221 221
             ret += (base**i2) * x
222 222
         return ret
... ...
@@ -355,10 +355,10 @@ class Sequin:
355 355
 
356 356
         """
357 357
         if n < 1:
358
-            msg = 'invalid target range'
358
+            msg = "invalid target range"
359 359
             raise ValueError(msg)
360 360
         if base < 2:  # noqa: PLR2004
361
-            msg = f'invalid base: {base!r}'
361
+            msg = f"invalid base: {base!r}"
362 362
             raise ValueError(msg)
363 363
         # p = base ** k, where k is the smallest integer such that
364 364
         # p >= n.  We determine p and k inductively.
... ...
@@ -413,4 +413,4 @@ class SequinExhaustedError(Exception):
413 413
     """
414 414
 
415 415
     def __init__(self) -> None:  # noqa: D107
416
-        super().__init__('Sequin is exhausted')
416
+        super().__init__("Sequin is exhausted")
... ...
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
26 26
 
27 27
     from typing_extensions import Buffer
28 28
 
29
-__all__ = ('SSHAgentClient',)
29
+__all__ = ("SSHAgentClient",)
30 30
 
31 31
 # In SSH bytestrings, the "length" of the byte string is stored as
32 32
 # a 4-byte/32-bit unsigned integer at the beginning.
... ...
@@ -37,7 +37,7 @@ class TrailingDataError(RuntimeError):
37 37
     """The result contained trailing data."""
38 38
 
39 39
     def __init__(self) -> None:
40
-        super().__init__('Overlong response from SSH agent')
40
+        super().__init__("Overlong response from SSH agent")
41 41
 
42 42
 
43 43
 class SSHAgentFailedError(RuntimeError):
... ...
@@ -48,19 +48,19 @@ class SSHAgentFailedError(RuntimeError):
48 48
         # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9
49 49
         if self.args == (  # pragma: no branch
50 50
             _types.SSH_AGENT.FAILURE.value,
51
-            b'',
51
+            b"",
52 52
         ):
53
-            return 'The SSH agent failed to complete the request'
53
+            return "The SSH agent failed to complete the request"
54 54
         elif self.args[1]:  # noqa: RET505  # pragma: no cover [failsafe]
55 55
             code = self.args[0]
56
-            msg = self.args[1].decode('utf-8', 'surrogateescape')
57
-            return f'[Code {code:d}] {msg:s}'
56
+            msg = self.args[1].decode("utf-8", "surrogateescape")
57
+            return f"[Code {code:d}] {msg:s}"
58 58
         else:  # pragma: no cover [failsafe]
59 59
             return repr(self)
60 60
 
61 61
     def __repr__(self) -> str:  # pragma: no cover [debug]
62 62
         """"""  # noqa: D419
63
-        return f'{self.__class__.__name__}{self.args!r}'
63
+        return f"{self.__class__.__name__}{self.args!r}"
64 64
 
65 65
 
66 66
 class SSHAgentClient:
... ...
@@ -80,7 +80,7 @@ class SSHAgentClient:
80 80
     """
81 81
 
82 82
     _connection: _types.SSHAgentSocket
83
-    SOCKET_PROVIDERS: ClassVar = ('native',)
83
+    SOCKET_PROVIDERS: ClassVar = ("native",)
84 84
     """
85 85
     The default list of SSH agent socket providers.
86 86
     """
... ...
@@ -156,7 +156,7 @@ class SSHAgentClient:
156 156
                 else:
157 157
                     break
158 158
             else:
159
-                msg = 'No supported SSH agent socket provider found.'
159
+                msg = "No supported SSH agent socket provider found."
160 160
                 raise (
161 161
                     ExceptionGroup(msg, excs)
162 162
                     if excs
... ...
@@ -166,7 +166,7 @@ class SSHAgentClient:
166 166
             self._connection = socket
167 167
         else:  # pragma: no cover [failsafe]
168 168
             assert_type(socket, Never)
169
-            msg = f'invalid socket object: {socket!r}'
169
+            msg = f"invalid socket object: {socket!r}"
170 170
             raise TypeError(msg)
171 171
 
172 172
     def __enter__(self) -> Self:
... ...
@@ -221,7 +221,7 @@ class SSHAgentClient:
221 221
             b'\x01\x00\x00\x00'
222 222
 
223 223
         """
224
-        return int.to_bytes(num, 4, 'big', signed=False)
224
+        return int.to_bytes(num, 4, "big", signed=False)
225 225
 
226 226
     @classmethod
227 227
     def string(cls, payload: Buffer, /) -> bytes:
... ...
@@ -235,14 +235,14 @@ class SSHAgentClient:
235 235
             as a bytes object.
236 236
 
237 237
         Examples:
238
-            >>> SSHAgentClient.string(b'ssh-rsa')
238
+            >>> SSHAgentClient.string(b"ssh-rsa")
239 239
             b'\x00\x00\x00\x07ssh-rsa'
240 240
 
241 241
         """  # noqa: DOC501
242 242
         try:
243 243
             payload = memoryview(payload)
244 244
         except TypeError as e:
245
-            msg = 'invalid payload type'
245
+            msg = "invalid payload type"
246 246
             raise TypeError(msg) from e
247 247
         ret = bytearray()
248 248
         ret.extend(cls.uint32(len(payload)))
... ...
@@ -264,17 +264,17 @@ class SSHAgentClient:
264 264
                 The byte string is not an SSH string.
265 265
 
266 266
         Examples:
267
-            >>> SSHAgentClient.unstring(b'\x00\x00\x00\x07ssh-rsa')
267
+            >>> SSHAgentClient.unstring(b"\x00\x00\x00\x07ssh-rsa")
268 268
             b'ssh-rsa'
269
-            >>> SSHAgentClient.unstring(SSHAgentClient.string(b'ssh-ed25519'))
269
+            >>> SSHAgentClient.unstring(SSHAgentClient.string(b"ssh-ed25519"))
270 270
             b'ssh-ed25519'
271 271
 
272 272
         """
273 273
         bytestring = memoryview(bytestring)
274 274
         n = len(bytestring)
275
-        msg = 'malformed SSH byte string'
275
+        msg = "malformed SSH byte string"
276 276
         if n < HEAD_LEN or n != HEAD_LEN + int.from_bytes(
277
-            bytestring[:HEAD_LEN], 'big', signed=False
277
+            bytestring[:HEAD_LEN], "big", signed=False
278 278
         ):
279 279
             raise ValueError(msg)
280 280
         return bytes(bytestring[HEAD_LEN:])
... ...
@@ -299,21 +299,21 @@ class SSHAgentClient:
299 299
 
300 300
         Examples:
301 301
             >>> SSHAgentClient.unstring_prefix(
302
-            ...     b'\x00\x00\x00\x07ssh-rsa____trailing data'
302
+            ...     b"\x00\x00\x00\x07ssh-rsa____trailing data"
303 303
             ... )
304 304
             (b'ssh-rsa', b'____trailing data')
305 305
             >>> SSHAgentClient.unstring_prefix(
306
-            ...     SSHAgentClient.string(b'ssh-ed25519')
306
+            ...     SSHAgentClient.string(b"ssh-ed25519")
307 307
             ... )
308 308
             (b'ssh-ed25519', b'')
309 309
 
310 310
         """
311 311
         bytestring = memoryview(bytestring).toreadonly()
312 312
         n = len(bytestring)
313
-        msg = 'malformed SSH byte string'
313
+        msg = "malformed SSH byte string"
314 314
         if n < HEAD_LEN:
315 315
             raise ValueError(msg)
316
-        m = int.from_bytes(bytestring[:HEAD_LEN], 'big', signed=False)
316
+        m = int.from_bytes(bytestring[:HEAD_LEN], "big", signed=False)
317 317
         if m + HEAD_LEN > n:
318 318
             raise ValueError(msg)
319 319
         return (
... ...
@@ -380,7 +380,7 @@ class SSHAgentClient:
380 380
                 yield client
381 381
         else:  # pragma: no cover [failsafe]
382 382
             assert_type(conn, Never)
383
-            msg = f'invalid connection hint: {conn!r}'
383
+            msg = f"invalid connection hint: {conn!r}"
384 384
             raise TypeError(msg)
385 385
 
386 386
     def _agent_is_pageant(self) -> bool:
... ...
@@ -391,7 +391,7 @@ class SSHAgentClient:
391 391
 
392 392
         """
393 393
         return (
394
-            b'list-extended@putty.projects.tartarus.org'
394
+            b"list-extended@putty.projects.tartarus.org"
395 395
             in self.query_extensions()
396 396
         )
397 397
 
... ...
@@ -416,7 +416,7 @@ class SSHAgentClient:
416 416
 
417 417
         """  # noqa: E501
418 418
         known_good_agents = {
419
-            'Pageant': self._agent_is_pageant,
419
+            "Pageant": self._agent_is_pageant,
420 420
         }
421 421
         return any(  # pragma: no branch
422 422
             v() for v in known_good_agents.values()
... ...
@@ -515,12 +515,12 @@ class SSHAgentClient:
515 515
         self._connection.sendall(self.string(request_message))
516 516
         chunk = self._connection.recv(HEAD_LEN)
517 517
         if len(chunk) < HEAD_LEN:
518
-            msg = 'cannot read response length'
518
+            msg = "cannot read response length"
519 519
             raise EOFError(msg)
520
-        response_length = int.from_bytes(chunk, 'big', signed=False)
520
+        response_length = int.from_bytes(chunk, "big", signed=False)
521 521
         response = self._connection.recv(response_length)
522 522
         if len(response) < response_length:
523
-            msg = 'truncated response from SSH agent'
523
+            msg = "truncated response from SSH agent"
524 524
             raise EOFError(msg)
525 525
         if not response_code:  # pragma: no cover [failsafe]
526 526
             return response[0], response[1:]
... ...
@@ -547,30 +547,30 @@ class SSHAgentClient:
547 547
         """
548 548
         response = self.request(
549 549
             _types.SSH_AGENTC.REQUEST_IDENTITIES.value,
550
-            b'',
550
+            b"",
551 551
             response_code=_types.SSH_AGENT.IDENTITIES_ANSWER,
552 552
         )
553 553
         response_stream = collections.deque(response)
554 554
 
555 555
         def shift(num: int) -> bytes:
556
-            buf = collections.deque(b'')
556
+            buf = collections.deque(b"")
557 557
             for _ in range(num):
558 558
                 try:
559 559
                     val = response_stream.popleft()
560 560
                 except IndexError:
561 561
                     response_stream.extendleft(reversed(buf))
562
-                    msg = 'truncated response from SSH agent'
562
+                    msg = "truncated response from SSH agent"
563 563
                     raise EOFError(msg) from None
564 564
                 buf.append(val)
565 565
             return bytes(buf)
566 566
 
567
-        key_count = int.from_bytes(shift(4), 'big')
567
+        key_count = int.from_bytes(shift(4), "big")
568 568
         keys: collections.deque[_types.SSHKeyCommentPair]
569 569
         keys = collections.deque()
570 570
         for _ in range(key_count):
571
-            key_size = int.from_bytes(shift(4), 'big')
571
+            key_size = int.from_bytes(shift(4), "big")
572 572
             key = shift(key_size)
573
-            comment_size = int.from_bytes(shift(4), 'big')
573
+            comment_size = int.from_bytes(shift(4), "big")
574 574
             comment = shift(comment_size)
575 575
             # Both `key` and `comment` are not wrapped as SSH strings.
576 576
             keys.append(_types.SSHKeyCommentPair(key, comment))
... ...
@@ -629,7 +629,7 @@ class SSHAgentClient:
629 629
         if check_if_key_loaded:
630 630
             loaded_keys = frozenset({pair.key for pair in self.list_keys()})
631 631
             if bytes(key) not in loaded_keys:
632
-                msg = 'target SSH key not loaded into agent'
632
+                msg = "target SSH key not loaded into agent"
633 633
                 raise KeyError(msg)
634 634
         request_data = bytearray(self.string(key))
635 635
         request_data.extend(self.string(payload))
... ...
@@ -671,7 +671,7 @@ class SSHAgentClient:
671 671
         try:
672 672
             response_data = self.request(
673 673
                 _types.SSH_AGENTC.EXTENSION,
674
-                self.string(b'query'),
674
+                self.string(b"query"),
675 675
                 response_code={
676 676
                     _types.SSH_AGENT.EXTENSION_RESPONSE,
677 677
                     _types.SSH_AGENT.SUCCESS,
... ...
@@ -682,13 +682,13 @@ class SSHAgentClient:
682 682
             # This isn't necessarily true, e.g. for OpenSSH's ssh-agent.
683 683
             return frozenset()
684 684
         extensions: set[bytes] = set()
685
-        msg = 'Malformed response from SSH agent'
686
-        msg2 = 'Extension response message does not match request'
685
+        msg = "Malformed response from SSH agent"
686
+        msg2 = "Extension response message does not match request"
687 687
         try:
688 688
             query, response_data = self.unstring_prefix(response_data)
689 689
         except ValueError as e:
690 690
             raise RuntimeError(msg) from e
691
-        if bytes(query) != b'query':
691
+        if bytes(query) != b"query":
692 692
             raise RuntimeError(msg2)
693 693
         while response_data:
694 694
             try:
... ...
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
17 17
 
18 18
     from derivepassphrase import _types
19 19
 
20
-__all__ = ('SocketProvider',)
20
+__all__ = ("SocketProvider",)
21 21
 
22 22
 
23 23
 class NoSuchProviderError(KeyError):
... ...
@@ -64,15 +64,15 @@ class SocketProvider:
64 64
                 agent.
65 65
 
66 66
         """
67
-        if not hasattr(socket, 'AF_UNIX'):
68
-            msg = 'This Python version does not support UNIX domain sockets.'
67
+        if not hasattr(socket, "AF_UNIX"):
68
+            msg = "This Python version does not support UNIX domain sockets."
69 69
             raise AfUnixNotAvailableError(msg)
70 70
         else:  # noqa: RET506  # pragma: unless posix no cover
71 71
             sock = socket.socket(family=socket.AF_UNIX)
72
-            if 'SSH_AUTH_SOCK' not in os.environ:
73
-                msg = 'SSH_AUTH_SOCK environment variable'
72
+            if "SSH_AUTH_SOCK" not in os.environ:
73
+                msg = "SSH_AUTH_SOCK environment variable"
74 74
                 raise KeyError(msg)
75
-            ssh_auth_sock = os.environ['SSH_AUTH_SOCK']
75
+            ssh_auth_sock = os.environ["SSH_AUTH_SOCK"]
76 76
             sock.settimeout(timeout)
77 77
             sock.connect(ssh_auth_sock)
78 78
             return sock
... ...
@@ -98,13 +98,13 @@ class SocketProvider:
98 98
             [windows-ssh-agent-support]: https://the13thletter.info/derivepassphrase/0.x/wishlist/windows-ssh-agent-support/
99 99
 
100 100
         """
101
-        if not hasattr(ctypes, 'WinDLL'):
102
-            msg = 'This Python version does not support Windows named pipes.'
101
+        if not hasattr(ctypes, "WinDLL"):
102
+            msg = "This Python version does not support Windows named pipes."
103 103
             raise TheAnnoyingOsNamedPipesNotAvailableError(msg)
104 104
         else:  # noqa: RET506  # pragma: unless the-annoying-os no cover
105 105
             msg = (
106
-                'Communicating with Pageant or OpenSSH on Windows '
107
-                'is not implemented yet.'
106
+                "Communicating with Pageant or OpenSSH on Windows "
107
+                "is not implemented yet."
108 108
             )
109 109
             raise NotImplementedError(msg)
110 110
 
... ...
@@ -194,8 +194,8 @@ class SocketProvider:
194 194
                         cls.registry[alias] = f if alias == name else name
195 195
                     elif existing != f:
196 196
                         msg = (
197
-                            f'The SSH agent socket provider {alias!r} '
198
-                            f'is already registered.'
197
+                            f"The SSH agent socket provider {alias!r} "
198
+                            f"is already registered."
199 199
                         )
200 200
                         raise ValueError(msg)
201 201
             return f
... ...
@@ -251,13 +251,13 @@ class SocketProvider:
251 251
         ret = cls.lookup(provider)
252 252
         if ret is None:
253 253
             msg = (
254
-                f'The {ret!r} socket provider is not functional on or '
255
-                'not applicable to this derivepassphrase installation.'
254
+                f"The {ret!r} socket provider is not functional on or "
255
+                "not applicable to this derivepassphrase installation."
256 256
             )
257 257
             raise NotImplementedError(msg)
258 258
         return ret
259 259
 
260
-    ENTRY_POINT_GROUP_NAME = 'derivepassphrase.ssh_agent_socket_providers'
260
+    ENTRY_POINT_GROUP_NAME = "derivepassphrase.ssh_agent_socket_providers"
261 261
     """
262 262
     The group name under which [entry
263 263
     points][importlib.metadata.entry_points] for the SSH agent socket
... ...
@@ -292,42 +292,42 @@ class SocketProvider:
292 292
             group=cls.ENTRY_POINT_GROUP_NAME
293 293
         ):
294 294
             provider_entry = cast(
295
-                '_types.SSHAgentSocketProviderEntry', entry_point.load()
295
+                "_types.SSHAgentSocketProviderEntry", entry_point.load()
296 296
             )
297 297
             key = provider_entry.key
298 298
             value = entry_point.value
299 299
             dist = (
300 300
                 entry_point.dist.name  # type: ignore[union-attr]
301
-                if getattr(entry_point, 'dist', None) is not None
301
+                if getattr(entry_point, "dist", None) is not None
302 302
                 else None
303 303
             )
304
-            origin = origins.get(key, 'derivepassphrase')
304
+            origin = origins.get(key, "derivepassphrase")
305 305
             if not callable(provider_entry.provider):
306 306
                 msg = (
307
-                    f'Not an SSHAgentSocketProvider: '
308
-                    f'{dist = }, {cls.ENTRY_POINT_GROUP_NAME = }, '
309
-                    f'{value = }, {provider_entry = }'
307
+                    f"Not an SSHAgentSocketProvider: "
308
+                    f"{dist = }, {cls.ENTRY_POINT_GROUP_NAME = }, "
309
+                    f"{value = }, {provider_entry = }"
310 310
                 )
311 311
                 raise AssertionError(msg)  # noqa: TRY004
312 312
             if key in entries:
313 313
                 if entries[key] != provider_entry.provider:
314 314
                     msg = (
315
-                        f'Name clash in SSH agent socket providers '
316
-                        f'for entry {key!r}, both by {dist!r} '
317
-                        f'and by {origin!r}'
315
+                        f"Name clash in SSH agent socket providers "
316
+                        f"for entry {key!r}, both by {dist!r} "
317
+                        f"and by {origin!r}"
318 318
                     )
319 319
                     raise AssertionError(msg)
320 320
             else:
321 321
                 entries[key] = provider_entry.provider
322 322
                 origins[key] = dist
323 323
             for alias in provider_entry.aliases:
324
-                alias_origin = origins.get(alias, 'derivepassphrase')
324
+                alias_origin = origins.get(alias, "derivepassphrase")
325 325
                 if alias in entries:
326 326
                     if entries[alias] != key:
327 327
                         msg = (
328
-                            f'Name clash in SSH agent socket providers '
329
-                            f'for entry {alias!r}, both by {dist!r} '
330
-                            f'and by {alias_origin!r}'
328
+                            f"Name clash in SSH agent socket providers "
329
+                            f"for entry {alias!r}, both by {dist!r} "
330
+                            f"and by {alias_origin!r}"
331 331
                         )
332 332
                         raise AssertionError(msg)
333 333
                 else:
... ...
@@ -337,21 +337,21 @@ class SocketProvider:
337 337
 
338 338
 
339 339
 SocketProvider.registry.update({
340
-    'posix': SocketProvider.unix_domain_ssh_auth_sock,
341
-    'the_annoying_os': SocketProvider.the_annoying_os_named_pipes,
340
+    "posix": SocketProvider.unix_domain_ssh_auth_sock,
341
+    "the_annoying_os": SocketProvider.the_annoying_os_named_pipes,
342 342
     # known instances
343
-    'stub_agent': None,
344
-    'stub_with_address': None,
345
-    'stub_with_address_and_deterministic_dsa': None,
343
+    "stub_agent": None,
344
+    "stub_with_address": None,
345
+    "stub_with_address_and_deterministic_dsa": None,
346 346
     # aliases
347
-    'native': 'the_annoying_os' if os.name == 'nt' else 'posix',
348
-    'unix_domain': 'posix',
349
-    'ssh_auth_sock': 'posix',
350
-    'the_annoying_os_named_pipe': 'the_annoying_os',
351
-    'pageant_on_the_annoying_os': 'the_annoying_os',
352
-    'openssh_on_the_annoying_os': 'the_annoying_os',
353
-    'windows': 'the_annoying_os',
354
-    'windows_named_pipe': 'the_annoying_os',
355
-    'pageant_on_windows': 'the_annoying_os',
356
-    'openssh_on_windows': 'the_annoying_os',
347
+    "native": "the_annoying_os" if os.name == "nt" else "posix",
348
+    "unix_domain": "posix",
349
+    "ssh_auth_sock": "posix",
350
+    "the_annoying_os_named_pipe": "the_annoying_os",
351
+    "pageant_on_the_annoying_os": "the_annoying_os",
352
+    "openssh_on_the_annoying_os": "the_annoying_os",
353
+    "windows": "the_annoying_os",
354
+    "windows_named_pipe": "the_annoying_os",
355
+    "pageant_on_windows": "the_annoying_os",
356
+    "openssh_on_windows": "the_annoying_os",
357 357
 })
... ...
@@ -46,49 +46,49 @@ class Vault:
46 46
 
47 47
     """
48 48
 
49
-    UUID: Final = b'e87eb0f4-34cb-46b9-93ad-766c5ab063e7'
49
+    UUID: Final = b"e87eb0f4-34cb-46b9-93ad-766c5ab063e7"
50 50
     """A tag used by vault in the bit stream generation."""
51 51
     CHARSETS: Final = types.MappingProxyType(
52 52
         collections.OrderedDict([
53
-            ('lower', b'abcdefghijklmnopqrstuvwxyz'),
54
-            ('upper', b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
53
+            ("lower", b"abcdefghijklmnopqrstuvwxyz"),
54
+            ("upper", b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
55 55
             (
56
-                'alpha',
56
+                "alpha",
57 57
                 (
58 58
                     # CHARSETS['lower']
59
-                    b'abcdefghijklmnopqrstuvwxyz'
59
+                    b"abcdefghijklmnopqrstuvwxyz"
60 60
                     # CHARSETS['upper']
61
-                    b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
61
+                    b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
62 62
                 ),
63 63
             ),
64
-            ('number', b'0123456789'),
64
+            ("number", b"0123456789"),
65 65
             (
66
-                'alphanum',
66
+                "alphanum",
67 67
                 (
68 68
                     # CHARSETS['lower']
69
-                    b'abcdefghijklmnopqrstuvwxyz'
69
+                    b"abcdefghijklmnopqrstuvwxyz"
70 70
                     # CHARSETS['upper']
71
-                    b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
71
+                    b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
72 72
                     # CHARSETS['number']
73
-                    b'0123456789'
73
+                    b"0123456789"
74 74
                 ),
75 75
             ),
76
-            ('space', b' '),
77
-            ('dash', b'-_'),
78
-            ('symbol', b'!"#$%&\'()*+,./:;<=>?@[\\]^{|}~-_'),
76
+            ("space", b" "),
77
+            ("dash", b"-_"),
78
+            ("symbol", b"!\"#$%&'()*+,./:;<=>?@[\\]^{|}~-_"),
79 79
             (
80
-                'all',
80
+                "all",
81 81
                 (
82 82
                     # CHARSETS['lower']
83
-                    b'abcdefghijklmnopqrstuvwxyz'
83
+                    b"abcdefghijklmnopqrstuvwxyz"
84 84
                     # CHARSETS['upper']
85
-                    b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
85
+                    b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
86 86
                     # CHARSETS['number']
87
-                    b'0123456789'
87
+                    b"0123456789"
88 88
                     # CHARSETS['space']
89
-                    b' '
89
+                    b" "
90 90
                     # CHARSETS['symbol']
91
-                    b'!"#$%&\'()*+,./:;<=>?@[\\]^{|}~-_'
91
+                    b"!\"#$%&'()*+,./:;<=>?@[\\]^{|}~-_"
92 92
                 ),
93 93
             ),
94 94
         ])
... ...
@@ -103,7 +103,7 @@ class Vault:
103 103
     def __init__(  # noqa: PLR0913
104 104
         self,
105 105
         *,
106
-        phrase: Buffer | str = b'',
106
+        phrase: Buffer | str = b"",
107 107
         length: int = 20,
108 108
         repeat: int = 0,
109 109
         lower: int | None = None,
... ...
@@ -158,7 +158,7 @@ class Vault:
158 158
         self._phrase = self._get_binary_string(phrase)
159 159
         self._length = length
160 160
         self._repeat = repeat
161
-        self._allowed = bytearray(self.CHARSETS['all'])
161
+        self._allowed = bytearray(self.CHARSETS["all"])
162 162
         self._required: list[bytes] = []
163 163
 
164 164
         def subtract_or_require(
... ...
@@ -172,17 +172,17 @@ class Vault:
172 172
                 for _ in range(count):
173 173
                     self._required.append(characters)
174 174
 
175
-        subtract_or_require(lower, self.CHARSETS['lower'])
176
-        subtract_or_require(upper, self.CHARSETS['upper'])
177
-        subtract_or_require(number, self.CHARSETS['number'])
178
-        subtract_or_require(space, self.CHARSETS['space'])
179
-        subtract_or_require(dash, self.CHARSETS['dash'])
180
-        subtract_or_require(symbol, self.CHARSETS['symbol'])
175
+        subtract_or_require(lower, self.CHARSETS["lower"])
176
+        subtract_or_require(upper, self.CHARSETS["upper"])
177
+        subtract_or_require(number, self.CHARSETS["number"])
178
+        subtract_or_require(space, self.CHARSETS["space"])
179
+        subtract_or_require(dash, self.CHARSETS["dash"])
180
+        subtract_or_require(symbol, self.CHARSETS["symbol"])
181 181
         if len(self._required) > self._length:
182
-            msg = 'requested passphrase length too short'
182
+            msg = "requested passphrase length too short"
183 183
             raise ValueError(msg)
184 184
         if not self._allowed:
185
-            msg = 'no allowed characters left'
185
+            msg = "no allowed characters left"
186 186
             raise ValueError(msg)
187 187
         for _ in range(len(self._required), self._length):
188 188
             self._required.append(bytes(self._allowed))
... ...
@@ -210,7 +210,7 @@ class Vault:
210 210
         """
211 211
         factors: list[int] = []
212 212
         if not self._required or any(not x for x in self._required):
213
-            return float('-inf')
213
+            return float("-inf")
214 214
         for i, charset in enumerate(self._required):
215 215
             factors.extend([i + 1, len(charset)])
216 216
         factors.sort()
... ...
@@ -247,10 +247,10 @@ class Vault:
247 247
         try:
248 248
             safety_factor = float(safety_factor)
249 249
         except TypeError as e:
250
-            msg = f'invalid safety factor: not a float: {safety_factor!r}'
250
+            msg = f"invalid safety factor: not a float: {safety_factor!r}"
251 251
             raise TypeError(msg) from e
252 252
         if not math.isfinite(safety_factor) or safety_factor < 1.0:
253
-            msg = f'invalid safety factor {safety_factor!r}'
253
+            msg = f"invalid safety factor {safety_factor!r}"
254 254
             raise ValueError(msg)
255 255
         # Ensure the bound is strictly positive.
256 256
         entropy_bound = max(1, self._entropy())
... ...
@@ -271,7 +271,7 @@ class Vault:
271 271
 
272 272
         """
273 273
         if isinstance(s, str):
274
-            return s.encode('UTF-8')
274
+            return s.encode("UTF-8")
275 275
         return bytes(s)
276 276
 
277 277
     @classmethod
... ...
@@ -323,11 +323,11 @@ class Vault:
323 323
             ... 0d 08 1f ec f8 73 9b 8c 5f 55 39 16 7c 53 54 2c
324 324
             ... 1e 52 bb 30 ed 7f 89 e2 2f 69 51 55 d8 9e a6 02
325 325
             ... ''')
326
-            >>> Vault.create_hash(phrase, 'some_service', length=4)
326
+            >>> Vault.create_hash(phrase, "some_service", length=4)
327 327
             b'M\xb1<S'
328
-            >>> Vault.create_hash(phrase, b'some_service', length=16)
328
+            >>> Vault.create_hash(phrase, b"some_service", length=16)
329 329
             b'M\xb1<S\x827E\xd1M\xaf\xf8~\xc8n\x10\xcc'
330
-            >>> Vault.create_hash(phrase, b'NOSUCHSERVICE', length=16)
330
+            >>> Vault.create_hash(phrase, b"NOSUCHSERVICE", length=16)
331 331
             b'\x1c\xc3\x9c\xd9\xb6\x1a\x99CS\x07\xc41\xf4\x85#s'
332 332
 
333 333
         """
... ...
@@ -335,7 +335,7 @@ class Vault:
335 335
         assert isinstance(phrase, bytes)
336 336
         salt = cls._get_binary_string(service) + cls.UUID
337 337
         return hashlib.pbkdf2_hmac(
338
-            hash_name='sha1',
338
+            hash_name="sha1",
339 339
             password=phrase,
340 340
             salt=salt,
341 341
             iterations=8,
... ...
@@ -347,7 +347,7 @@ class Vault:
347 347
         service_name: Buffer | str,
348 348
         /,
349 349
         *,
350
-        phrase: Buffer | str = b'',
350
+        phrase: Buffer | str = b"",
351 351
     ) -> bytes:
352 352
         r"""Generate a service passphrase.
353 353
 
... ...
@@ -369,12 +369,12 @@ class Vault:
369 369
                 characters, or increase the desired passphrase length.
370 370
 
371 371
         Examples:
372
-            >>> phrase = b'She cells C shells bye the sea shoars'
372
+            >>> phrase = b"She cells C shells bye the sea shoars"
373 373
             >>> # Using default options in constructor.
374
-            >>> Vault(phrase=phrase).generate(b'google')
374
+            >>> Vault(phrase=phrase).generate(b"google")
375 375
             b': 4TVH#5:aZl8LueOT\\{'
376 376
             >>> # Also possible:
377
-            >>> Vault().generate(b'google', phrase=phrase)
377
+            >>> Vault().generate(b"google", phrase=phrase)
378 378
             b': 4TVH#5:aZl8LueOT\\{'
379 379
 
380 380
             Conflicting constraints are sometimes only found during
... ...
@@ -393,7 +393,7 @@ class Vault:
393 393
             ... )
394 394
             >>> # ... but here.
395 395
             >>> v.generate(
396
-            ...     '0', phrase=b'\x00'
396
+            ...     "0", phrase=b"\x00"
397 397
             ... )  # doctest: +IGNORE_EXCEPTION_DETAIL
398 398
             Traceback (most recent call last):
399 399
                 ...
... ...
@@ -443,7 +443,7 @@ class Vault:
443 443
                     pos = seq.generate(len(charset))
444 444
                     result.extend(charset[pos : pos + 1])
445 445
             except ValueError as exc:
446
-                msg = 'no allowed characters left'
446
+                msg = "no allowed characters left"
447 447
                 raise ValueError(msg) from exc
448 448
             except sequin.SequinExhaustedError:
449 449
                 hash_length *= 2
... ...
@@ -478,25 +478,25 @@ class Vault:
478 478
 
479 479
         """
480 480
         key = bytes(key)
481
-        TestFunc: TypeAlias = 'Callable[[bytes | bytearray], bool]'
481
+        TestFunc: TypeAlias = "Callable[[bytes | bytearray], bool]"
482 482
         deterministic_signature_types: dict[str, TestFunc]
483 483
         deterministic_signature_types = {
484
-            'ssh-ed25519': lambda k: k.startswith(
485
-                b'\x00\x00\x00\x0bssh-ed25519'
484
+            "ssh-ed25519": lambda k: k.startswith(
485
+                b"\x00\x00\x00\x0bssh-ed25519"
486 486
             ),
487
-            'ssh-ed448': lambda k: k.startswith(b'\x00\x00\x00\x09ssh-ed448'),
488
-            'ssh-rsa': lambda k: k.startswith(b'\x00\x00\x00\x07ssh-rsa'),
487
+            "ssh-ed448": lambda k: k.startswith(b"\x00\x00\x00\x09ssh-ed448"),
488
+            "ssh-rsa": lambda k: k.startswith(b"\x00\x00\x00\x07ssh-rsa"),
489 489
         }
490 490
         dsa_signature_types = {
491
-            'ssh-dss': lambda k: k.startswith(b'\x00\x00\x00\x07ssh-dss'),
492
-            'ecdsa-sha2-nistp256': lambda k: k.startswith(
493
-                b'\x00\x00\x00\x13ecdsa-sha2-nistp256'
491
+            "ssh-dss": lambda k: k.startswith(b"\x00\x00\x00\x07ssh-dss"),
492
+            "ecdsa-sha2-nistp256": lambda k: k.startswith(
493
+                b"\x00\x00\x00\x13ecdsa-sha2-nistp256"
494 494
             ),
495
-            'ecdsa-sha2-nistp384': lambda k: k.startswith(
496
-                b'\x00\x00\x00\x13ecdsa-sha2-nistp384'
495
+            "ecdsa-sha2-nistp384": lambda k: k.startswith(
496
+                b"\x00\x00\x00\x13ecdsa-sha2-nistp384"
497 497
             ),
498
-            'ecdsa-sha2-nistp521': lambda k: k.startswith(
499
-                b'\x00\x00\x00\x13ecdsa-sha2-nistp521'
498
+            "ecdsa-sha2-nistp521": lambda k: k.startswith(
499
+                b"\x00\x00\x00\x13ecdsa-sha2-nistp521"
500 500
             ),
501 501
         }
502 502
         criteria = [
... ...
@@ -595,8 +595,8 @@ class Vault:
595 595
         with ssh_agent.SSHAgentClient.ensure_agent_subcontext(conn) as client:
596 596
             if not cls.is_suitable_ssh_key(key, client=client):
597 597
                 msg = (
598
-                    'unsuitable SSH key: bad key, or '
599
-                    'signature not deterministic under this agent'
598
+                    "unsuitable SSH key: bad key, or "
599
+                    "signature not deterministic under this agent"
600 600
                 )
601 601
                 raise ValueError(msg)
602 602
             raw_sig = client.sign(key, cls.UUID)
... ...
@@ -679,7 +679,7 @@ class Vault:
679 679
                 key[i] = byte
680 680
             return bytes(key)
681 681
         except IndexError:
682
-            return h.digest() + b'\x00' * (h.block_size - h.digest_size)
682
+            return h.digest() + b"\x00" * (h.block_size - h.digest_size)
683 683
 
684 684
     @staticmethod
685 685
     def _subtract(
... ...
@@ -710,9 +710,9 @@ class Vault:
710 710
             allowed if isinstance(allowed, bytearray) else bytearray(allowed)
711 711
         )
712 712
         assert_type(allowed, bytearray)
713
-        charset = memoryview(charset).toreadonly().cast('c')
714
-        assert_type(charset, 'memoryview[bytes]')
715
-        msg_dup_characters = 'duplicate characters in set'
713
+        charset = memoryview(charset).toreadonly().cast("c")
714
+        assert_type(charset, "memoryview[bytes]")
715
+        msg_dup_characters = "duplicate characters in set"
716 716
         if len(frozenset(allowed)) != len(allowed):
717 717
             raise ValueError(msg_dup_characters)
718 718
         if len(frozenset(charset)) != len(charset):
... ...
@@ -197,251 +197,251 @@ class VaultTestConfig(NamedTuple):
197 197
 
198 198
 
199 199
 TEST_CONFIGS: list[VaultTestConfig] = [
200
-    VaultTestConfig(None, 'not a dict', None),
201
-    VaultTestConfig({}, 'missing required keys', None),
200
+    VaultTestConfig(None, "not a dict", None),
201
+    VaultTestConfig({}, "missing required keys", None),
202 202
     VaultTestConfig(
203
-        {'global': None, 'services': {}}, 'bad config value: global', None
203
+        {"global": None, "services": {}}, "bad config value: global", None
204 204
     ),
205 205
     VaultTestConfig(
206
-        {'global': {'key': 123}, 'services': {}},
207
-        'bad config value: global.key',
206
+        {"global": {"key": 123}, "services": {}},
207
+        "bad config value: global.key",
208 208
         None,
209 209
     ),
210 210
     VaultTestConfig(
211
-        {'global': {'phrase': 'abc', 'key': '...'}, 'services': {}},
212
-        '',
211
+        {"global": {"phrase": "abc", "key": "..."}, "services": {}},
212
+        "",
213 213
         None,
214 214
     ),
215
-    VaultTestConfig({'services': None}, 'bad config value: services', None),
215
+    VaultTestConfig({"services": None}, "bad config value: services", None),
216 216
     VaultTestConfig(
217
-        {'services': {'1': {}, 2: {}}}, 'bad config value: services."2"', None
217
+        {"services": {"1": {}, 2: {}}}, 'bad config value: services."2"', None
218 218
     ),
219 219
     VaultTestConfig(
220
-        {'services': {'1': {}, '2': 2}}, 'bad config value: services."2"', None
220
+        {"services": {"1": {}, "2": 2}}, 'bad config value: services."2"', None
221 221
     ),
222 222
     VaultTestConfig(
223
-        {'services': {'sv': {'notes': ['sentinel', 'list']}}},
224
-        'bad config value: services.sv.notes',
223
+        {"services": {"sv": {"notes": ["sentinel", "list"]}}},
224
+        "bad config value: services.sv.notes",
225 225
         None,
226 226
     ),
227 227
     VaultTestConfig(
228
-        {'services': {'sv': {'notes': 'blah blah blah'}}}, '', None
228
+        {"services": {"sv": {"notes": "blah blah blah"}}}, "", None
229 229
     ),
230 230
     VaultTestConfig(
231
-        {'services': {'sv': {'length': '200'}}},
232
-        'bad config value: services.sv.length',
231
+        {"services": {"sv": {"length": "200"}}},
232
+        "bad config value: services.sv.length",
233 233
         None,
234 234
     ),
235 235
     VaultTestConfig(
236
-        {'services': {'sv': {'length': 0.5}}},
237
-        'bad config value: services.sv.length',
236
+        {"services": {"sv": {"length": 0.5}}},
237
+        "bad config value: services.sv.length",
238 238
         None,
239 239
     ),
240 240
     VaultTestConfig(
241
-        {'services': {'sv': {'length': ['sentinel', 'list']}}},
242
-        'bad config value: services.sv.length',
241
+        {"services": {"sv": {"length": ["sentinel", "list"]}}},
242
+        "bad config value: services.sv.length",
243 243
         None,
244 244
     ),
245 245
     VaultTestConfig(
246
-        {'services': {'sv': {'length': -10}}},
247
-        'bad config value: services.sv.length',
246
+        {"services": {"sv": {"length": -10}}},
247
+        "bad config value: services.sv.length",
248 248
         None,
249 249
     ),
250 250
     VaultTestConfig(
251
-        {'services': {'sv': {'lower': '10'}}},
252
-        'bad config value: services.sv.lower',
251
+        {"services": {"sv": {"lower": "10"}}},
252
+        "bad config value: services.sv.lower",
253 253
         None,
254 254
     ),
255 255
     VaultTestConfig(
256
-        {'services': {'sv': {'upper': -10}}},
257
-        'bad config value: services.sv.upper',
256
+        {"services": {"sv": {"upper": -10}}},
257
+        "bad config value: services.sv.upper",
258 258
         None,
259 259
     ),
260 260
     VaultTestConfig(
261
-        {'services': {'sv': {'number': ['sentinel', 'list']}}},
262
-        'bad config value: services.sv.number',
261
+        {"services": {"sv": {"number": ["sentinel", "list"]}}},
262
+        "bad config value: services.sv.number",
263 263
         None,
264 264
     ),
265 265
     VaultTestConfig(
266 266
         {
267
-            'global': {'phrase': 'my secret phrase'},
268
-            'services': {'sv': {'length': 10}},
267
+            "global": {"phrase": "my secret phrase"},
268
+            "services": {"sv": {"length": 10}},
269 269
         },
270
-        '',
270
+        "",
271 271
         None,
272 272
     ),
273 273
     VaultTestConfig(
274
-        {'services': {'sv': {'length': 10, 'phrase': '...'}}}, '', None
274
+        {"services": {"sv": {"length": 10, "phrase": "..."}}}, "", None
275 275
     ),
276 276
     VaultTestConfig(
277
-        {'services': {'sv': {'length': 10, 'key': '...'}}}, '', None
277
+        {"services": {"sv": {"length": 10, "key": "..."}}}, "", None
278 278
     ),
279 279
     VaultTestConfig(
280
-        {'services': {'sv': {'upper': 10, 'key': '...'}}}, '', None
280
+        {"services": {"sv": {"upper": 10, "key": "..."}}}, "", None
281 281
     ),
282 282
     VaultTestConfig(
283
-        {'services': {'sv': {'phrase': 'abc', 'key': '...'}}}, '', None
283
+        {"services": {"sv": {"phrase": "abc", "key": "..."}}}, "", None
284 284
     ),
285 285
     VaultTestConfig(
286 286
         {
287
-            'global': {'phrase': 'abc'},
288
-            'services': {'sv': {'phrase': 'abc', 'length': 10}},
287
+            "global": {"phrase": "abc"},
288
+            "services": {"sv": {"phrase": "abc", "length": 10}},
289 289
         },
290
-        '',
290
+        "",
291 291
         None,
292 292
     ),
293 293
     VaultTestConfig(
294 294
         {
295
-            'global': {'key': '...'},
296
-            'services': {'sv': {'phrase': 'abc', 'length': 10}},
295
+            "global": {"key": "..."},
296
+            "services": {"sv": {"phrase": "abc", "length": 10}},
297 297
         },
298
-        '',
298
+        "",
299 299
         None,
300 300
     ),
301 301
     VaultTestConfig(
302 302
         {
303
-            'global': {'key': '...'},
304
-            'services': {'sv': {'phrase': 'abc', 'key': '...', 'length': 10}},
303
+            "global": {"key": "..."},
304
+            "services": {"sv": {"phrase": "abc", "key": "...", "length": 10}},
305 305
         },
306
-        '',
306
+        "",
307 307
         None,
308 308
     ),
309 309
     VaultTestConfig(
310 310
         {
311
-            'global': {'key': '...'},
312
-            'services': {
313
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
314
-                'sv2': {'length': 10, 'repeat': 1, 'lower': 1},
311
+            "global": {"key": "..."},
312
+            "services": {
313
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
314
+                "sv2": {"length": 10, "repeat": 1, "lower": 1},
315 315
             },
316 316
         },
317
-        '',
317
+        "",
318 318
         None,
319 319
     ),
320 320
     VaultTestConfig(
321 321
         {
322
-            'global': {'key': '...', 'unicode_normalization_form': 'NFC'},
323
-            'services': {
324
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
325
-                'sv2': {'length': 10, 'repeat': 1, 'lower': 1},
322
+            "global": {"key": "...", "unicode_normalization_form": "NFC"},
323
+            "services": {
324
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
325
+                "sv2": {"length": 10, "repeat": 1, "lower": 1},
326 326
             },
327 327
         },
328
-        '',
328
+        "",
329 329
         None,
330 330
     ),
331 331
     VaultTestConfig(
332 332
         {
333
-            'global': {'key': '...', 'unicode_normalization_form': True},
334
-            'services': {},
333
+            "global": {"key": "...", "unicode_normalization_form": True},
334
+            "services": {},
335 335
         },
336
-        'bad config value: global.unicode_normalization_form',
336
+        "bad config value: global.unicode_normalization_form",
337 337
         None,
338 338
     ),
339 339
     VaultTestConfig(
340 340
         {
341
-            'global': {'key': '...', 'unicode_normalization_form': 'NFC'},
342
-            'services': {
343
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
344
-                'sv2': {'length': 10, 'repeat': 1, 'lower': 1},
341
+            "global": {"key": "...", "unicode_normalization_form": "NFC"},
342
+            "services": {
343
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
344
+                "sv2": {"length": 10, "repeat": 1, "lower": 1},
345 345
             },
346 346
         },
347
-        '',
347
+        "",
348 348
         ValidationSettings(True),
349 349
     ),
350 350
     VaultTestConfig(
351 351
         {
352
-            'global': {'key': '...', 'unicode_normalization_form': 'NFC'},
353
-            'services': {
354
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
355
-                'sv2': {'length': 10, 'repeat': 1, 'lower': 1},
352
+            "global": {"key": "...", "unicode_normalization_form": "NFC"},
353
+            "services": {
354
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
355
+                "sv2": {"length": 10, "repeat": 1, "lower": 1},
356 356
             },
357 357
         },
358
-        'extension/unknown key: .global.unicode_normalization_form',
358
+        "extension/unknown key: .global.unicode_normalization_form",
359 359
         ValidationSettings(False),
360 360
     ),
361 361
     VaultTestConfig(
362 362
         {
363
-            'global': {'key': '...', 'unknown_key': True},
364
-            'services': {
365
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
366
-                'sv2': {'length': 10, 'repeat': 1, 'lower': 1},
363
+            "global": {"key": "...", "unknown_key": True},
364
+            "services": {
365
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
366
+                "sv2": {"length": 10, "repeat": 1, "lower": 1},
367 367
             },
368 368
         },
369
-        '',
369
+        "",
370 370
         ValidationSettings(True),
371 371
     ),
372 372
     VaultTestConfig(
373 373
         {
374
-            'global': {'key': '...', 'unknown_key': True},
375
-            'services': {
376
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
377
-                'sv2': {'length': 10, 'repeat': 1, 'lower': 1},
374
+            "global": {"key": "...", "unknown_key": True},
375
+            "services": {
376
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
377
+                "sv2": {"length": 10, "repeat": 1, "lower": 1},
378 378
             },
379 379
         },
380
-        'unknown key: .global.unknown_key',
380
+        "unknown key: .global.unknown_key",
381 381
         ValidationSettings(False),
382 382
     ),
383 383
     VaultTestConfig(
384 384
         {
385
-            'global': {'key': '...'},
386
-            'services': {
387
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
388
-                'sv2': {
389
-                    'length': 10,
390
-                    'repeat': 1,
391
-                    'lower': 1,
392
-                    'unknown_key': True,
385
+            "global": {"key": "..."},
386
+            "services": {
387
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
388
+                "sv2": {
389
+                    "length": 10,
390
+                    "repeat": 1,
391
+                    "lower": 1,
392
+                    "unknown_key": True,
393 393
                 },
394 394
             },
395 395
         },
396
-        'unknown key: .services.sv2.unknown_key',
396
+        "unknown key: .services.sv2.unknown_key",
397 397
         ValidationSettings(False),
398 398
     ),
399 399
     VaultTestConfig(
400 400
         {
401
-            'global': {'key': '...', 'unicode_normalization_form': 'NFC'},
402
-            'services': {
403
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
404
-                'sv2': {
405
-                    'length': 10,
406
-                    'repeat': 1,
407
-                    'lower': 1,
408
-                    'unknown_key': True,
401
+            "global": {"key": "...", "unicode_normalization_form": "NFC"},
402
+            "services": {
403
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
404
+                "sv2": {
405
+                    "length": 10,
406
+                    "repeat": 1,
407
+                    "lower": 1,
408
+                    "unknown_key": True,
409 409
                 },
410 410
             },
411 411
         },
412
-        '',
412
+        "",
413 413
         ValidationSettings(True),
414 414
     ),
415 415
     VaultTestConfig(
416 416
         {
417
-            'global': {'key': '...', 'unicode_normalization_form': 'NFC'},
418
-            'services': {
419
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
420
-                'sv2': {
421
-                    'length': 10,
422
-                    'repeat': 1,
423
-                    'lower': 1,
424
-                    'unknown_key': True,
417
+            "global": {"key": "...", "unicode_normalization_form": "NFC"},
418
+            "services": {
419
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
420
+                "sv2": {
421
+                    "length": 10,
422
+                    "repeat": 1,
423
+                    "lower": 1,
424
+                    "unknown_key": True,
425 425
                 },
426 426
             },
427 427
         },
428
-        '',
428
+        "",
429 429
         ValidationSettings(True),
430 430
     ),
431 431
     VaultTestConfig(
432 432
         {
433
-            'global': {'key': '...', 'unicode_normalization_form': 'NFC'},
434
-            'services': {
435
-                'sv1': {'phrase': 'abc', 'length': 10, 'upper': 1},
436
-                'sv2': {
437
-                    'length': 10,
438
-                    'repeat': 1,
439
-                    'lower': 1,
440
-                    'unknown_key': True,
433
+            "global": {"key": "...", "unicode_normalization_form": "NFC"},
434
+            "services": {
435
+                "sv1": {"phrase": "abc", "length": 10, "upper": 1},
436
+                "sv2": {
437
+                    "length": 10,
438
+                    "repeat": 1,
439
+                    "lower": 1,
440
+                    "unknown_key": True,
441 441
                 },
442 442
             },
443 443
         },
444
-        '',
444
+        "",
445 445
         ValidationSettings(True),
446 446
     ),
447 447
 ]
... ...
@@ -497,14 +497,14 @@ def vault_full_service_config(draw: strategies.DrawFn) -> dict[str, int]:
497 497
     hypothesis.assume(lower + upper + number + space + symbol > 0)
498 498
     hypothesis.assume(repeat >= space)
499 499
     return {
500
-        'lower': lower,
501
-        'upper': upper,
502
-        'number': number,
503
-        'space': space,
504
-        'dash': dash,
505
-        'symbol': symbol,
506
-        'repeat': repeat,
507
-        'length': length,
500
+        "lower": lower,
501
+        "upper": upper,
502
+        "number": number,
503
+        "space": space,
504
+        "dash": dash,
505
+        "symbol": symbol,
506
+        "repeat": repeat,
507
+        "length": length,
508 508
     }
509 509
 
510 510
 
... ...
@@ -525,10 +525,10 @@ def is_smudgable_vault_test_config(conf: VaultTestConfig) -> bool:
525 525
     config = conf.config
526 526
     return bool(
527 527
         isinstance(config, dict)
528
-        and ('global' not in config or isinstance(config['global'], dict))
529
-        and ('services' in config and isinstance(config['services'], dict))
530
-        and all(isinstance(x, dict) for x in config['services'].values())
531
-        and (config['services'] or config.get('global'))
528
+        and ("global" not in config or isinstance(config["global"], dict))
529
+        and ("services" in config and isinstance(config["services"], dict))
530
+        and all(isinstance(x, dict) for x in config["services"].values())
531
+        and (config["services"] or config.get("global"))
532 532
     )
533 533
 
534 534
 
... ...
@@ -557,40 +557,40 @@ def smudged_vault_test_config(
557 557
 
558 558
     """
559 559
 
560
-    falsy = (None, False, 0, 0.0, '', float('nan'))
561
-    falsy_no_str = (None, False, 0, 0.0, float('nan'))
562
-    falsy_no_zero = (None, False, '', float('nan'))
560
+    falsy = (None, False, 0, 0.0, "", float("nan"))
561
+    falsy_no_str = (None, False, 0, 0.0, float("nan"))
562
+    falsy_no_zero = (None, False, "", float("nan"))
563 563
     conf = draw(config)
564 564
     hypothesis.assume(is_smudgable_vault_test_config(conf))
565 565
     obj = copy.deepcopy(conf.config)
566
-    services: list[dict[str, Any]] = list(obj['services'].values())
567
-    if 'global' in obj:
568
-        services.append(obj['global'])
566
+    services: list[dict[str, Any]] = list(obj["services"].values())
567
+    if "global" in obj:
568
+        services.append(obj["global"])
569 569
     assert all(isinstance(x, dict) for x in services), (
570
-        'is_smudgable_vault_test_config guard failed to '
571
-        'ensure each settings dict is a dict'
570
+        "is_smudgable_vault_test_config guard failed to "
571
+        "ensure each settings dict is a dict"
572 572
     )
573 573
     for service in services:
574
-        for key in ('phrase',):
574
+        for key in ("phrase",):
575 575
             value = service.get(key)
576
-            if not _types.js_truthiness(value) and value != '':
576
+            if not _types.js_truthiness(value) and value != "":
577 577
                 service[key] = draw(strategies.sampled_from(falsy_no_str))
578 578
         for key in (
579
-            'notes',
580
-            'key',
581
-            'length',
582
-            'repeat',
579
+            "notes",
580
+            "key",
581
+            "length",
582
+            "repeat",
583 583
         ):
584 584
             value = service.get(key)
585 585
             if not _types.js_truthiness(value):
586 586
                 service[key] = draw(strategies.sampled_from(falsy))
587 587
         for key in (
588
-            'lower',
589
-            'upper',
590
-            'number',
591
-            'space',
592
-            'dash',
593
-            'symbol',
588
+            "lower",
589
+            "upper",
590
+            "number",
591
+            "space",
592
+            "dash",
593
+            "symbol",
594 594
         ):
595 595
             value = service.get(key)
596 596
             if not _types.js_truthiness(value) and value != 0:
... ...
@@ -615,13 +615,13 @@ class KnownSSHAgent(str, enum.Enum):
615 615
 
616 616
     """
617 617
 
618
-    UNKNOWN = '(unknown)'
618
+    UNKNOWN = "(unknown)"
619 619
     """"""
620
-    Pageant = 'Pageant'
620
+    Pageant = "Pageant"
621 621
     """"""
622
-    OpenSSHAgent = 'OpenSSHAgent'
622
+    OpenSSHAgent = "OpenSSHAgent"
623 623
     """"""
624
-    StubbedSSHAgent = 'StubbedSSHAgent'
624
+    StubbedSSHAgent = "StubbedSSHAgent"
625 625
     """"""
626 626
 
627 627
 
... ...
@@ -678,14 +678,14 @@ class RunningSSHAgentInfo(NamedTuple):
678 678
     def require_external_address(self) -> str:  # pragma: no cover
679 679
         if not isinstance(self.socket, str):
680 680
             pytest.skip(
681
-                reason='This test requires a real, externally resolvable '
682
-                'address for the SSH agent socket.'
681
+                reason="This test requires a real, externally resolvable "
682
+                "address for the SSH agent socket."
683 683
             )
684 684
         return self.socket
685 685
 
686 686
 
687 687
 ALL_KEYS: Mapping[str, SSHTestKey] = {
688
-    'ed25519': SSHTestKey(
688
+    "ed25519": SSHTestKey(
689 689
         private_key=rb"""-----BEGIN OPENSSH PRIVATE KEY-----
690 690
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
691 691
 QyNTUxOQAAACCBeIFoJtYCSF8P/zJIb+TBMIncHGpFBgnpCQ/7whJpdgAAAKDweO7H8Hju
... ...
@@ -731,7 +731,7 @@ idwcakUGCekJD/vCEml2AAAAG3Rlc3Qga2V5IHdpdGhvdXQgcGFzc3BocmFzZQEC
731 731
     ),
732 732
     # Currently only supported by PuTTY (which is deficient in other
733 733
     # niceties of the SSH agent and the agent's client).
734
-    'ed448': SSHTestKey(
734
+    "ed448": SSHTestKey(
735 735
         private_key=rb"""-----BEGIN OPENSSH PRIVATE KEY-----
736 736
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
737 737
 c2gtZWQ0NDgAAAA54vZy009Wu8wExjvEb3hqtLz1GO/+d5vmGUbErWQ4AUO9mYLT
... ...
@@ -786,7 +786,7 @@ dGhvdXQgcGFzc3BocmFzZQECAwQFBgcICQ==
786 786
             ),
787 787
         },
788 788
     ),
789
-    'rsa': SSHTestKey(
789
+    "rsa": SSHTestKey(
790 790
         private_key=rb"""-----BEGIN OPENSSH PRIVATE KEY-----
791 791
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
792 792
 NhAAAAAwEAAQAAAYEAsaHu6Xs4cVsuDSNJlMCqoPVgmDgEviI8TfXmHKqX3JkIqI3LsvV7
... ...
@@ -986,7 +986,7 @@ Bgp6142WnSCQAAABt0ZXN0IGtleSB3aXRob3V0IHBhc3NwaHJhc2UB
986 986
             ),
987 987
         },
988 988
     ),
989
-    'dsa1024': SSHTestKey(
989
+    "dsa1024": SSHTestKey(
990 990
         private_key=rb"""-----BEGIN OPENSSH PRIVATE KEY-----
991 991
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH
992 992
 NzAAAAgQC7KAZXqBGNVLBQPrcMYAoNW54BhD8aIhe7BDWYzJcsaMt72VKSkguZ8+XR7nRa
... ...
@@ -1102,7 +1102,7 @@ u7HfrQhdOiKSa+ZO9AAojbURqrLDRfBJa5dXn2AAAAFQDJHfenj4EJ9WkehpdJatPBlqCW
1102 1102
             ),
1103 1103
         },
1104 1104
     ),
1105
-    'ecdsa256': SSHTestKey(
1105
+    "ecdsa256": SSHTestKey(
1106 1106
         private_key=rb"""-----BEGIN OPENSSH PRIVATE KEY-----
1107 1107
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1108 1108
 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTLbU0zDwsk2Dvp+VYIrsNVf5gWwz2S
... ...
@@ -1173,7 +1173,7 @@ dGhvdXQgcGFzc3BocmFzZQECAwQ=
1173 1173
             ),
1174 1174
         },
1175 1175
     ),
1176
-    'ecdsa384': SSHTestKey(
1176
+    "ecdsa384": SSHTestKey(
1177 1177
         private_key=rb"""-----BEGIN OPENSSH PRIVATE KEY-----
1178 1178
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
1179 1179
 1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQSgkOjkAvq7v5vHuj3KBL4/EAWcn5hZ
... ...
@@ -1254,7 +1254,7 @@ JAu0J3Q+cypZuKQVAAAAMQD5sTy8p+B1cn/DhOmXquui1BcxvASqzzevkBlbQoBa73y04B
1254 1254
             ),
1255 1255
         },
1256