Marco Ricci commited on 2025-01-23 10:53:54
Zeige 7 geänderte Dateien mit 56 Einfügungen und 19 Löschungen.
This includes a short instruction and a link to the upgrade notes or Python compatibility section related to this code section.
... | ... |
@@ -291,7 +291,9 @@ class _VaultConfigValidator: |
291 | 291 |
kwargs['key'] = key |
292 | 292 |
kwargs['value'] = value |
293 | 293 |
kwargs['json_path_str'] = json_path([*path, key]) |
294 |
- # Use match/case here once Python 3.9 becomes unsupported. |
|
294 |
+ # TODO(the-13th-letter): Rewrite using structural pattern |
|
295 |
+ # matching. |
|
296 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
295 | 297 |
if key in {'key', 'phrase'}: |
296 | 298 |
if not isinstance(value, str): |
297 | 299 |
raise TypeError(err_not_a_string.format(**kwargs)) |
... | ... |
@@ -353,7 +355,9 @@ class _VaultConfigValidator: |
353 | 355 |
|
354 | 356 |
for path, key, value in self.walk_subconfigs(): |
355 | 357 |
service_obj = self.traverse_path(path) |
356 |
- # Use match/case here once Python 3.9 becomes unsupported. |
|
358 |
+ # TODO(the-13th-letter): Rewrite using structural pattern |
|
359 |
+ # matching. |
|
360 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
357 | 361 |
if key == 'phrase' and falsy_but_not_string(value): |
358 | 362 |
yield CleanupStep( |
359 | 363 |
(*path, key), service_obj[key], 'replace', '' |
... | ... |
@@ -454,6 +458,8 @@ def validate_vault_config( |
454 | 458 |
specified `derivepassphrase` extensions. |
455 | 459 |
|
456 | 460 |
""" |
461 |
+ # TODO(the-13th-letter): Remove this block in v1.0. |
|
462 |
+ # https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#v1.0-allow-derivepassphrase-extensions |
|
457 | 463 |
# TODO(the-13th-letter): Add tests that trigger the deprecation warning, |
458 | 464 |
# then include this in coverage. |
459 | 465 |
if not isinstance( |
... | ... |
@@ -593,6 +599,8 @@ def clean_up_falsy_vault_config_values( |
593 | 599 |
return None |
594 | 600 |
|
595 | 601 |
|
602 |
+# TODO(the-13th-letter): Use type variables local to each class. |
|
603 |
+# https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.11 |
|
596 | 604 |
T_Buffer = TypeVar('T_Buffer', bound=Buffer) |
597 | 605 |
""" |
598 | 606 |
A [`TypeVar`][] for classes implementing the [`Buffer`][] interface. |
... | ... |
@@ -1111,6 +1111,9 @@ if ( |
1111 | 1111 |
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
1112 | 1112 |
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
1113 | 1113 |
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
1114 |
+# |
|
1115 |
+# TODO(the-13th-letter): Remove this class and license block in v1.0. |
|
1116 |
+# https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#v1.0-implied-subcommands |
|
1114 | 1117 |
class _DefaultToVaultGroup(CommandWithHelpGroups, click.Group): |
1115 | 1118 |
"""A helper class to implement the default-to-"vault"-subcommand behavior. |
1116 | 1119 |
|
... | ... |
@@ -1166,6 +1169,9 @@ class _DefaultToVaultGroup(CommandWithHelpGroups, click.Group): |
1166 | 1169 |
return cmd_name if cmd else None, cmd, args[1:] |
1167 | 1170 |
|
1168 | 1171 |
|
1172 |
+# TODO(the-13th-letter): Base this class on CommandWithHelpGroups and |
|
1173 |
+# click.Group in v1.0. |
|
1174 |
+# https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#v1.0-implied-subcommands |
|
1169 | 1175 |
class _TopLevelCLIEntryPoint(_DefaultToVaultGroup): |
1170 | 1176 |
"""A minor variation of _DefaultToVaultGroup for the top-level command. |
1171 | 1177 |
|
... | ... |
@@ -1227,6 +1233,8 @@ def derivepassphrase(ctx: click.Context, /) -> None: |
1227 | 1233 |
[CLICK]: https://pypi.org/package/click/ |
1228 | 1234 |
|
1229 | 1235 |
""" |
1236 |
+ # TODO(the-13th-letter): Turn this callback into a no-op in v1.0. |
|
1237 |
+ # https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#v1.0-implied-subcommands |
|
1230 | 1238 |
deprecation = logging.getLogger(f'{PROG_NAME}.deprecation') |
1231 | 1239 |
if ctx.invoked_subcommand is None: |
1232 | 1240 |
deprecation.warning( |
... | ... |
@@ -1280,6 +1288,8 @@ def derivepassphrase_export(ctx: click.Context, /) -> None: |
1280 | 1288 |
[CLICK]: https://pypi.org/package/click/ |
1281 | 1289 |
|
1282 | 1290 |
""" |
1291 |
+ # TODO(the-13th-letter): Turn this callback into a no-op in v1.0. |
|
1292 |
+ # https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#v1.0-implied-subcommands |
|
1283 | 1293 |
deprecation = logging.getLogger(f'{PROG_NAME}.deprecation') |
1284 | 1294 |
if ctx.invoked_subcommand is None: |
1285 | 1295 |
deprecation.warning( |
... | ... |
@@ -1465,6 +1475,8 @@ _config_filename_table = { |
1465 | 1475 |
None: '.', |
1466 | 1476 |
'vault': 'vault.json', |
1467 | 1477 |
'user configuration': 'config.toml', |
1478 |
+ # TODO(the-13th-letter): Remove the old settings.json file. |
|
1479 |
+ # https://the13thletter.info/derivepassphrase/latest/upgrade-notes.html#v1.0-old-settings-file |
|
1468 | 1480 |
'old settings.json': 'settings.json', |
1469 | 1481 |
} |
1470 | 1482 |
|
... | ... |
@@ -1535,6 +1547,8 @@ def _load_config() -> _types.VaultConfig: |
1535 | 1547 |
return data |
1536 | 1548 |
|
1537 | 1549 |
|
1550 |
+# TODO(the-13th-letter): Remove this function. |
|
1551 |
+# https://the13thletter.info/derivepassphrase/latest/upgrade-notes.html#v1.0-old-settings-file |
|
1538 | 1552 |
def _migrate_and_load_old_config() -> tuple[ |
1539 | 1553 |
_types.VaultConfig, OSError | None |
1540 | 1554 |
]: |
... | ... |
@@ -44,7 +44,8 @@ class SSHAgentFailedError(RuntimeError): |
44 | 44 |
"""The SSH agent failed to complete the requested operation.""" |
45 | 45 |
|
46 | 46 |
def __str__(self) -> str: |
47 |
- # Use match/case here once Python 3.9 becomes unsupported. |
|
47 |
+ # TODO(the-13th-letter): Rewrite using structural pattern matching. |
|
48 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
48 | 49 |
if self.args == ( # pragma: no branch |
49 | 50 |
_types.SSH_AGENT.FAILURE.value, |
50 | 51 |
b'', |
... | ... |
@@ -327,7 +328,8 @@ class SSHAgentClient: |
327 | 328 |
setting up a socket connection to the agent. |
328 | 329 |
|
329 | 330 |
""" # noqa: DOC501 |
330 |
- # Use match/case here once Python 3.9 becomes unsupported. |
|
331 |
+ # TODO(the-13th-letter): Rewrite using structural pattern matching. |
|
332 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
331 | 333 |
if isinstance(conn, SSHAgentClient): |
332 | 334 |
with contextlib.nullcontext(): |
333 | 335 |
yield conn |
... | ... |
@@ -1433,8 +1433,8 @@ def isolated_config( |
1433 | 1433 |
) -> Iterator[None]: |
1434 | 1434 |
prog_name = cli.PROG_NAME |
1435 | 1435 |
env_name = prog_name.replace(' ', '_').upper() + '_PATH' |
1436 |
- # Use parenthesized context manager expressions once Python 3.9 |
|
1437 |
- # becomes unsupported. |
|
1436 |
+ # TODO(the-13th-letter): Rewrite using parenthesized with-statements. |
|
1437 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
1438 | 1438 |
with contextlib.ExitStack() as stack: |
1439 | 1439 |
stack.enter_context(runner.isolated_filesystem()) |
1440 | 1440 |
stack.enter_context(cli.StandardCLILogging.ensure_standard_logging()) |
... | ... |
@@ -1477,6 +1477,8 @@ def isolated_vault_exporter_config( |
1477 | 1477 |
vault_config: str | bytes | None = None, |
1478 | 1478 |
vault_key: str | None = None, |
1479 | 1479 |
) -> Iterator[None]: |
1480 |
+ # TODO(the-13th-letter): Remove the fallback implementation. |
|
1481 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.10 |
|
1480 | 1482 |
if TYPE_CHECKING: |
1481 | 1483 |
chdir: Callable[..., AbstractContextManager] |
1482 | 1484 |
else: |
... | ... |
@@ -1505,13 +1507,15 @@ def isolated_vault_exporter_config( |
1505 | 1507 |
if vault_key is not None: |
1506 | 1508 |
monkeypatch.setenv('VAULT_KEY', vault_key) |
1507 | 1509 |
vault_config_path = pathlib.Path('.vault').resolve() |
1508 |
- # Use match/case here once Python 3.9 becomes unsupported. |
|
1510 |
+ # TODO(the-13th-letter): Rewrite using structural pattern matching. |
|
1511 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
1509 | 1512 |
if isinstance(vault_config, str): |
1510 | 1513 |
vault_config_path.write_text(f'{vault_config}\n', encoding='UTF-8') |
1511 | 1514 |
elif isinstance(vault_config, bytes): |
1512 | 1515 |
vault_config_path.mkdir(parents=True, mode=0o700, exist_ok=True) |
1513 |
- # Use parenthesized context manager expressions here once |
|
1514 |
- # Python 3.9 becomes unsupported. |
|
1516 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
1517 |
+ # with-statements. |
|
1518 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
1515 | 1519 |
with contextlib.ExitStack() as stack: |
1516 | 1520 |
stack.enter_context(chdir(vault_config_path)) |
1517 | 1521 |
tmpzipfile = stack.enter_context( |
... | ... |
@@ -1647,7 +1651,8 @@ class ReadableResult(NamedTuple): |
1647 | 1651 |
else error.match(line) is not None |
1648 | 1652 |
) |
1649 | 1653 |
|
1650 |
- # Use match/case here once Python 3.9 becomes unsupported. |
|
1654 |
+ # TODO(the-13th-letter): Rewrite using structural pattern matching. |
|
1655 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
1651 | 1656 |
if isinstance(error, type): |
1652 | 1657 |
return isinstance(self.exception, error) |
1653 | 1658 |
else: # noqa: RET505 |
... | ... |
@@ -2086,8 +2086,9 @@ class TestCLIUtils: |
2086 | 2086 |
self, monkeypatch: pytest.MonkeyPatch |
2087 | 2087 |
) -> None: |
2088 | 2088 |
runner = click.testing.CliRunner() |
2089 |
- # Use parenthesized context manager expressions here once Python |
|
2090 |
- # 3.9 becomes unsupported. |
|
2089 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
2090 |
+ # with-statements. |
|
2091 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
2091 | 2092 |
with contextlib.ExitStack() as stack: |
2092 | 2093 |
stack.enter_context( |
2093 | 2094 |
tests.isolated_vault_config( |
... | ... |
@@ -2632,7 +2633,9 @@ Boo. |
2632 | 2633 |
ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys |
2633 | 2634 |
) |
2634 | 2635 |
hint: ssh_agent.SSHAgentClient | socket.socket | None |
2635 |
- # Use match/case here once Python 3.9 becomes unsupported. |
|
2636 |
+ # TODO(the-13th-letter): Rewrite using structural pattern |
|
2637 |
+ # matching. |
|
2638 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
2636 | 2639 |
if conn_hint == 'client': |
2637 | 2640 |
hint = ssh_agent.SSHAgentClient() |
2638 | 2641 |
elif conn_hint == 'socket': |
... | ... |
@@ -2737,6 +2740,8 @@ Boo. |
2737 | 2740 |
cli._key_to_phrase(loaded_key, error_callback=err) |
2738 | 2741 |
|
2739 | 2742 |
|
2743 |
+# TODO(the-13th-letter): Remove this class in v1.0. |
|
2744 |
+# https://the13thletter.info/derivepassphrase/latest/upgrade-notes/#upgrading-to-v1.0 |
|
2740 | 2745 |
class TestCLITransition: |
2741 | 2746 |
def test_100_help_output(self, monkeypatch: pytest.MonkeyPatch) -> None: |
2742 | 2747 |
runner = click.testing.CliRunner(mix_stderr=False) |
... | ... |
@@ -404,8 +404,9 @@ class TestStoreroom: |
404 | 404 |
handler: exporter.ExportVaultConfigDataFunction, |
405 | 405 |
) -> None: |
406 | 406 |
runner = click.testing.CliRunner(mix_stderr=False) |
407 |
- # Use parenthesized context manager expressions once Python 3.9 |
|
408 |
- # becomes unsupported. |
|
407 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
408 |
+ # with-statements. |
|
409 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
409 | 410 |
with contextlib.ExitStack() as stack: |
410 | 411 |
stack.enter_context( |
411 | 412 |
tests.isolated_vault_exporter_config( |
... | ... |
@@ -590,8 +590,9 @@ class TestAgentInteraction: |
590 | 590 |
) -> None: |
591 | 591 |
del running_ssh_agent |
592 | 592 |
|
593 |
- # Use parenthesized context manager expressions once Python 3.9 |
|
594 |
- # becomes unsupported. |
|
593 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
594 |
+ # with-statements. |
|
595 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
595 | 596 |
with contextlib.ExitStack() as stack: |
596 | 597 |
stack.enter_context(pytest.raises(exc_type, match=exc_pattern)) |
597 | 598 |
client = stack.enter_context(ssh_agent.SSHAgentClient()) |
... | ... |
@@ -652,8 +653,9 @@ class TestAgentInteraction: |
652 | 653 |
assert single_code in response_codes |
653 | 654 |
return response_data # pragma: no cover |
654 | 655 |
|
655 |
- # Use parenthesized context manager expressions once Python 3.9 |
|
656 |
- # becomes unsupported. |
|
656 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
657 |
+ # with-statements. |
|
658 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
657 | 659 |
with contextlib.ExitStack() as stack: |
658 | 660 |
monkeypatch2 = stack.enter_context(monkeypatch.context()) |
659 | 661 |
client = stack.enter_context(ssh_agent.SSHAgentClient()) |
660 | 662 |