Marco Ricci commited on 2025-01-25 22:15:53
              Zeige 4 geänderte Dateien mit 999 Einfügungen und 360 Löschungen.
            
The `pytest.MonkeyPatch.context` context manager is just as easy to use, and does not interfere with hypothesis.
| ... | ... | 
                      @@ -348,17 +348,23 @@ class TestAllCLI:  | 
                  
| 348 | 348 | 
                        )  | 
                    
| 349 | 349 | 
                        def test_200_eager_options(  | 
                    
| 350 | 350 | 
                        self,  | 
                    
| 351 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 352 | 351 | 
                        command: list[str],  | 
                    
| 353 | 352 | 
                        arguments: list[str],  | 
                    
| 354 | 353 | 
                        non_eager_arguments: list[str],  | 
                    
| 355 | 354 | 
                        ) -> None:  | 
                    
| 356 | 355 | 
                        """Eager options terminate option and argument processing."""  | 
                    
| 357 | 356 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 358 | 
                        - with tests.isolated_config(  | 
                    |
| 357 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 358 | 
                        + # with-statements.  | 
                    |
| 359 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 360 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 361 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 362 | 
                        + stack.enter_context(  | 
                    |
| 363 | 
                        + tests.isolated_config(  | 
                    |
| 359 | 364 | 
                        monkeypatch=monkeypatch,  | 
                    
| 360 | 365 | 
                        runner=runner,  | 
                    
| 361 | 
                        - ):  | 
                    |
| 366 | 
                        + )  | 
                    |
| 367 | 
                        + )  | 
                    |
| 362 | 368 | 
                        result_ = runner.invoke(  | 
                    
| 363 | 369 | 
                        cli.derivepassphrase,  | 
                    
| 364 | 370 | 
                        [*command, *arguments, *non_eager_arguments],  | 
                    
| ... | ... | 
                      @@ -394,7 +400,6 @@ class TestAllCLI:  | 
                  
| 394 | 400 | 
                        )  | 
                    
| 395 | 401 | 
                        def test_201_no_color_force_color(  | 
                    
| 396 | 402 | 
                        self,  | 
                    
| 397 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 398 | 403 | 
                        no_color: bool,  | 
                    
| 399 | 404 | 
                        force_color: bool,  | 
                    
| 400 | 405 | 
                        isatty: bool,  | 
                    
| ... | ... | 
                      @@ -406,10 +411,17 @@ class TestAllCLI:  | 
                  
| 406 | 411 | 
                        # no_color. Otherwise set color if and only if we have a TTY.  | 
                    
| 407 | 412 | 
                        color = force_color or not no_color if isatty else force_color  | 
                    
| 408 | 413 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 409 | 
                        - with tests.isolated_config(  | 
                    |
| 414 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 415 | 
                        + # with-statements.  | 
                    |
| 416 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 417 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 418 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 419 | 
                        + stack.enter_context(  | 
                    |
| 420 | 
                        + tests.isolated_config(  | 
                    |
| 410 | 421 | 
                        monkeypatch=monkeypatch,  | 
                    
| 411 | 422 | 
                        runner=runner,  | 
                    
| 412 | 
                        - ):  | 
                    |
| 423 | 
                        + )  | 
                    |
| 424 | 
                        + )  | 
                    |
| 413 | 425 | 
                        if no_color:  | 
                    
| 414 | 426 | 
                                         monkeypatch.setenv('NO_COLOR', 'yes')
                       | 
                    
| 415 | 427 | 
                        if force_color:  | 
                    
| ... | ... | 
                      @@ -437,14 +449,20 @@ class TestCLI:  | 
                  
| 437 | 449 | 
                         | 
                    
| 438 | 450 | 
                        def test_200_help_output(  | 
                    
| 439 | 451 | 
                        self,  | 
                    
| 440 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 441 | 452 | 
                        ) -> None:  | 
                    
| 442 | 453 | 
                        """The `--help` option emits help text."""  | 
                    
| 443 | 454 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 444 | 
                        - with tests.isolated_config(  | 
                    |
| 455 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 456 | 
                        + # with-statements.  | 
                    |
| 457 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 458 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 459 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 460 | 
                        + stack.enter_context(  | 
                    |
| 461 | 
                        + tests.isolated_config(  | 
                    |
| 445 | 462 | 
                        monkeypatch=monkeypatch,  | 
                    
| 446 | 463 | 
                        runner=runner,  | 
                    
| 447 | 
                        - ):  | 
                    |
| 464 | 
                        + )  | 
                    |
| 465 | 
                        + )  | 
                    |
| 448 | 466 | 
                        result_ = runner.invoke(  | 
                    
| 449 | 467 | 
                        cli.derivepassphrase_vault,  | 
                    
| 450 | 468 | 
                        ['--help'],  | 
                    
| ... | ... | 
                      @@ -460,14 +478,20 @@ class TestCLI:  | 
                  
| 460 | 478 | 
                         | 
                    
| 461 | 479 | 
                        def test_200a_version_output(  | 
                    
| 462 | 480 | 
                        self,  | 
                    
| 463 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 464 | 481 | 
                        ) -> None:  | 
                    
| 465 | 482 | 
                        """The `--version` option emits version information."""  | 
                    
| 466 | 483 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 467 | 
                        - with tests.isolated_config(  | 
                    |
| 484 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 485 | 
                        + # with-statements.  | 
                    |
| 486 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 487 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 488 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 489 | 
                        + stack.enter_context(  | 
                    |
| 490 | 
                        + tests.isolated_config(  | 
                    |
| 468 | 491 | 
                        monkeypatch=monkeypatch,  | 
                    
| 469 | 492 | 
                        runner=runner,  | 
                    
| 470 | 
                        - ):  | 
                    |
| 493 | 
                        + )  | 
                    |
| 494 | 
                        + )  | 
                    |
| 471 | 495 | 
                        result_ = runner.invoke(  | 
                    
| 472 | 496 | 
                        cli.derivepassphrase_vault,  | 
                    
| 473 | 497 | 
                        ['--version'],  | 
                    
| ... | ... | 
                      @@ -485,17 +509,27 @@ class TestCLI:  | 
                  
| 485 | 509 | 
                        'charset_name', ['lower', 'upper', 'number', 'space', 'dash', 'symbol']  | 
                    
| 486 | 510 | 
                        )  | 
                    
| 487 | 511 | 
                        def test_201_disable_character_set(  | 
                    
| 488 | 
                        - self, monkeypatch: pytest.MonkeyPatch, charset_name: str  | 
                    |
| 512 | 
                        + self,  | 
                    |
| 513 | 
                        + charset_name: str,  | 
                    |
| 489 | 514 | 
                        ) -> None:  | 
                    
| 490 | 515 | 
                        """Named character classes can be disabled on the command-line."""  | 
                    
| 491 | 
                        - monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)  | 
                    |
| 492 | 516 | 
                                 option = f'--{charset_name}'
                       | 
                    
| 493 | 517 | 
                                 charset = vault.Vault._CHARSETS[charset_name].decode('ascii')
                       | 
                    
| 494 | 518 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 495 | 
                        - with tests.isolated_config(  | 
                    |
| 519 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 520 | 
                        + # with-statements.  | 
                    |
| 521 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 522 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 523 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 524 | 
                        + stack.enter_context(  | 
                    |
| 525 | 
                        + tests.isolated_config(  | 
                    |
| 496 | 526 | 
                        monkeypatch=monkeypatch,  | 
                    
| 497 | 527 | 
                        runner=runner,  | 
                    
| 498 | 
                        - ):  | 
                    |
| 528 | 
                        + )  | 
                    |
| 529 | 
                        + )  | 
                    |
| 530 | 
                        + monkeypatch.setattr(  | 
                    |
| 531 | 
                        + cli, '_prompt_for_passphrase', tests.auto_prompt  | 
                    |
| 532 | 
                        + )  | 
                    |
| 499 | 533 | 
                        result_ = runner.invoke(  | 
                    
| 500 | 534 | 
                        cli.derivepassphrase_vault,  | 
                    
| 501 | 535 | 
                        [option, '0', '-p', '--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -510,15 +544,24 @@ class TestCLI:  | 
                  
| 510 | 544 | 
                        )  | 
                    
| 511 | 545 | 
                         | 
                    
| 512 | 546 | 
                        def test_202_disable_repetition(  | 
                    
| 513 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 547 | 
                        + self,  | 
                    |
| 514 | 548 | 
                        ) -> None:  | 
                    
| 515 | 549 | 
                        """Character repetition can be disabled on the command-line."""  | 
                    
| 516 | 
                        - monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)  | 
                    |
| 517 | 550 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 518 | 
                        - with tests.isolated_config(  | 
                    |
| 551 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 552 | 
                        + # with-statements.  | 
                    |
| 553 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 554 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 555 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 556 | 
                        + stack.enter_context(  | 
                    |
| 557 | 
                        + tests.isolated_config(  | 
                    |
| 519 | 558 | 
                        monkeypatch=monkeypatch,  | 
                    
| 520 | 559 | 
                        runner=runner,  | 
                    
| 521 | 
                        - ):  | 
                    |
| 560 | 
                        + )  | 
                    |
| 561 | 
                        + )  | 
                    |
| 562 | 
                        + monkeypatch.setattr(  | 
                    |
| 563 | 
                        + cli, '_prompt_for_passphrase', tests.auto_prompt  | 
                    |
| 564 | 
                        + )  | 
                    |
| 522 | 565 | 
                        result_ = runner.invoke(  | 
                    
| 523 | 566 | 
                        cli.derivepassphrase_vault,  | 
                    
| 524 | 567 | 
                        ['--repeat', '0', '-p', '--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -562,14 +605,22 @@ class TestCLI:  | 
                  
| 562 | 605 | 
                        )  | 
                    
| 563 | 606 | 
                        def test_204a_key_from_config(  | 
                    
| 564 | 607 | 
                        self,  | 
                    
| 565 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 566 | 608 | 
                        config: _types.VaultConfig,  | 
                    
| 567 | 609 | 
                        ) -> None:  | 
                    
| 568 | 610 | 
                        """A stored configured SSH key will be used."""  | 
                    
| 569 | 611 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 570 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 571 | 
                        - monkeypatch=monkeypatch, runner=runner, vault_config=config  | 
                    |
| 572 | 
                        - ):  | 
                    |
| 612 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 613 | 
                        + # with-statements.  | 
                    |
| 614 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 615 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 616 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 617 | 
                        + stack.enter_context(  | 
                    |
| 618 | 
                        + tests.isolated_vault_config(  | 
                    |
| 619 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 620 | 
                        + runner=runner,  | 
                    |
| 621 | 
                        + vault_config=config,  | 
                    |
| 622 | 
                        + )  | 
                    |
| 623 | 
                        + )  | 
                    |
| 573 | 624 | 
                        monkeypatch.setattr(  | 
                    
| 574 | 625 | 
                        vault.Vault, 'phrase_from_key', tests.phrase_from_key  | 
                    
| 575 | 626 | 
                        )  | 
                    
| ... | ... | 
                      @@ -591,15 +642,24 @@ class TestCLI:  | 
                  
| 591 | 642 | 
                        )  | 
                    
| 592 | 643 | 
                         | 
                    
| 593 | 644 | 
                        def test_204b_key_from_command_line(  | 
                    
| 594 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 645 | 
                        + self,  | 
                    |
| 595 | 646 | 
                        ) -> None:  | 
                    
| 596 | 647 | 
                        """An SSH key requested on the command-line will be used."""  | 
                    
| 597 | 648 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 598 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 649 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 650 | 
                        + # with-statements.  | 
                    |
| 651 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 652 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 653 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 654 | 
                        + stack.enter_context(  | 
                    |
| 655 | 
                        + tests.isolated_vault_config(  | 
                    |
| 599 | 656 | 
                        monkeypatch=monkeypatch,  | 
                    
| 600 | 657 | 
                        runner=runner,  | 
                    
| 601 | 
                        -            vault_config={'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}},
                       | 
                    |
| 602 | 
                        - ):  | 
                    |
| 658 | 
                        +                    vault_config={
                       | 
                    |
| 659 | 
                        +                        'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}
                       | 
                    |
| 660 | 
                        + },  | 
                    |
| 661 | 
                        + )  | 
                    |
| 662 | 
                        + )  | 
                    |
| 603 | 663 | 
                        monkeypatch.setattr(  | 
                    
| 604 | 664 | 
                        cli, '_get_suitable_ssh_keys', tests.suitable_ssh_keys  | 
                    
| 605 | 665 | 
                        )  | 
                    
| ... | ... | 
                      @@ -649,22 +709,29 @@ class TestCLI:  | 
                  
| 649 | 709 | 
                             @pytest.mark.parametrize('key_index', [1, 2, 3], ids=lambda i: f'index{i}')
                       | 
                    
| 650 | 710 | 
                        def test_204c_key_override_on_command_line(  | 
                    
| 651 | 711 | 
                        self,  | 
                    
| 652 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 653 | 712 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 654 | 713 | 
                        config: dict[str, Any],  | 
                    
| 655 | 714 | 
                        key_index: int,  | 
                    
| 656 | 715 | 
                        ) -> None:  | 
                    
| 657 | 716 | 
                        """A command-line SSH key will override the configured key."""  | 
                    
| 658 | 
                        - with monkeypatch.context():  | 
                    |
| 717 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 718 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 719 | 
                        + # with-statements.  | 
                    |
| 720 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 721 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 722 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 723 | 
                        + stack.enter_context(  | 
                    |
| 724 | 
                        + tests.isolated_vault_config(  | 
                    |
| 725 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 726 | 
                        + runner=runner,  | 
                    |
| 727 | 
                        + vault_config=config,  | 
                    |
| 728 | 
                        + )  | 
                    |
| 729 | 
                        + )  | 
                    |
| 659 | 730 | 
                                     monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
                       | 
                    
| 660 | 731 | 
                        monkeypatch.setattr(  | 
                    
| 661 | 732 | 
                        ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys  | 
                    
| 662 | 733 | 
                        )  | 
                    
| 663 | 734 | 
                        monkeypatch.setattr(ssh_agent.SSHAgentClient, 'sign', tests.sign)  | 
                    
| 664 | 
                        - runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 665 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 666 | 
                        - monkeypatch=monkeypatch, runner=runner, vault_config=config  | 
                    |
| 667 | 
                        - ):  | 
                    |
| 668 | 735 | 
                        result_ = runner.invoke(  | 
                    
| 669 | 736 | 
                        cli.derivepassphrase_vault,  | 
                    
| 670 | 737 | 
                        ['-k', '--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -680,18 +747,17 @@ class TestCLI:  | 
                  
| 680 | 747 | 
                         | 
                    
| 681 | 748 | 
                        def test_205_service_phrase_if_key_in_global_config(  | 
                    
| 682 | 749 | 
                        self,  | 
                    
| 683 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 684 | 750 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 685 | 751 | 
                        ) -> None:  | 
                    
| 686 | 752 | 
                        """A command-line passphrase will override the configured key."""  | 
                    
| 687 | 
                        - with monkeypatch.context():  | 
                    |
| 688 | 
                        -            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
                       | 
                    |
| 689 | 
                        - monkeypatch.setattr(  | 
                    |
| 690 | 
                        - ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys  | 
                    |
| 691 | 
                        - )  | 
                    |
| 692 | 
                        - monkeypatch.setattr(ssh_agent.SSHAgentClient, 'sign', tests.sign)  | 
                    |
| 693 | 753 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 694 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 754 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 755 | 
                        + # with-statements.  | 
                    |
| 756 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 757 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 758 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 759 | 
                        + stack.enter_context(  | 
                    |
| 760 | 
                        + tests.isolated_vault_config(  | 
                    |
| 695 | 761 | 
                        monkeypatch=monkeypatch,  | 
                    
| 696 | 762 | 
                        runner=runner,  | 
                    
| 697 | 763 | 
                                             vault_config={
                       | 
                    
| ... | ... | 
                      @@ -703,7 +769,13 @@ class TestCLI:  | 
                  
| 703 | 769 | 
                        }  | 
                    
| 704 | 770 | 
                        },  | 
                    
| 705 | 771 | 
                        },  | 
                    
| 706 | 
                        - ):  | 
                    |
| 772 | 
                        + )  | 
                    |
| 773 | 
                        + )  | 
                    |
| 774 | 
                        +            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
                       | 
                    |
| 775 | 
                        + monkeypatch.setattr(  | 
                    |
| 776 | 
                        + ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys  | 
                    |
| 777 | 
                        + )  | 
                    |
| 778 | 
                        + monkeypatch.setattr(ssh_agent.SSHAgentClient, 'sign', tests.sign)  | 
                    |
| 707 | 779 | 
                        result_ = runner.invoke(  | 
                    
| 708 | 780 | 
                        cli.derivepassphrase_vault,  | 
                    
| 709 | 781 | 
                        ['--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -755,25 +827,30 @@ class TestCLI:  | 
                  
| 755 | 827 | 
                        )  | 
                    
| 756 | 828 | 
                        def test_206_setting_phrase_thus_overriding_key_in_config(  | 
                    
| 757 | 829 | 
                        self,  | 
                    
| 758 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 759 | 830 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 760 | 831 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 761 | 832 | 
                        config: _types.VaultConfig,  | 
                    
| 762 | 833 | 
                        command_line: list[str],  | 
                    
| 763 | 834 | 
                        ) -> None:  | 
                    
| 764 | 835 | 
                        """Configuring a passphrase atop an SSH key works, but warns."""  | 
                    
| 765 | 
                        - with monkeypatch.context():  | 
                    |
| 836 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 837 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 838 | 
                        + # with-statements.  | 
                    |
| 839 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 840 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 841 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 842 | 
                        + stack.enter_context(  | 
                    |
| 843 | 
                        + tests.isolated_vault_config(  | 
                    |
| 844 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 845 | 
                        + runner=runner,  | 
                    |
| 846 | 
                        + vault_config=config,  | 
                    |
| 847 | 
                        + )  | 
                    |
| 848 | 
                        + )  | 
                    |
| 766 | 849 | 
                                     monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
                       | 
                    
| 767 | 850 | 
                        monkeypatch.setattr(  | 
                    
| 768 | 851 | 
                        ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys  | 
                    
| 769 | 852 | 
                        )  | 
                    
| 770 | 853 | 
                        monkeypatch.setattr(ssh_agent.SSHAgentClient, 'sign', tests.sign)  | 
                    
| 771 | 
                        - runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 772 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 773 | 
                        - monkeypatch=monkeypatch,  | 
                    |
| 774 | 
                        - runner=runner,  | 
                    |
| 775 | 
                        - vault_config=config,  | 
                    |
| 776 | 
                        - ):  | 
                    |
| 777 | 854 | 
                        result_ = runner.invoke(  | 
                    
| 778 | 855 | 
                        cli.derivepassphrase_vault,  | 
                    
| 779 | 856 | 
                        command_line,  | 
                    
| ... | ... | 
                      @@ -812,14 +889,22 @@ class TestCLI:  | 
                  
| 812 | 889 | 
                        ],  | 
                    
| 813 | 890 | 
                        )  | 
                    
| 814 | 891 | 
                        def test_210_invalid_argument_range(  | 
                    
| 815 | 
                        - self, monkeypatch: pytest.MonkeyPatch, option: str  | 
                    |
| 892 | 
                        + self,  | 
                    |
| 893 | 
                        + option: str,  | 
                    |
| 816 | 894 | 
                        ) -> None:  | 
                    
| 817 | 895 | 
                        """Requesting invalidly many characters from a class fails."""  | 
                    
| 818 | 896 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 819 | 
                        - with tests.isolated_config(  | 
                    |
| 897 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 898 | 
                        + # with-statements.  | 
                    |
| 899 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 900 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 901 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 902 | 
                        + stack.enter_context(  | 
                    |
| 903 | 
                        + tests.isolated_config(  | 
                    |
| 820 | 904 | 
                        monkeypatch=monkeypatch,  | 
                    
| 821 | 905 | 
                        runner=runner,  | 
                    
| 822 | 
                        - ):  | 
                    |
| 906 | 
                        + )  | 
                    |
| 907 | 
                        + )  | 
                    |
| 823 | 908 | 
                        for value in '-42', 'invalid':  | 
                    
| 824 | 909 | 
                        result_ = runner.invoke(  | 
                    
| 825 | 910 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -848,20 +933,28 @@ class TestCLI:  | 
                  
| 848 | 933 | 
                        )  | 
                    
| 849 | 934 | 
                        def test_211_service_needed(  | 
                    
| 850 | 935 | 
                        self,  | 
                    
| 851 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 852 | 936 | 
                        options: list[str],  | 
                    
| 853 | 937 | 
                        service: bool | None,  | 
                    
| 854 | 938 | 
                        input: str | None,  | 
                    
| 855 | 939 | 
                        check_success: bool,  | 
                    
| 856 | 940 | 
                        ) -> None:  | 
                    
| 857 | 941 | 
                        """We require or forbid a service argument, depending on options."""  | 
                    
| 858 | 
                        - monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)  | 
                    |
| 859 | 942 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 860 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 943 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 944 | 
                        + # with-statements.  | 
                    |
| 945 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 946 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 947 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 948 | 
                        + stack.enter_context(  | 
                    |
| 949 | 
                        + tests.isolated_vault_config(  | 
                    |
| 861 | 950 | 
                        monkeypatch=monkeypatch,  | 
                    
| 862 | 951 | 
                        runner=runner,  | 
                    
| 863 | 952 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 864 | 
                        - ):  | 
                    |
| 953 | 
                        + )  | 
                    |
| 954 | 
                        + )  | 
                    |
| 955 | 
                        + monkeypatch.setattr(  | 
                    |
| 956 | 
                        + cli, '_prompt_for_passphrase', tests.auto_prompt  | 
                    |
| 957 | 
                        + )  | 
                    |
| 865 | 958 | 
                        result_ = runner.invoke(  | 
                    
| 866 | 959 | 
                        cli.derivepassphrase_vault,  | 
                    
| 867 | 960 | 
                        options if service else [*options, '--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -883,11 +976,18 @@ class TestCLI:  | 
                  
| 883 | 976 | 
                        'expected clean exit'  | 
                    
| 884 | 977 | 
                        )  | 
                    
| 885 | 978 | 
                        if check_success:  | 
                    
| 886 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 979 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 980 | 
                        + # with-statements.  | 
                    |
| 981 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 982 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 983 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 984 | 
                        + stack.enter_context(  | 
                    |
| 985 | 
                        + tests.isolated_vault_config(  | 
                    |
| 887 | 986 | 
                        monkeypatch=monkeypatch,  | 
                    
| 888 | 987 | 
                        runner=runner,  | 
                    
| 889 | 988 | 
                                                 vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 890 | 
                        - ):  | 
                    |
| 989 | 
                        + )  | 
                    |
| 990 | 
                        + )  | 
                    |
| 891 | 991 | 
                        monkeypatch.setattr(  | 
                    
| 892 | 992 | 
                        cli, '_prompt_for_passphrase', tests.auto_prompt  | 
                    
| 893 | 993 | 
                        )  | 
                    
| ... | ... | 
                      @@ -902,7 +1002,6 @@ class TestCLI:  | 
                  
| 902 | 1002 | 
                         | 
                    
| 903 | 1003 | 
                        def test_211a_empty_service_name_causes_warning(  | 
                    
| 904 | 1004 | 
                        self,  | 
                    
| 905 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 906 | 1005 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 907 | 1006 | 
                        ) -> None:  | 
                    
| 908 | 1007 | 
                        """Using an empty service name (where permissible) warns.  | 
                    
| ... | ... | 
                      @@ -918,13 +1017,22 @@ class TestCLI:  | 
                  
| 918 | 1017 | 
                        'An empty SERVICE is not supported by vault(1)', [record]  | 
                    
| 919 | 1018 | 
                        )  | 
                    
| 920 | 1019 | 
                         | 
                    
| 921 | 
                        - monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)  | 
                    |
| 922 | 1020 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 923 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1021 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1022 | 
                        + # with-statements.  | 
                    |
| 1023 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1024 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1025 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1026 | 
                        + stack.enter_context(  | 
                    |
| 1027 | 
                        + tests.isolated_vault_config(  | 
                    |
| 924 | 1028 | 
                        monkeypatch=monkeypatch,  | 
                    
| 925 | 1029 | 
                        runner=runner,  | 
                    
| 926 | 1030 | 
                                             vault_config={'services': {}},
                       | 
                    
| 927 | 
                        - ):  | 
                    |
| 1031 | 
                        + )  | 
                    |
| 1032 | 
                        + )  | 
                    |
| 1033 | 
                        + monkeypatch.setattr(  | 
                    |
| 1034 | 
                        + cli, '_prompt_for_passphrase', tests.auto_prompt  | 
                    |
| 1035 | 
                        + )  | 
                    |
| 928 | 1036 | 
                        result_ = runner.invoke(  | 
                    
| 929 | 1037 | 
                        cli.derivepassphrase_vault,  | 
                    
| 930 | 1038 | 
                        ['--config', '--length=30', '--', ''],  | 
                    
| ... | ... | 
                      @@ -968,16 +1076,22 @@ class TestCLI:  | 
                  
| 968 | 1076 | 
                        )  | 
                    
| 969 | 1077 | 
                        def test_212_incompatible_options(  | 
                    
| 970 | 1078 | 
                        self,  | 
                    
| 971 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 972 | 1079 | 
                        options: list[str],  | 
                    
| 973 | 1080 | 
                        service: bool | None,  | 
                    
| 974 | 1081 | 
                        ) -> None:  | 
                    
| 975 | 1082 | 
                        """Incompatible options are detected."""  | 
                    
| 976 | 1083 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 977 | 
                        - with tests.isolated_config(  | 
                    |
| 1084 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1085 | 
                        + # with-statements.  | 
                    |
| 1086 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1087 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1088 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1089 | 
                        + stack.enter_context(  | 
                    |
| 1090 | 
                        + tests.isolated_config(  | 
                    |
| 978 | 1091 | 
                        monkeypatch=monkeypatch,  | 
                    
| 979 | 1092 | 
                        runner=runner,  | 
                    
| 980 | 
                        - ):  | 
                    |
| 1093 | 
                        + )  | 
                    |
| 1094 | 
                        + )  | 
                    |
| 981 | 1095 | 
                        result_ = runner.invoke(  | 
                    
| 982 | 1096 | 
                        cli.derivepassphrase_vault,  | 
                    
| 983 | 1097 | 
                        [*options, '--', DUMMY_SERVICE] if service else options,  | 
                    
| ... | ... | 
                      @@ -999,17 +1113,23 @@ class TestCLI:  | 
                  
| 999 | 1113 | 
                        )  | 
                    
| 1000 | 1114 | 
                        def test_213_import_config_success(  | 
                    
| 1001 | 1115 | 
                        self,  | 
                    
| 1002 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1003 | 1116 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 1004 | 1117 | 
                        config: Any,  | 
                    
| 1005 | 1118 | 
                        ) -> None:  | 
                    
| 1006 | 1119 | 
                        """Importing a configuration works."""  | 
                    
| 1007 | 1120 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1008 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1121 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1122 | 
                        + # with-statements.  | 
                    |
| 1123 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1124 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1125 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1126 | 
                        + stack.enter_context(  | 
                    |
| 1127 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1009 | 1128 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1010 | 1129 | 
                        runner=runner,  | 
                    
| 1011 | 1130 | 
                                             vault_config={'services': {}},
                       | 
                    
| 1012 | 
                        - ):  | 
                    |
| 1131 | 
                        + )  | 
                    |
| 1132 | 
                        + )  | 
                    |
| 1013 | 1133 | 
                        result_ = runner.invoke(  | 
                    
| 1014 | 1134 | 
                        cli.derivepassphrase_vault,  | 
                    
| 1015 | 1135 | 
                        ['--import', '-'],  | 
                    
| ... | ... | 
                      @@ -1051,11 +1171,18 @@ class TestCLI:  | 
                  
| 1051 | 1171 | 
                        config2 = copy.deepcopy(config)  | 
                    
| 1052 | 1172 | 
                        _types.clean_up_falsy_vault_config_values(config2)  | 
                    
| 1053 | 1173 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1054 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1055 | 
                        - monkeypatch=pytest.MonkeyPatch(),  | 
                    |
| 1174 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1175 | 
                        + # with-statements.  | 
                    |
| 1176 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1177 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1178 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1179 | 
                        + stack.enter_context(  | 
                    |
| 1180 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1181 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1056 | 1182 | 
                        runner=runner,  | 
                    
| 1057 | 1183 | 
                                             vault_config={'services': {}},
                       | 
                    
| 1058 | 
                        - ):  | 
                    |
| 1184 | 
                        + )  | 
                    |
| 1185 | 
                        + )  | 
                    |
| 1059 | 1186 | 
                        result_ = runner.invoke(  | 
                    
| 1060 | 1187 | 
                        cli.derivepassphrase_vault,  | 
                    
| 1061 | 1188 | 
                        ['--import', '-'],  | 
                    
| ... | ... | 
                      @@ -1075,11 +1202,20 @@ class TestCLI:  | 
                  
| 1075 | 1202 | 
                         | 
                    
| 1076 | 1203 | 
                        def test_213b_import_bad_config_not_vault_config(  | 
                    
| 1077 | 1204 | 
                        self,  | 
                    
| 1078 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1079 | 1205 | 
                        ) -> None:  | 
                    
| 1080 | 1206 | 
                        """Importing an invalid config fails."""  | 
                    
| 1081 | 1207 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1082 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 1208 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1209 | 
                        + # with-statements.  | 
                    |
| 1210 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1211 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1212 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1213 | 
                        + stack.enter_context(  | 
                    |
| 1214 | 
                        + tests.isolated_config(  | 
                    |
| 1215 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1216 | 
                        + runner=runner,  | 
                    |
| 1217 | 
                        + )  | 
                    |
| 1218 | 
                        + )  | 
                    |
| 1083 | 1219 | 
                        result_ = runner.invoke(  | 
                    
| 1084 | 1220 | 
                        cli.derivepassphrase_vault,  | 
                    
| 1085 | 1221 | 
                        ['--import', '-'],  | 
                    
| ... | ... | 
                      @@ -1093,11 +1229,20 @@ class TestCLI:  | 
                  
| 1093 | 1229 | 
                         | 
                    
| 1094 | 1230 | 
                        def test_213c_import_bad_config_not_json_data(  | 
                    
| 1095 | 1231 | 
                        self,  | 
                    
| 1096 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1097 | 1232 | 
                        ) -> None:  | 
                    
| 1098 | 1233 | 
                        """Importing an invalid config fails."""  | 
                    
| 1099 | 1234 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1100 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 1235 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1236 | 
                        + # with-statements.  | 
                    |
| 1237 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1238 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1239 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1240 | 
                        + stack.enter_context(  | 
                    |
| 1241 | 
                        + tests.isolated_config(  | 
                    |
| 1242 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1243 | 
                        + runner=runner,  | 
                    |
| 1244 | 
                        + )  | 
                    |
| 1245 | 
                        + )  | 
                    |
| 1101 | 1246 | 
                        result_ = runner.invoke(  | 
                    
| 1102 | 1247 | 
                        cli.derivepassphrase_vault,  | 
                    
| 1103 | 1248 | 
                        ['--import', '-'],  | 
                    
| ... | ... | 
                      @@ -1111,15 +1256,26 @@ class TestCLI:  | 
                  
| 1111 | 1256 | 
                         | 
                    
| 1112 | 1257 | 
                        def test_213d_import_bad_config_not_a_file(  | 
                    
| 1113 | 1258 | 
                        self,  | 
                    
| 1114 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1115 | 1259 | 
                        ) -> None:  | 
                    
| 1116 | 1260 | 
                        """Importing an invalid config fails."""  | 
                    
| 1117 | 1261 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1118 | 
                        - # `isolated_vault_config` validates the configuration. So, to  | 
                    |
| 1119 | 
                        - # pass an actual broken configuration, we must open the  | 
                    |
| 1120 | 
                        - # configuration file ourselves afterwards, inside the context.  | 
                    |
| 1121 | 
                        - # We also might as well use `isolated_config` instead.  | 
                    |
| 1122 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 1262 | 
                        + # `isolated_vault_config` ensures the configuration is valid  | 
                    |
| 1263 | 
                        + # JSON. So, to pass an actual broken configuration, we must  | 
                    |
| 1264 | 
                        + # open the configuration file ourselves afterwards, inside the  | 
                    |
| 1265 | 
                        + # context.  | 
                    |
| 1266 | 
                        + #  | 
                    |
| 1267 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1268 | 
                        + # with-statements.  | 
                    |
| 1269 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1270 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1271 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1272 | 
                        + stack.enter_context(  | 
                    |
| 1273 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1274 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1275 | 
                        + runner=runner,  | 
                    |
| 1276 | 
                        +                    vault_config={'services': {}},
                       | 
                    |
| 1277 | 
                        + )  | 
                    |
| 1278 | 
                        + )  | 
                    |
| 1123 | 1279 | 
                        cli._config_filename(subsystem='vault').write_text(  | 
                    
| 1124 | 1280 | 
                        'This string is not valid JSON.\n', encoding='UTF-8'  | 
                    
| 1125 | 1281 | 
                        )  | 
                    
| ... | ... | 
                      @@ -1143,12 +1299,21 @@ class TestCLI:  | 
                  
| 1143 | 1299 | 
                        )  | 
                    
| 1144 | 1300 | 
                        def test_214_export_settings_no_stored_settings(  | 
                    
| 1145 | 1301 | 
                        self,  | 
                    
| 1146 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1147 | 1302 | 
                        export_options: list[str],  | 
                    
| 1148 | 1303 | 
                        ) -> None:  | 
                    
| 1149 | 1304 | 
                        """Exporting the default, empty config works."""  | 
                    
| 1150 | 1305 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1151 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 1306 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1307 | 
                        + # with-statements.  | 
                    |
| 1308 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1309 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1310 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1311 | 
                        + stack.enter_context(  | 
                    |
| 1312 | 
                        + tests.isolated_config(  | 
                    |
| 1313 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1314 | 
                        + runner=runner,  | 
                    |
| 1315 | 
                        + )  | 
                    |
| 1316 | 
                        + )  | 
                    |
| 1152 | 1317 | 
                        cli._config_filename(subsystem='vault').unlink(missing_ok=True)  | 
                    
| 1153 | 1318 | 
                        result_ = runner.invoke(  | 
                    
| 1154 | 1319 | 
                        # Test parent context navigation by not calling  | 
                    
| ... | ... | 
                      @@ -1171,14 +1336,22 @@ class TestCLI:  | 
                  
| 1171 | 1336 | 
                        )  | 
                    
| 1172 | 1337 | 
                        def test_214a_export_settings_bad_stored_config(  | 
                    
| 1173 | 1338 | 
                        self,  | 
                    
| 1174 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1175 | 1339 | 
                        export_options: list[str],  | 
                    
| 1176 | 1340 | 
                        ) -> None:  | 
                    
| 1177 | 1341 | 
                        """Exporting an invalid config fails."""  | 
                    
| 1178 | 1342 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1179 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1180 | 
                        -            monkeypatch=monkeypatch, runner=runner, vault_config={}
                       | 
                    |
| 1181 | 
                        - ):  | 
                    |
| 1343 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1344 | 
                        + # with-statements.  | 
                    |
| 1345 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1346 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1347 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1348 | 
                        + stack.enter_context(  | 
                    |
| 1349 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1350 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1351 | 
                        + runner=runner,  | 
                    |
| 1352 | 
                        +                    vault_config={},
                       | 
                    |
| 1353 | 
                        + )  | 
                    |
| 1354 | 
                        + )  | 
                    |
| 1182 | 1355 | 
                        result_ = runner.invoke(  | 
                    
| 1183 | 1356 | 
                        cli.derivepassphrase_vault,  | 
                    
| 1184 | 1357 | 
                        ['--export', '-', *export_options],  | 
                    
| ... | ... | 
                      @@ -1199,12 +1372,21 @@ class TestCLI:  | 
                  
| 1199 | 1372 | 
                        )  | 
                    
| 1200 | 1373 | 
                        def test_214b_export_settings_not_a_file(  | 
                    
| 1201 | 1374 | 
                        self,  | 
                    
| 1202 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1203 | 1375 | 
                        export_options: list[str],  | 
                    
| 1204 | 1376 | 
                        ) -> None:  | 
                    
| 1205 | 1377 | 
                        """Exporting an invalid config fails."""  | 
                    
| 1206 | 1378 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1207 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 1379 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1380 | 
                        + # with-statements.  | 
                    |
| 1381 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1382 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1383 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1384 | 
                        + stack.enter_context(  | 
                    |
| 1385 | 
                        + tests.isolated_config(  | 
                    |
| 1386 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1387 | 
                        + runner=runner,  | 
                    |
| 1388 | 
                        + )  | 
                    |
| 1389 | 
                        + )  | 
                    |
| 1208 | 1390 | 
                        config_file = cli._config_filename(subsystem='vault')  | 
                    
| 1209 | 1391 | 
                        config_file.unlink(missing_ok=True)  | 
                    
| 1210 | 1392 | 
                        config_file.mkdir(parents=True, exist_ok=True)  | 
                    
| ... | ... | 
                      @@ -1228,12 +1410,21 @@ class TestCLI:  | 
                  
| 1228 | 1410 | 
                        )  | 
                    
| 1229 | 1411 | 
                        def test_214c_export_settings_target_not_a_file(  | 
                    
| 1230 | 1412 | 
                        self,  | 
                    
| 1231 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1232 | 1413 | 
                        export_options: list[str],  | 
                    
| 1233 | 1414 | 
                        ) -> None:  | 
                    
| 1234 | 1415 | 
                        """Exporting an invalid config fails."""  | 
                    
| 1235 | 1416 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1236 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 1417 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1418 | 
                        + # with-statements.  | 
                    |
| 1419 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1420 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1421 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1422 | 
                        + stack.enter_context(  | 
                    |
| 1423 | 
                        + tests.isolated_config(  | 
                    |
| 1424 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1425 | 
                        + runner=runner,  | 
                    |
| 1426 | 
                        + )  | 
                    |
| 1427 | 
                        + )  | 
                    |
| 1237 | 1428 | 
                        dname = cli._config_filename(subsystem=None)  | 
                    
| 1238 | 1429 | 
                        result_ = runner.invoke(  | 
                    
| 1239 | 1430 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -1255,12 +1446,21 @@ class TestCLI:  | 
                  
| 1255 | 1446 | 
                        )  | 
                    
| 1256 | 1447 | 
                        def test_214d_export_settings_settings_directory_not_a_directory(  | 
                    
| 1257 | 1448 | 
                        self,  | 
                    
| 1258 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1259 | 1449 | 
                        export_options: list[str],  | 
                    
| 1260 | 1450 | 
                        ) -> None:  | 
                    
| 1261 | 1451 | 
                        """Exporting an invalid config fails."""  | 
                    
| 1262 | 1452 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1263 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 1453 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1454 | 
                        + # with-statements.  | 
                    |
| 1455 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1456 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1457 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1458 | 
                        + stack.enter_context(  | 
                    |
| 1459 | 
                        + tests.isolated_config(  | 
                    |
| 1460 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 1461 | 
                        + runner=runner,  | 
                    |
| 1462 | 
                        + )  | 
                    |
| 1463 | 
                        + )  | 
                    |
| 1264 | 1464 | 
                        config_dir = cli._config_filename(subsystem=None)  | 
                    
| 1265 | 1465 | 
                        with contextlib.suppress(FileNotFoundError):  | 
                    
| 1266 | 1466 | 
                        shutil.rmtree(config_dir)  | 
                    
| ... | ... | 
                      @@ -1279,7 +1479,7 @@ class TestCLI:  | 
                  
| 1279 | 1479 | 
                        )  | 
                    
| 1280 | 1480 | 
                         | 
                    
| 1281 | 1481 | 
                        def test_220_edit_notes_successfully(  | 
                    
| 1282 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 1482 | 
                        + self,  | 
                    |
| 1283 | 1483 | 
                        ) -> None:  | 
                    
| 1284 | 1484 | 
                        """Editing notes works."""  | 
                    
| 1285 | 1485 | 
                        edit_result = """  | 
                    
| ... | ... | 
                      @@ -1288,11 +1488,18 @@ class TestCLI:  | 
                  
| 1288 | 1488 | 
                        contents go here  | 
                    
| 1289 | 1489 | 
                        """  | 
                    
| 1290 | 1490 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1291 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1491 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1492 | 
                        + # with-statements.  | 
                    |
| 1493 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1494 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1495 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1496 | 
                        + stack.enter_context(  | 
                    |
| 1497 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1292 | 1498 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1293 | 1499 | 
                        runner=runner,  | 
                    
| 1294 | 1500 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1295 | 
                        - ):  | 
                    |
| 1501 | 
                        + )  | 
                    |
| 1502 | 
                        + )  | 
                    |
| 1296 | 1503 | 
                        monkeypatch.setattr(click, 'edit', lambda *a, **kw: edit_result) # noqa: ARG005  | 
                    
| 1297 | 1504 | 
                        result_ = runner.invoke(  | 
                    
| 1298 | 1505 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -1311,15 +1518,22 @@ contents go here  | 
                  
| 1311 | 1518 | 
                        }  | 
                    
| 1312 | 1519 | 
                         | 
                    
| 1313 | 1520 | 
                        def test_221_edit_notes_noop(  | 
                    
| 1314 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 1521 | 
                        + self,  | 
                    |
| 1315 | 1522 | 
                        ) -> None:  | 
                    
| 1316 | 1523 | 
                        """Abandoning edited notes works."""  | 
                    
| 1317 | 1524 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1318 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1525 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1526 | 
                        + # with-statements.  | 
                    |
| 1527 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1528 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1529 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1530 | 
                        + stack.enter_context(  | 
                    |
| 1531 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1319 | 1532 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1320 | 1533 | 
                        runner=runner,  | 
                    
| 1321 | 1534 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1322 | 
                        - ):  | 
                    |
| 1535 | 
                        + )  | 
                    |
| 1536 | 
                        + )  | 
                    |
| 1323 | 1537 | 
                        monkeypatch.setattr(click, 'edit', lambda *a, **kw: None) # noqa: ARG005  | 
                    
| 1324 | 1538 | 
                        result_ = runner.invoke(  | 
                    
| 1325 | 1539 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -1337,7 +1551,7 @@ contents go here  | 
                  
| 1337 | 1551 | 
                        # TODO(the-13th-letter): Keep this behavior or not, with or without  | 
                    
| 1338 | 1552 | 
                        # warning?  | 
                    
| 1339 | 1553 | 
                        def test_222_edit_notes_marker_removed(  | 
                    
| 1340 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 1554 | 
                        + self,  | 
                    |
| 1341 | 1555 | 
                        ) -> None:  | 
                    
| 1342 | 1556 | 
                        """Removing the notes marker still saves the notes.  | 
                    
| 1343 | 1557 | 
                         | 
                    
| ... | ... | 
                      @@ -1345,11 +1559,18 @@ contents go here  | 
                  
| 1345 | 1559 | 
                         | 
                    
| 1346 | 1560 | 
                        """  | 
                    
| 1347 | 1561 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1348 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1562 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1563 | 
                        + # with-statements.  | 
                    |
| 1564 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1565 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1566 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1567 | 
                        + stack.enter_context(  | 
                    |
| 1568 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1349 | 1569 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1350 | 1570 | 
                        runner=runner,  | 
                    
| 1351 | 1571 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1352 | 
                        - ):  | 
                    |
| 1572 | 
                        + )  | 
                    |
| 1573 | 
                        + )  | 
                    |
| 1353 | 1574 | 
                        monkeypatch.setattr(click, 'edit', lambda *a, **kw: 'long\ntext') # noqa: ARG005  | 
                    
| 1354 | 1575 | 
                        result_ = runner.invoke(  | 
                    
| 1355 | 1576 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -1368,15 +1589,22 @@ contents go here  | 
                  
| 1368 | 1589 | 
                        }  | 
                    
| 1369 | 1590 | 
                         | 
                    
| 1370 | 1591 | 
                        def test_223_edit_notes_abort(  | 
                    
| 1371 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 1592 | 
                        + self,  | 
                    |
| 1372 | 1593 | 
                        ) -> None:  | 
                    
| 1373 | 1594 | 
                        """Aborting editing notes works."""  | 
                    
| 1374 | 1595 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1375 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1596 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1597 | 
                        + # with-statements.  | 
                    |
| 1598 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1599 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1600 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1601 | 
                        + stack.enter_context(  | 
                    |
| 1602 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1376 | 1603 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1377 | 1604 | 
                        runner=runner,  | 
                    
| 1378 | 1605 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1379 | 
                        - ):  | 
                    |
| 1606 | 
                        + )  | 
                    |
| 1607 | 
                        + )  | 
                    |
| 1380 | 1608 | 
                        monkeypatch.setattr(click, 'edit', lambda *a, **kw: '\n\n') # noqa: ARG005  | 
                    
| 1381 | 1609 | 
                        result_ = runner.invoke(  | 
                    
| 1382 | 1610 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -1442,18 +1670,24 @@ contents go here  | 
                  
| 1442 | 1670 | 
                        )  | 
                    
| 1443 | 1671 | 
                        def test_224_store_config_good(  | 
                    
| 1444 | 1672 | 
                        self,  | 
                    
| 1445 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1446 | 1673 | 
                        command_line: list[str],  | 
                    
| 1447 | 1674 | 
                        input: str,  | 
                    
| 1448 | 1675 | 
                        result_config: Any,  | 
                    
| 1449 | 1676 | 
                        ) -> None:  | 
                    
| 1450 | 1677 | 
                        """Storing valid settings via `--config` works."""  | 
                    
| 1451 | 1678 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1452 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1679 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1680 | 
                        + # with-statements.  | 
                    |
| 1681 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1682 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1683 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1684 | 
                        + stack.enter_context(  | 
                    |
| 1685 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1453 | 1686 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1454 | 1687 | 
                        runner=runner,  | 
                    
| 1455 | 1688 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1456 | 
                        - ):  | 
                    |
| 1689 | 
                        + )  | 
                    |
| 1690 | 
                        + )  | 
                    |
| 1457 | 1691 | 
                        monkeypatch.setattr(  | 
                    
| 1458 | 1692 | 
                        cli, '_get_suitable_ssh_keys', tests.suitable_ssh_keys  | 
                    
| 1459 | 1693 | 
                        )  | 
                    
| ... | ... | 
                      @@ -1504,18 +1738,24 @@ contents go here  | 
                  
| 1504 | 1738 | 
                        )  | 
                    
| 1505 | 1739 | 
                        def test_225_store_config_fail(  | 
                    
| 1506 | 1740 | 
                        self,  | 
                    
| 1507 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1508 | 1741 | 
                        command_line: list[str],  | 
                    
| 1509 | 1742 | 
                        input: str,  | 
                    
| 1510 | 1743 | 
                        err_text: str,  | 
                    
| 1511 | 1744 | 
                        ) -> None:  | 
                    
| 1512 | 1745 | 
                        """Storing invalid settings via `--config` fails."""  | 
                    
| 1513 | 1746 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1514 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1747 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1748 | 
                        + # with-statements.  | 
                    |
| 1749 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1750 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1751 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1752 | 
                        + stack.enter_context(  | 
                    |
| 1753 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1515 | 1754 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1516 | 1755 | 
                        runner=runner,  | 
                    
| 1517 | 1756 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1518 | 
                        - ):  | 
                    |
| 1757 | 
                        + )  | 
                    |
| 1758 | 
                        + )  | 
                    |
| 1519 | 1759 | 
                        monkeypatch.setattr(  | 
                    
| 1520 | 1760 | 
                        cli, '_get_suitable_ssh_keys', tests.suitable_ssh_keys  | 
                    
| 1521 | 1761 | 
                        )  | 
                    
| ... | ... | 
                      @@ -1532,15 +1772,21 @@ contents go here  | 
                  
| 1532 | 1772 | 
                         | 
                    
| 1533 | 1773 | 
                        def test_225a_store_config_fail_manual_no_ssh_key_selection(  | 
                    
| 1534 | 1774 | 
                        self,  | 
                    
| 1535 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1536 | 1775 | 
                        ) -> None:  | 
                    
| 1537 | 1776 | 
                        """Not selecting an SSH key during `--config --key` fails."""  | 
                    
| 1538 | 1777 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1539 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1778 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1779 | 
                        + # with-statements.  | 
                    |
| 1780 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1781 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1782 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1783 | 
                        + stack.enter_context(  | 
                    |
| 1784 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1540 | 1785 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1541 | 1786 | 
                        runner=runner,  | 
                    
| 1542 | 1787 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1543 | 
                        - ):  | 
                    |
| 1788 | 
                        + )  | 
                    |
| 1789 | 
                        + )  | 
                    |
| 1544 | 1790 | 
                        custom_error = 'custom error message'  | 
                    
| 1545 | 1791 | 
                         | 
                    
| 1546 | 1792 | 
                        def raiser(*_args: Any, **_kwargs: Any) -> None:  | 
                    
| ... | ... | 
                      @@ -1559,17 +1805,23 @@ contents go here  | 
                  
| 1559 | 1805 | 
                         | 
                    
| 1560 | 1806 | 
                        def test_225b_store_config_fail_manual_no_ssh_agent(  | 
                    
| 1561 | 1807 | 
                        self,  | 
                    
| 1562 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1563 | 1808 | 
                        skip_if_no_af_unix_support: None,  | 
                    
| 1564 | 1809 | 
                        ) -> None:  | 
                    
| 1565 | 1810 | 
                        """Not running an SSH agent during `--config --key` fails."""  | 
                    
| 1566 | 1811 | 
                        del skip_if_no_af_unix_support  | 
                    
| 1567 | 1812 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1568 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1813 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1814 | 
                        + # with-statements.  | 
                    |
| 1815 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1816 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1817 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1818 | 
                        + stack.enter_context(  | 
                    |
| 1819 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1569 | 1820 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1570 | 1821 | 
                        runner=runner,  | 
                    
| 1571 | 1822 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1572 | 
                        - ):  | 
                    |
| 1823 | 
                        + )  | 
                    |
| 1824 | 
                        + )  | 
                    |
| 1573 | 1825 | 
                                     monkeypatch.delenv('SSH_AUTH_SOCK', raising=False)
                       | 
                    
| 1574 | 1826 | 
                        result_ = runner.invoke(  | 
                    
| 1575 | 1827 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -1583,15 +1835,21 @@ contents go here  | 
                  
| 1583 | 1835 | 
                         | 
                    
| 1584 | 1836 | 
                        def test_225c_store_config_fail_manual_bad_ssh_agent_connection(  | 
                    
| 1585 | 1837 | 
                        self,  | 
                    
| 1586 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1587 | 1838 | 
                        ) -> None:  | 
                    
| 1588 | 1839 | 
                        """Not running a reachable SSH agent during `--config --key` fails."""  | 
                    
| 1589 | 1840 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1590 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1841 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1842 | 
                        + # with-statements.  | 
                    |
| 1843 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1844 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1845 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1846 | 
                        + stack.enter_context(  | 
                    |
| 1847 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1591 | 1848 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1592 | 1849 | 
                        runner=runner,  | 
                    
| 1593 | 1850 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1594 | 
                        - ):  | 
                    |
| 1851 | 
                        + )  | 
                    |
| 1852 | 
                        + )  | 
                    |
| 1595 | 1853 | 
                        cwd = pathlib.Path.cwd().resolve()  | 
                    
| 1596 | 1854 | 
                                     monkeypatch.setenv('SSH_AUTH_SOCK', str(cwd))
                       | 
                    
| 1597 | 1855 | 
                        result_ = runner.invoke(  | 
                    
| ... | ... | 
                      @@ -1607,16 +1865,22 @@ contents go here  | 
                  
| 1607 | 1865 | 
                             @pytest.mark.parametrize('try_race_free_implementation', [True, False])
                       | 
                    
| 1608 | 1866 | 
                        def test_225d_store_config_fail_manual_read_only_file(  | 
                    
| 1609 | 1867 | 
                        self,  | 
                    
| 1610 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1611 | 1868 | 
                        try_race_free_implementation: bool,  | 
                    
| 1612 | 1869 | 
                        ) -> None:  | 
                    
| 1613 | 1870 | 
                        """Using a read-only configuration file with `--config` fails."""  | 
                    
| 1614 | 1871 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1615 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1872 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1873 | 
                        + # with-statements.  | 
                    |
| 1874 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1875 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1876 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1877 | 
                        + stack.enter_context(  | 
                    |
| 1878 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1616 | 1879 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1617 | 1880 | 
                        runner=runner,  | 
                    
| 1618 | 1881 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1619 | 
                        - ):  | 
                    |
| 1882 | 
                        + )  | 
                    |
| 1883 | 
                        + )  | 
                    |
| 1620 | 1884 | 
                        tests.make_file_readonly(  | 
                    
| 1621 | 1885 | 
                        cli._config_filename(subsystem='vault'),  | 
                    
| 1622 | 1886 | 
                        try_race_free_implementation=try_race_free_implementation,  | 
                    
| ... | ... | 
                      @@ -1633,15 +1897,21 @@ contents go here  | 
                  
| 1633 | 1897 | 
                         | 
                    
| 1634 | 1898 | 
                        def test_225e_store_config_fail_manual_custom_error(  | 
                    
| 1635 | 1899 | 
                        self,  | 
                    
| 1636 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1637 | 1900 | 
                        ) -> None:  | 
                    
| 1638 | 1901 | 
                        """OS-erroring with `--config` fails."""  | 
                    
| 1639 | 1902 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1640 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1903 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1904 | 
                        + # with-statements.  | 
                    |
| 1905 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1906 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1907 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1908 | 
                        + stack.enter_context(  | 
                    |
| 1909 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1641 | 1910 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1642 | 1911 | 
                        runner=runner,  | 
                    
| 1643 | 1912 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1644 | 
                        - ):  | 
                    |
| 1913 | 
                        + )  | 
                    |
| 1914 | 
                        + )  | 
                    |
| 1645 | 1915 | 
                        custom_error = 'custom error message'  | 
                    
| 1646 | 1916 | 
                         | 
                    
| 1647 | 1917 | 
                        def raiser(config: Any) -> None:  | 
                    
| ... | ... | 
                      @@ -1661,15 +1931,21 @@ contents go here  | 
                  
| 1661 | 1931 | 
                         | 
                    
| 1662 | 1932 | 
                        def test_225f_store_config_fail_unset_and_set_same_settings(  | 
                    
| 1663 | 1933 | 
                        self,  | 
                    
| 1664 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1665 | 1934 | 
                        ) -> None:  | 
                    
| 1666 | 1935 | 
                        """Issuing conflicting settings to `--config` fails."""  | 
                    
| 1667 | 1936 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1668 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1937 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1938 | 
                        + # with-statements.  | 
                    |
| 1939 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1940 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1941 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1942 | 
                        + stack.enter_context(  | 
                    |
| 1943 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1669 | 1944 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1670 | 1945 | 
                        runner=runner,  | 
                    
| 1671 | 1946 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1672 | 
                        - ):  | 
                    |
| 1947 | 
                        + )  | 
                    |
| 1948 | 
                        + )  | 
                    |
| 1673 | 1949 | 
                        result_ = runner.invoke(  | 
                    
| 1674 | 1950 | 
                        cli.derivepassphrase_vault,  | 
                    
| 1675 | 1951 | 
                        [  | 
                    
| ... | ... | 
                      @@ -1688,17 +1964,23 @@ contents go here  | 
                  
| 1688 | 1964 | 
                         | 
                    
| 1689 | 1965 | 
                        def test_225g_store_config_fail_manual_ssh_agent_no_keys_loaded(  | 
                    
| 1690 | 1966 | 
                        self,  | 
                    
| 1691 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1692 | 1967 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 1693 | 1968 | 
                        ) -> None:  | 
                    
| 1694 | 1969 | 
                        """Not holding any SSH keys during `--config --key` fails."""  | 
                    
| 1695 | 1970 | 
                        del running_ssh_agent  | 
                    
| 1696 | 1971 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1697 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 1972 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 1973 | 
                        + # with-statements.  | 
                    |
| 1974 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 1975 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 1976 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 1977 | 
                        + stack.enter_context(  | 
                    |
| 1978 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1698 | 1979 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1699 | 1980 | 
                        runner=runner,  | 
                    
| 1700 | 1981 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1701 | 
                        - ):  | 
                    |
| 1982 | 
                        + )  | 
                    |
| 1983 | 
                        + )  | 
                    |
| 1702 | 1984 | 
                         | 
                    
| 1703 | 1985 | 
                        def func(  | 
                    
| 1704 | 1986 | 
                        *_args: Any,  | 
                    
| ... | ... | 
                      @@ -1719,17 +2001,23 @@ contents go here  | 
                  
| 1719 | 2001 | 
                         | 
                    
| 1720 | 2002 | 
                        def test_225h_store_config_fail_manual_ssh_agent_runtime_error(  | 
                    
| 1721 | 2003 | 
                        self,  | 
                    
| 1722 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1723 | 2004 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 1724 | 2005 | 
                        ) -> None:  | 
                    
| 1725 | 2006 | 
                        """The SSH agent erroring during `--config --key` fails."""  | 
                    
| 1726 | 2007 | 
                        del running_ssh_agent  | 
                    
| 1727 | 2008 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1728 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2009 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2010 | 
                        + # with-statements.  | 
                    |
| 2011 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2012 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2013 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2014 | 
                        + stack.enter_context(  | 
                    |
| 2015 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1729 | 2016 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1730 | 2017 | 
                        runner=runner,  | 
                    
| 1731 | 2018 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1732 | 
                        - ):  | 
                    |
| 2019 | 
                        + )  | 
                    |
| 2020 | 
                        + )  | 
                    |
| 1733 | 2021 | 
                         | 
                    
| 1734 | 2022 | 
                        def raiser(*_args: Any, **_kwargs: Any) -> None:  | 
                    
| 1735 | 2023 | 
                        raise ssh_agent.TrailingDataError()  | 
                    
| ... | ... | 
                      @@ -1747,17 +2035,23 @@ contents go here  | 
                  
| 1747 | 2035 | 
                         | 
                    
| 1748 | 2036 | 
                        def test_225i_store_config_fail_manual_ssh_agent_refuses(  | 
                    
| 1749 | 2037 | 
                        self,  | 
                    
| 1750 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 1751 | 2038 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 1752 | 2039 | 
                        ) -> None:  | 
                    
| 1753 | 2040 | 
                        """The SSH agent refusing during `--config --key` fails."""  | 
                    
| 1754 | 2041 | 
                        del running_ssh_agent  | 
                    
| 1755 | 2042 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1756 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2043 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2044 | 
                        + # with-statements.  | 
                    |
| 2045 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2046 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2047 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2048 | 
                        + stack.enter_context(  | 
                    |
| 2049 | 
                        + tests.isolated_vault_config(  | 
                    |
| 1757 | 2050 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1758 | 2051 | 
                        runner=runner,  | 
                    
| 1759 | 2052 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 1760 | 
                        - ):  | 
                    |
| 2053 | 
                        + )  | 
                    |
| 2054 | 
                        + )  | 
                    |
| 1761 | 2055 | 
                         | 
                    
| 1762 | 2056 | 
                        def func(*_args: Any, **_kwargs: Any) -> NoReturn:  | 
                    
| 1763 | 2057 | 
                        raise ssh_agent.SSHAgentFailedError(  | 
                    
| ... | ... | 
                      @@ -1775,13 +2069,20 @@ contents go here  | 
                  
| 1775 | 2069 | 
                        'expected error exit and known error message'  | 
                    
| 1776 | 2070 | 
                        )  | 
                    
| 1777 | 2071 | 
                         | 
                    
| 1778 | 
                        - def test_226_no_arguments(self, monkeypatch: pytest.MonkeyPatch) -> None:  | 
                    |
| 2072 | 
                        + def test_226_no_arguments(self) -> None:  | 
                    |
| 1779 | 2073 | 
                        """Calling `derivepassphrase vault` without any arguments fails."""  | 
                    
| 1780 | 2074 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1781 | 
                        - with tests.isolated_config(  | 
                    |
| 2075 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2076 | 
                        + # with-statements.  | 
                    |
| 2077 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2078 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2079 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2080 | 
                        + stack.enter_context(  | 
                    |
| 2081 | 
                        + tests.isolated_config(  | 
                    |
| 1782 | 2082 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1783 | 2083 | 
                        runner=runner,  | 
                    
| 1784 | 
                        - ):  | 
                    |
| 2084 | 
                        + )  | 
                    |
| 2085 | 
                        + )  | 
                    |
| 1785 | 2086 | 
                        result_ = runner.invoke(  | 
                    
| 1786 | 2087 | 
                        cli.derivepassphrase_vault, [], catch_exceptions=False  | 
                    
| 1787 | 2088 | 
                        )  | 
                    
| ... | ... | 
                      @@ -1791,14 +2092,21 @@ contents go here  | 
                  
| 1791 | 2092 | 
                        ), 'expected error exit and known error message'  | 
                    
| 1792 | 2093 | 
                         | 
                    
| 1793 | 2094 | 
                        def test_226a_no_passphrase_or_key(  | 
                    
| 1794 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 2095 | 
                        + self,  | 
                    |
| 1795 | 2096 | 
                        ) -> None:  | 
                    
| 1796 | 2097 | 
                        """Deriving a passphrase without a passphrase or key fails."""  | 
                    
| 1797 | 2098 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1798 | 
                        - with tests.isolated_config(  | 
                    |
| 2099 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2100 | 
                        + # with-statements.  | 
                    |
| 2101 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2102 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2103 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2104 | 
                        + stack.enter_context(  | 
                    |
| 2105 | 
                        + tests.isolated_config(  | 
                    |
| 1799 | 2106 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1800 | 2107 | 
                        runner=runner,  | 
                    
| 1801 | 
                        - ):  | 
                    |
| 2108 | 
                        + )  | 
                    |
| 2109 | 
                        + )  | 
                    |
| 1802 | 2110 | 
                        result_ = runner.invoke(  | 
                    
| 1803 | 2111 | 
                        cli.derivepassphrase_vault,  | 
                    
| 1804 | 2112 | 
                        ['--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -1810,7 +2118,7 @@ contents go here  | 
                  
| 1810 | 2118 | 
                        )  | 
                    
| 1811 | 2119 | 
                         | 
                    
| 1812 | 2120 | 
                        def test_230_config_directory_nonexistant(  | 
                    
| 1813 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 2121 | 
                        + self,  | 
                    |
| 1814 | 2122 | 
                        ) -> None:  | 
                    
| 1815 | 2123 | 
                        """Running without an existing config directory works.  | 
                    
| 1816 | 2124 | 
                         | 
                    
| ... | ... | 
                      @@ -1820,10 +2128,17 @@ contents go here  | 
                  
| 1820 | 2128 | 
                         | 
                    
| 1821 | 2129 | 
                        """  | 
                    
| 1822 | 2130 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1823 | 
                        - with tests.isolated_config(  | 
                    |
| 2131 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2132 | 
                        + # with-statements.  | 
                    |
| 2133 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2134 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2135 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2136 | 
                        + stack.enter_context(  | 
                    |
| 2137 | 
                        + tests.isolated_config(  | 
                    |
| 1824 | 2138 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1825 | 2139 | 
                        runner=runner,  | 
                    
| 1826 | 
                        - ):  | 
                    |
| 2140 | 
                        + )  | 
                    |
| 2141 | 
                        + )  | 
                    |
| 1827 | 2142 | 
                        with contextlib.suppress(FileNotFoundError):  | 
                    
| 1828 | 2143 | 
                        shutil.rmtree(cli._config_filename(subsystem=None))  | 
                    
| 1829 | 2144 | 
                        result_ = runner.invoke(  | 
                    
| ... | ... | 
                      @@ -1847,7 +2162,7 @@ contents go here  | 
                  
| 1847 | 2162 | 
                        }, 'config mismatch'  | 
                    
| 1848 | 2163 | 
                         | 
                    
| 1849 | 2164 | 
                        def test_230a_config_directory_not_a_file(  | 
                    
| 1850 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 2165 | 
                        + self,  | 
                    |
| 1851 | 2166 | 
                        ) -> None:  | 
                    
| 1852 | 2167 | 
                        """Erroring without an existing config directory errors normally.  | 
                    
| 1853 | 2168 | 
                         | 
                    
| ... | ... | 
                      @@ -1860,10 +2175,17 @@ contents go here  | 
                  
| 1860 | 2175 | 
                         | 
                    
| 1861 | 2176 | 
                        """  | 
                    
| 1862 | 2177 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1863 | 
                        - with tests.isolated_config(  | 
                    |
| 2178 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2179 | 
                        + # with-statements.  | 
                    |
| 2180 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2181 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2182 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2183 | 
                        + stack.enter_context(  | 
                    |
| 2184 | 
                        + tests.isolated_config(  | 
                    |
| 1864 | 2185 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1865 | 2186 | 
                        runner=runner,  | 
                    
| 1866 | 
                        - ):  | 
                    |
| 2187 | 
                        + )  | 
                    |
| 2188 | 
                        + )  | 
                    |
| 1867 | 2189 | 
                        save_config_ = cli._save_config  | 
                    
| 1868 | 2190 | 
                         | 
                    
| 1869 | 2191 | 
                        def obstruct_config_saving(*args: Any, **kwargs: Any) -> Any:  | 
                    
| ... | ... | 
                      @@ -1887,14 +2209,21 @@ contents go here  | 
                  
| 1887 | 2209 | 
                        )  | 
                    
| 1888 | 2210 | 
                         | 
                    
| 1889 | 2211 | 
                        def test_230b_store_config_custom_error(  | 
                    
| 1890 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 2212 | 
                        + self,  | 
                    |
| 1891 | 2213 | 
                        ) -> None:  | 
                    
| 1892 | 2214 | 
                        """Storing the configuration reacts even to weird errors."""  | 
                    
| 1893 | 2215 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 1894 | 
                        - with tests.isolated_config(  | 
                    |
| 2216 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2217 | 
                        + # with-statements.  | 
                    |
| 2218 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2219 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2220 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2221 | 
                        + stack.enter_context(  | 
                    |
| 2222 | 
                        + tests.isolated_config(  | 
                    |
| 1895 | 2223 | 
                        monkeypatch=monkeypatch,  | 
                    
| 1896 | 2224 | 
                        runner=runner,  | 
                    
| 1897 | 
                        - ):  | 
                    |
| 2225 | 
                        + )  | 
                    |
| 2226 | 
                        + )  | 
                    |
| 1898 | 2227 | 
                        custom_error = 'custom error message'  | 
                    
| 1899 | 2228 | 
                         | 
                    
| 1900 | 2229 | 
                        def raiser(config: Any) -> None:  | 
                    
| ... | ... | 
                      @@ -2014,7 +2343,6 @@ contents go here  | 
                  
| 2014 | 2343 | 
                        )  | 
                    
| 2015 | 2344 | 
                        def test_300_unicode_normalization_form_warning(  | 
                    
| 2016 | 2345 | 
                        self,  | 
                    
| 2017 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2018 | 2346 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 2019 | 2347 | 
                        main_config: str,  | 
                    
| 2020 | 2348 | 
                        command_line: list[str],  | 
                    
| ... | ... | 
                      @@ -2023,14 +2351,23 @@ contents go here  | 
                  
| 2023 | 2351 | 
                        ) -> None:  | 
                    
| 2024 | 2352 | 
                        """Using unnormalized Unicode passphrases warns."""  | 
                    
| 2025 | 2353 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 2026 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2354 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2355 | 
                        + # with-statements.  | 
                    |
| 2356 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2357 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2358 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2359 | 
                        + stack.enter_context(  | 
                    |
| 2360 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2027 | 2361 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2028 | 2362 | 
                        runner=runner,  | 
                    
| 2029 | 2363 | 
                                             vault_config={
                       | 
                    
| 2030 | 
                        -                'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()}
                       | 
                    |
| 2364 | 
                        +                        'services': {
                       | 
                    |
| 2365 | 
                        + DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()  | 
                    |
| 2366 | 
                        + }  | 
                    |
| 2031 | 2367 | 
                        },  | 
                    
| 2032 | 2368 | 
                        main_config_str=main_config,  | 
                    
| 2033 | 
                        - ):  | 
                    |
| 2369 | 
                        + )  | 
                    |
| 2370 | 
                        + )  | 
                    |
| 2034 | 2371 | 
                        result_ = runner.invoke(  | 
                    
| 2035 | 2372 | 
                        cli.derivepassphrase_vault,  | 
                    
| 2036 | 2373 | 
                        ['--debug', *command_line],  | 
                    
| ... | ... | 
                      @@ -2086,7 +2423,6 @@ contents go here  | 
                  
| 2086 | 2423 | 
                        )  | 
                    
| 2087 | 2424 | 
                        def test_301_unicode_normalization_form_error(  | 
                    
| 2088 | 2425 | 
                        self,  | 
                    
| 2089 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2090 | 2426 | 
                        main_config: str,  | 
                    
| 2091 | 2427 | 
                        command_line: list[str],  | 
                    
| 2092 | 2428 | 
                        input: str | None,  | 
                    
| ... | ... | 
                      @@ -2094,14 +2430,23 @@ contents go here  | 
                  
| 2094 | 2430 | 
                        ) -> None:  | 
                    
| 2095 | 2431 | 
                        """Using unknown Unicode normalization forms fails."""  | 
                    
| 2096 | 2432 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 2097 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2433 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2434 | 
                        + # with-statements.  | 
                    |
| 2435 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2436 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2437 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2438 | 
                        + stack.enter_context(  | 
                    |
| 2439 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2098 | 2440 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2099 | 2441 | 
                        runner=runner,  | 
                    
| 2100 | 2442 | 
                                             vault_config={
                       | 
                    
| 2101 | 
                        -                'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()}
                       | 
                    |
| 2443 | 
                        +                        'services': {
                       | 
                    |
| 2444 | 
                        + DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()  | 
                    |
| 2445 | 
                        + }  | 
                    |
| 2102 | 2446 | 
                        },  | 
                    
| 2103 | 2447 | 
                        main_config_str=main_config,  | 
                    
| 2104 | 
                        - ):  | 
                    |
| 2448 | 
                        + )  | 
                    |
| 2449 | 
                        + )  | 
                    |
| 2105 | 2450 | 
                        result_ = runner.invoke(  | 
                    
| 2106 | 2451 | 
                        cli.derivepassphrase_vault,  | 
                    
| 2107 | 2452 | 
                        command_line,  | 
                    
| ... | ... | 
                      @@ -2131,22 +2476,29 @@ contents go here  | 
                  
| 2131 | 2476 | 
                        )  | 
                    
| 2132 | 2477 | 
                        def test_301a_unicode_normalization_form_error_from_stored_config(  | 
                    
| 2133 | 2478 | 
                        self,  | 
                    
| 2134 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2135 | 2479 | 
                        command_line: list[str],  | 
                    
| 2136 | 2480 | 
                        ) -> None:  | 
                    
| 2137 | 2481 | 
                        """Using unknown Unicode normalization forms in the config fails."""  | 
                    
| 2138 | 2482 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 2139 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2483 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2484 | 
                        + # with-statements.  | 
                    |
| 2485 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2486 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2487 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2488 | 
                        + stack.enter_context(  | 
                    |
| 2489 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2140 | 2490 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2141 | 2491 | 
                        runner=runner,  | 
                    
| 2142 | 2492 | 
                                             vault_config={
                       | 
                    
| 2143 | 
                        -                'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()}
                       | 
                    |
| 2493 | 
                        +                        'services': {
                       | 
                    |
| 2494 | 
                        + DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()  | 
                    |
| 2495 | 
                        + }  | 
                    |
| 2144 | 2496 | 
                        },  | 
                    
| 2145 | 
                        -            main_config_str=textwrap.dedent("""
                       | 
                    |
| 2146 | 
                        - [vault]  | 
                    |
| 2147 | 
                        - default-unicode-normalization-form = 'XXX'  | 
                    |
| 2148 | 
                        - """),  | 
                    |
| 2149 | 
                        - ):  | 
                    |
| 2497 | 
                        + main_config_str=(  | 
                    |
| 2498 | 
                        + "[vault]\ndefault-unicode-normalization-form = 'XXX'\n"  | 
                    |
| 2499 | 
                        + ),  | 
                    |
| 2500 | 
                        + )  | 
                    |
| 2501 | 
                        + )  | 
                    |
| 2150 | 2502 | 
                        result_ = runner.invoke(  | 
                    
| 2151 | 2503 | 
                        cli.derivepassphrase_vault,  | 
                    
| 2152 | 2504 | 
                        command_line,  | 
                    
| ... | ... | 
                      @@ -2166,18 +2518,22 @@ contents go here  | 
                  
| 2166 | 2518 | 
                         | 
                    
| 2167 | 2519 | 
                        def test_310_bad_user_config_file(  | 
                    
| 2168 | 2520 | 
                        self,  | 
                    
| 2169 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2170 | 2521 | 
                        ) -> None:  | 
                    
| 2171 | 2522 | 
                        """Loading a user configuration file in an invalid format fails."""  | 
                    
| 2172 | 2523 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 2173 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2524 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2525 | 
                        + # with-statements.  | 
                    |
| 2526 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2527 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2528 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2529 | 
                        + stack.enter_context(  | 
                    |
| 2530 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2174 | 2531 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2175 | 2532 | 
                        runner=runner,  | 
                    
| 2176 | 2533 | 
                                             vault_config={'services': {}},
                       | 
                    
| 2177 | 
                        -            main_config_str=textwrap.dedent("""
                       | 
                    |
| 2178 | 
                        - This file is not valid TOML.  | 
                    |
| 2179 | 
                        - """),  | 
                    |
| 2180 | 
                        - ):  | 
                    |
| 2534 | 
                        + main_config_str='This file is not valid TOML.\n',  | 
                    |
| 2535 | 
                        + )  | 
                    |
| 2536 | 
                        + )  | 
                    |
| 2181 | 2537 | 
                        result_ = runner.invoke(  | 
                    
| 2182 | 2538 | 
                        cli.derivepassphrase_vault,  | 
                    
| 2183 | 2539 | 
                        ['--phrase', '--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -2191,15 +2547,21 @@ contents go here  | 
                  
| 2191 | 2547 | 
                         | 
                    
| 2192 | 2548 | 
                        def test_400_missing_af_unix_support(  | 
                    
| 2193 | 2549 | 
                        self,  | 
                    
| 2194 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2195 | 2550 | 
                        ) -> None:  | 
                    
| 2196 | 2551 | 
                        """Querying the SSH agent without `AF_UNIX` support fails."""  | 
                    
| 2197 | 2552 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 2198 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2553 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2554 | 
                        + # with-statements.  | 
                    |
| 2555 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2556 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2557 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2558 | 
                        + stack.enter_context(  | 
                    |
| 2559 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2199 | 2560 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2200 | 2561 | 
                        runner=runner,  | 
                    
| 2201 | 2562 | 
                                             vault_config={'global': {'phrase': 'abc'}, 'services': {}},
                       | 
                    
| 2202 | 
                        - ):  | 
                    |
| 2563 | 
                        + )  | 
                    |
| 2564 | 
                        + )  | 
                    |
| 2203 | 2565 | 
                        monkeypatch.setenv(  | 
                    
| 2204 | 2566 | 
                        'SSH_AUTH_SOCK', "the value doesn't even matter"  | 
                    
| 2205 | 2567 | 
                        )  | 
                    
| ... | ... | 
                      @@ -2238,30 +2600,43 @@ class TestCLIUtils:  | 
                  
| 2238 | 2600 | 
                        ],  | 
                    
| 2239 | 2601 | 
                        )  | 
                    
| 2240 | 2602 | 
                        def test_100_load_config(  | 
                    
| 2241 | 
                        - self, monkeypatch: pytest.MonkeyPatch, config: Any  | 
                    |
| 2603 | 
                        + self,  | 
                    |
| 2604 | 
                        + config: Any,  | 
                    |
| 2242 | 2605 | 
                        ) -> None:  | 
                    
| 2243 | 2606 | 
                        """`cli._load_config` works for valid configurations."""  | 
                    
| 2244 | 
                        - runner = click.testing.CliRunner()  | 
                    |
| 2245 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2246 | 
                        - monkeypatch=monkeypatch, runner=runner, vault_config=config  | 
                    |
| 2247 | 
                        - ):  | 
                    |
| 2607 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 2608 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2609 | 
                        + # with-statements.  | 
                    |
| 2610 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2611 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2612 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2613 | 
                        + stack.enter_context(  | 
                    |
| 2614 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2615 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 2616 | 
                        + runner=runner,  | 
                    |
| 2617 | 
                        + vault_config=config,  | 
                    |
| 2618 | 
                        + )  | 
                    |
| 2619 | 
                        + )  | 
                    |
| 2248 | 2620 | 
                        config_filename = cli._config_filename(subsystem='vault')  | 
                    
| 2249 | 2621 | 
                        with config_filename.open(encoding='UTF-8') as fileobj:  | 
                    
| 2250 | 2622 | 
                        assert json.load(fileobj) == config  | 
                    
| 2251 | 2623 | 
                        assert cli._load_config() == config  | 
                    
| 2252 | 2624 | 
                         | 
                    
| 2253 | 2625 | 
                        def test_110_save_bad_config(  | 
                    
| 2254 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 2626 | 
                        + self,  | 
                    |
| 2255 | 2627 | 
                        ) -> None:  | 
                    
| 2256 | 2628 | 
                        """`cli._save_config` fails for bad configurations."""  | 
                    
| 2257 | 
                        - runner = click.testing.CliRunner()  | 
                    |
| 2629 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 2258 | 2630 | 
                        # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    
| 2259 | 2631 | 
                        # with-statements.  | 
                    
| 2260 | 2632 | 
                        # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    
| 2261 | 2633 | 
                        with contextlib.ExitStack() as stack:  | 
                    
| 2634 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2262 | 2635 | 
                        stack.enter_context(  | 
                    
| 2263 | 2636 | 
                        tests.isolated_vault_config(  | 
                    
| 2264 | 
                        -                    monkeypatch=monkeypatch, runner=runner, vault_config={}
                       | 
                    |
| 2637 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 2638 | 
                        + runner=runner,  | 
                    |
| 2639 | 
                        +                    vault_config={},
                       | 
                    |
| 2265 | 2640 | 
                        )  | 
                    
| 2266 | 2641 | 
                        )  | 
                    
| 2267 | 2642 | 
                        stack.enter_context(  | 
                    
| ... | ... | 
                      @@ -2392,9 +2769,10 @@ Boo.  | 
                  
| 2392 | 2769 | 
                        ), 'expected known output'  | 
                    
| 2393 | 2770 | 
                         | 
                    
| 2394 | 2771 | 
                        def test_113_prompt_for_passphrase(  | 
                    
| 2395 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 2772 | 
                        + self,  | 
                    |
| 2396 | 2773 | 
                        ) -> None:  | 
                    
| 2397 | 2774 | 
                        """`cli._prompt_for_passphrase` works."""  | 
                    
| 2775 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 2398 | 2776 | 
                        monkeypatch.setattr(  | 
                    
| 2399 | 2777 | 
                        click,  | 
                    
| 2400 | 2778 | 
                        'prompt',  | 
                    
| ... | ... | 
                      @@ -2553,12 +2931,18 @@ Boo.  | 
                  
| 2553 | 2931 | 
                        )  | 
                    
| 2554 | 2932 | 
                        script = outfile.getvalue()  | 
                    
| 2555 | 2933 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 2556 | 
                        - monkeypatch = pytest.MonkeyPatch()  | 
                    |
| 2557 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 2558 | 
                        - runner=runner,  | 
                    |
| 2934 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 2935 | 
                        + # with-statements.  | 
                    |
| 2936 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 2937 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 2938 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 2939 | 
                        + stack.enter_context(  | 
                    |
| 2940 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2559 | 2941 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2942 | 
                        + runner=runner,  | 
                    |
| 2560 | 2943 | 
                                             vault_config={'services': {}},
                       | 
                    
| 2561 | 
                        - ):  | 
                    |
| 2944 | 
                        + )  | 
                    |
| 2945 | 
                        + )  | 
                    |
| 2562 | 2946 | 
                        for result_ in vault_config_exporter_shell_interpreter(script):  | 
                    
| 2563 | 2947 | 
                        result = tests.ReadableResult.parse(result_)  | 
                    
| 2564 | 2948 | 
                        assert result.clean_exit()  | 
                    
| ... | ... | 
                      @@ -2806,19 +3190,25 @@ Boo.  | 
                  
| 2806 | 3190 | 
                        )  | 
                    
| 2807 | 3191 | 
                        def test_203_repeated_config_deletion(  | 
                    
| 2808 | 3192 | 
                        self,  | 
                    
| 2809 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2810 | 3193 | 
                        command_line: list[str],  | 
                    
| 2811 | 3194 | 
                        config: _types.VaultConfig,  | 
                    
| 2812 | 3195 | 
                        result_config: _types.VaultConfig,  | 
                    
| 2813 | 3196 | 
                        ) -> None:  | 
                    
| 2814 | 3197 | 
                        """Repeatedly removing the same parts of a configuration works."""  | 
                    
| 2815 | 
                        - runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 2816 | 3198 | 
                        for start_config in [config, result_config]:  | 
                    
| 2817 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 3199 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 3200 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3201 | 
                        + # with-statements.  | 
                    |
| 3202 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3203 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3204 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3205 | 
                        + stack.enter_context(  | 
                    |
| 3206 | 
                        + tests.isolated_vault_config(  | 
                    |
| 2818 | 3207 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2819 | 3208 | 
                        runner=runner,  | 
                    
| 2820 | 3209 | 
                        vault_config=start_config,  | 
                    
| 2821 | 
                        - ):  | 
                    |
| 3210 | 
                        + )  | 
                    |
| 3211 | 
                        + )  | 
                    |
| 2822 | 3212 | 
                        result_ = runner.invoke(  | 
                    
| 2823 | 3213 | 
                        cli.derivepassphrase_vault,  | 
                    
| 2824 | 3214 | 
                        command_line,  | 
                    
| ... | ... | 
                      @@ -2863,12 +3253,11 @@ Boo.  | 
                  
| 2863 | 3253 | 
                             @pytest.mark.parametrize('conn_hint', ['none', 'socket', 'client'])
                       | 
                    
| 2864 | 3254 | 
                        def test_227_get_suitable_ssh_keys(  | 
                    
| 2865 | 3255 | 
                        self,  | 
                    
| 2866 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2867 | 3256 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 2868 | 3257 | 
                        conn_hint: str,  | 
                    
| 2869 | 3258 | 
                        ) -> None:  | 
                    
| 2870 | 3259 | 
                        """`cli._get_suitable_ssh_keys` works."""  | 
                    
| 2871 | 
                        - with monkeypatch.context():  | 
                    |
| 3260 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 2872 | 3261 | 
                                     monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket)
                       | 
                    
| 2873 | 3262 | 
                        monkeypatch.setattr(  | 
                    
| 2874 | 3263 | 
                        ssh_agent.SSHAgentClient, 'list_keys', tests.list_keys  | 
                    
| ... | ... | 
                      @@ -2899,7 +3288,6 @@ Boo.  | 
                  
| 2899 | 3288 | 
                         | 
                    
| 2900 | 3289 | 
                        def test_400_key_to_phrase(  | 
                    
| 2901 | 3290 | 
                        self,  | 
                    
| 2902 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 2903 | 3291 | 
                        skip_if_no_af_unix_support: None,  | 
                    
| 2904 | 3292 | 
                        ssh_agent_client_with_test_keys_loaded: ssh_agent.SSHAgentClient,  | 
                    
| 2905 | 3293 | 
                        ) -> None:  | 
                    
| ... | ... | 
                      @@ -2924,8 +3312,11 @@ Boo.  | 
                  
| 2924 | 3312 | 
                        raise ssh_agent.TrailingDataError()  | 
                    
| 2925 | 3313 | 
                         | 
                    
| 2926 | 3314 | 
                        del skip_if_no_af_unix_support  | 
                    
| 3315 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 2927 | 3316 | 
                        monkeypatch.setattr(ssh_agent.SSHAgentClient, 'sign', fail)  | 
                    
| 2928 | 
                        - loaded_keys = list(ssh_agent_client_with_test_keys_loaded.list_keys())  | 
                    |
| 3317 | 
                        + loaded_keys = list(  | 
                    |
| 3318 | 
                        + ssh_agent_client_with_test_keys_loaded.list_keys()  | 
                    |
| 3319 | 
                        + )  | 
                    |
| 2929 | 3320 | 
                        loaded_key = base64.standard_b64encode(loaded_keys[0][0])  | 
                    
| 2930 | 3321 | 
                        with monkeypatch.context() as mp:  | 
                    
| 2931 | 3322 | 
                        mp.setattr(  | 
                    
| ... | ... | 
                      @@ -2933,7 +3324,9 @@ Boo.  | 
                  
| 2933 | 3324 | 
                        'list_keys',  | 
                    
| 2934 | 3325 | 
                        lambda *_a, **_kw: [],  | 
                    
| 2935 | 3326 | 
                        )  | 
                    
| 2936 | 
                        - with pytest.raises(ErrCallback, match='not loaded into the agent'):  | 
                    |
| 3327 | 
                        + with pytest.raises(  | 
                    |
| 3328 | 
                        + ErrCallback, match='not loaded into the agent'  | 
                    |
| 3329 | 
                        + ):  | 
                    |
| 2937 | 3330 | 
                        cli._key_to_phrase(loaded_key, error_callback=err)  | 
                    
| 2938 | 3331 | 
                        with monkeypatch.context() as mp:  | 
                    
| 2939 | 3332 | 
                        mp.setattr(ssh_agent.SSHAgentClient, 'list_keys', fail)  | 
                    
| ... | ... | 
                      @@ -2988,13 +3381,20 @@ Boo.  | 
                  
| 2988 | 3381 | 
                        class TestCLITransition:  | 
                    
| 2989 | 3382 | 
                        """Transition tests for the command-line interface up to v1.0."""  | 
                    
| 2990 | 3383 | 
                         | 
                    
| 2991 | 
                        - def test_100_help_output(self, monkeypatch: pytest.MonkeyPatch) -> None:  | 
                    |
| 3384 | 
                        + def test_100_help_output(self) -> None:  | 
                    |
| 2992 | 3385 | 
                        """The top-level help text mentions subcommands."""  | 
                    
| 2993 | 3386 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 2994 | 
                        - with tests.isolated_config(  | 
                    |
| 3387 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3388 | 
                        + # with-statements.  | 
                    |
| 3389 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3390 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3391 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3392 | 
                        + stack.enter_context(  | 
                    |
| 3393 | 
                        + tests.isolated_config(  | 
                    |
| 2995 | 3394 | 
                        monkeypatch=monkeypatch,  | 
                    
| 2996 | 3395 | 
                        runner=runner,  | 
                    
| 2997 | 
                        - ):  | 
                    |
| 3396 | 
                        + )  | 
                    |
| 3397 | 
                        + )  | 
                    |
| 2998 | 3398 | 
                        result_ = runner.invoke(  | 
                    
| 2999 | 3399 | 
                        cli.derivepassphrase, ['--help'], catch_exceptions=False  | 
                    
| 3000 | 3400 | 
                        )  | 
                    
| ... | ... | 
                      @@ -3004,14 +3404,21 @@ class TestCLITransition:  | 
                  
| 3004 | 3404 | 
                        ), 'expected clean exit, and known help text'  | 
                    
| 3005 | 3405 | 
                         | 
                    
| 3006 | 3406 | 
                        def test_101_help_output_export(  | 
                    
| 3007 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 3407 | 
                        + self,  | 
                    |
| 3008 | 3408 | 
                        ) -> None:  | 
                    
| 3009 | 3409 | 
                        """The "export" subcommand help text mentions subcommands."""  | 
                    
| 3010 | 3410 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3011 | 
                        - with tests.isolated_config(  | 
                    |
| 3411 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3412 | 
                        + # with-statements.  | 
                    |
| 3413 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3414 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3415 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3416 | 
                        + stack.enter_context(  | 
                    |
| 3417 | 
                        + tests.isolated_config(  | 
                    |
| 3012 | 3418 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3013 | 3419 | 
                        runner=runner,  | 
                    
| 3014 | 
                        - ):  | 
                    |
| 3420 | 
                        + )  | 
                    |
| 3421 | 
                        + )  | 
                    |
| 3015 | 3422 | 
                        result_ = runner.invoke(  | 
                    
| 3016 | 3423 | 
                        cli.derivepassphrase,  | 
                    
| 3017 | 3424 | 
                        ['export', '--help'],  | 
                    
| ... | ... | 
                      @@ -3023,14 +3430,21 @@ class TestCLITransition:  | 
                  
| 3023 | 3430 | 
                        ), 'expected clean exit, and known help text'  | 
                    
| 3024 | 3431 | 
                         | 
                    
| 3025 | 3432 | 
                        def test_102_help_output_export_vault(  | 
                    
| 3026 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 3433 | 
                        + self,  | 
                    |
| 3027 | 3434 | 
                        ) -> None:  | 
                    
| 3028 | 3435 | 
                        """The "export vault" subcommand help text has known content."""  | 
                    
| 3029 | 3436 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3030 | 
                        - with tests.isolated_config(  | 
                    |
| 3437 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3438 | 
                        + # with-statements.  | 
                    |
| 3439 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3440 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3441 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3442 | 
                        + stack.enter_context(  | 
                    |
| 3443 | 
                        + tests.isolated_config(  | 
                    |
| 3031 | 3444 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3032 | 3445 | 
                        runner=runner,  | 
                    
| 3033 | 
                        - ):  | 
                    |
| 3446 | 
                        + )  | 
                    |
| 3447 | 
                        + )  | 
                    |
| 3034 | 3448 | 
                        result_ = runner.invoke(  | 
                    
| 3035 | 3449 | 
                        cli.derivepassphrase,  | 
                    
| 3036 | 3450 | 
                        ['export', 'vault', '--help'],  | 
                    
| ... | ... | 
                      @@ -3042,14 +3456,21 @@ class TestCLITransition:  | 
                  
| 3042 | 3456 | 
                        ), 'expected clean exit, and known help text'  | 
                    
| 3043 | 3457 | 
                         | 
                    
| 3044 | 3458 | 
                        def test_103_help_output_vault(  | 
                    
| 3045 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 3459 | 
                        + self,  | 
                    |
| 3046 | 3460 | 
                        ) -> None:  | 
                    
| 3047 | 3461 | 
                        """The "vault" subcommand help text has known content."""  | 
                    
| 3048 | 3462 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3049 | 
                        - with tests.isolated_config(  | 
                    |
| 3463 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3464 | 
                        + # with-statements.  | 
                    |
| 3465 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3466 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3467 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3468 | 
                        + stack.enter_context(  | 
                    |
| 3469 | 
                        + tests.isolated_config(  | 
                    |
| 3050 | 3470 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3051 | 3471 | 
                        runner=runner,  | 
                    
| 3052 | 
                        - ):  | 
                    |
| 3472 | 
                        + )  | 
                    |
| 3473 | 
                        + )  | 
                    |
| 3053 | 3474 | 
                        result_ = runner.invoke(  | 
                    
| 3054 | 3475 | 
                        cli.derivepassphrase,  | 
                    
| 3055 | 3476 | 
                        ['vault', '--help'],  | 
                    
| ... | ... | 
                      @@ -3083,11 +3504,22 @@ class TestCLITransition:  | 
                  
| 3083 | 3504 | 
                        ],  | 
                    
| 3084 | 3505 | 
                        )  | 
                    
| 3085 | 3506 | 
                        def test_110_load_config_backup(  | 
                    
| 3086 | 
                        - self, monkeypatch: pytest.MonkeyPatch, config: Any  | 
                    |
| 3507 | 
                        + self,  | 
                    |
| 3508 | 
                        + config: Any,  | 
                    |
| 3087 | 3509 | 
                        ) -> None:  | 
                    
| 3088 | 3510 | 
                        """Loading the old settings file works."""  | 
                    
| 3089 | 
                        - runner = click.testing.CliRunner()  | 
                    |
| 3090 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 3511 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 3512 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3513 | 
                        + # with-statements.  | 
                    |
| 3514 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3515 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3516 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3517 | 
                        + stack.enter_context(  | 
                    |
| 3518 | 
                        + tests.isolated_config(  | 
                    |
| 3519 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 3520 | 
                        + runner=runner,  | 
                    |
| 3521 | 
                        + )  | 
                    |
| 3522 | 
                        + )  | 
                    |
| 3091 | 3523 | 
                        cli._config_filename(subsystem='old settings.json').write_text(  | 
                    
| 3092 | 3524 | 
                        json.dumps(config, indent=2) + '\n', encoding='UTF-8'  | 
                    
| 3093 | 3525 | 
                        )  | 
                    
| ... | ... | 
                      @@ -3113,11 +3545,22 @@ class TestCLITransition:  | 
                  
| 3113 | 3545 | 
                        ],  | 
                    
| 3114 | 3546 | 
                        )  | 
                    
| 3115 | 3547 | 
                        def test_111_migrate_config(  | 
                    
| 3116 | 
                        - self, monkeypatch: pytest.MonkeyPatch, config: Any  | 
                    |
| 3548 | 
                        + self,  | 
                    |
| 3549 | 
                        + config: Any,  | 
                    |
| 3117 | 3550 | 
                        ) -> None:  | 
                    
| 3118 | 3551 | 
                        """Migrating the old settings file works."""  | 
                    
| 3119 | 
                        - runner = click.testing.CliRunner()  | 
                    |
| 3120 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 3552 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 3553 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3554 | 
                        + # with-statements.  | 
                    |
| 3555 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3556 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3557 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3558 | 
                        + stack.enter_context(  | 
                    |
| 3559 | 
                        + tests.isolated_config(  | 
                    |
| 3560 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 3561 | 
                        + runner=runner,  | 
                    |
| 3562 | 
                        + )  | 
                    |
| 3563 | 
                        + )  | 
                    |
| 3121 | 3564 | 
                        cli._config_filename(subsystem='old settings.json').write_text(  | 
                    
| 3122 | 3565 | 
                        json.dumps(config, indent=2) + '\n', encoding='UTF-8'  | 
                    
| 3123 | 3566 | 
                        )  | 
                    
| ... | ... | 
                      @@ -3143,11 +3586,22 @@ class TestCLITransition:  | 
                  
| 3143 | 3586 | 
                        ],  | 
                    
| 3144 | 3587 | 
                        )  | 
                    
| 3145 | 3588 | 
                        def test_112_migrate_config_error(  | 
                    
| 3146 | 
                        - self, monkeypatch: pytest.MonkeyPatch, config: Any  | 
                    |
| 3589 | 
                        + self,  | 
                    |
| 3590 | 
                        + config: Any,  | 
                    |
| 3147 | 3591 | 
                        ) -> None:  | 
                    
| 3148 | 3592 | 
                        """Migrating the old settings file atop a directory fails."""  | 
                    
| 3149 | 
                        - runner = click.testing.CliRunner()  | 
                    |
| 3150 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 3593 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 3594 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3595 | 
                        + # with-statements.  | 
                    |
| 3596 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3597 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3598 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3599 | 
                        + stack.enter_context(  | 
                    |
| 3600 | 
                        + tests.isolated_config(  | 
                    |
| 3601 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 3602 | 
                        + runner=runner,  | 
                    |
| 3603 | 
                        + )  | 
                    |
| 3604 | 
                        + )  | 
                    |
| 3151 | 3605 | 
                        cli._config_filename(subsystem='old settings.json').write_text(  | 
                    
| 3152 | 3606 | 
                        json.dumps(config, indent=2) + '\n', encoding='UTF-8'  | 
                    
| 3153 | 3607 | 
                        )  | 
                    
| ... | ... | 
                      @@ -3179,11 +3633,22 @@ class TestCLITransition:  | 
                  
| 3179 | 3633 | 
                        ],  | 
                    
| 3180 | 3634 | 
                        )  | 
                    
| 3181 | 3635 | 
                        def test_113_migrate_config_error_bad_config_value(  | 
                    
| 3182 | 
                        - self, monkeypatch: pytest.MonkeyPatch, config: Any  | 
                    |
| 3636 | 
                        + self,  | 
                    |
| 3637 | 
                        + config: Any,  | 
                    |
| 3183 | 3638 | 
                        ) -> None:  | 
                    
| 3184 | 3639 | 
                        """Migrating an invalid old settings file fails."""  | 
                    
| 3185 | 
                        - runner = click.testing.CliRunner()  | 
                    |
| 3186 | 
                        - with tests.isolated_config(monkeypatch=monkeypatch, runner=runner):  | 
                    |
| 3640 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 3641 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3642 | 
                        + # with-statements.  | 
                    |
| 3643 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3644 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3645 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3646 | 
                        + stack.enter_context(  | 
                    |
| 3647 | 
                        + tests.isolated_config(  | 
                    |
| 3648 | 
                        + monkeypatch=monkeypatch,  | 
                    |
| 3649 | 
                        + runner=runner,  | 
                    |
| 3650 | 
                        + )  | 
                    |
| 3651 | 
                        + )  | 
                    |
| 3187 | 3652 | 
                        cli._config_filename(subsystem='old settings.json').write_text(  | 
                    
| 3188 | 3653 | 
                        json.dumps(config, indent=2) + '\n', encoding='UTF-8'  | 
                    
| 3189 | 3654 | 
                        )  | 
                    
| ... | ... | 
                      @@ -3192,18 +3657,24 @@ class TestCLITransition:  | 
                  
| 3192 | 3657 | 
                         | 
                    
| 3193 | 3658 | 
                        def test_200_forward_export_vault_path_parameter(  | 
                    
| 3194 | 3659 | 
                        self,  | 
                    
| 3195 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 3196 | 3660 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 3197 | 3661 | 
                        ) -> None:  | 
                    
| 3198 | 3662 | 
                        """Forwarding arguments from "export" to "export vault" works."""  | 
                    
| 3199 | 3663 | 
                                 pytest.importorskip('cryptography', minversion='38.0')
                       | 
                    
| 3200 | 3664 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3201 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 3665 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3666 | 
                        + # with-statements.  | 
                    |
| 3667 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3668 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3669 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3670 | 
                        + stack.enter_context(  | 
                    |
| 3671 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 3202 | 3672 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3203 | 3673 | 
                        runner=runner,  | 
                    
| 3204 | 3674 | 
                        vault_config=tests.VAULT_V03_CONFIG,  | 
                    
| 3205 | 3675 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 3206 | 
                        - ):  | 
                    |
| 3676 | 
                        + )  | 
                    |
| 3677 | 
                        + )  | 
                    |
| 3207 | 3678 | 
                                     monkeypatch.setenv('VAULT_KEY', tests.VAULT_MASTER_KEY)
                       | 
                    
| 3208 | 3679 | 
                        result_ = runner.invoke(  | 
                    
| 3209 | 3680 | 
                        cli.derivepassphrase,  | 
                    
| ... | ... | 
                      @@ -3221,16 +3692,22 @@ class TestCLITransition:  | 
                  
| 3221 | 3692 | 
                         | 
                    
| 3222 | 3693 | 
                        def test_201_forward_export_vault_empty_commandline(  | 
                    
| 3223 | 3694 | 
                        self,  | 
                    
| 3224 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 3225 | 3695 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 3226 | 3696 | 
                        ) -> None:  | 
                    
| 3227 | 3697 | 
                        """Deferring from "export" to "export vault" works."""  | 
                    
| 3228 | 3698 | 
                                 pytest.importorskip('cryptography', minversion='38.0')
                       | 
                    
| 3229 | 3699 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3230 | 
                        - with tests.isolated_config(  | 
                    |
| 3700 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3701 | 
                        + # with-statements.  | 
                    |
| 3702 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3703 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3704 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3705 | 
                        + stack.enter_context(  | 
                    |
| 3706 | 
                        + tests.isolated_config(  | 
                    |
| 3231 | 3707 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3232 | 3708 | 
                        runner=runner,  | 
                    
| 3233 | 
                        - ):  | 
                    |
| 3709 | 
                        + )  | 
                    |
| 3710 | 
                        + )  | 
                    |
| 3234 | 3711 | 
                        result_ = runner.invoke(  | 
                    
| 3235 | 3712 | 
                        cli.derivepassphrase,  | 
                    
| 3236 | 3713 | 
                        ['export'],  | 
                    
| ... | ... | 
                      @@ -3251,19 +3728,27 @@ class TestCLITransition:  | 
                  
| 3251 | 3728 | 
                        )  | 
                    
| 3252 | 3729 | 
                        def test_210_forward_vault_disable_character_set(  | 
                    
| 3253 | 3730 | 
                        self,  | 
                    
| 3254 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 3255 | 3731 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 3256 | 3732 | 
                        charset_name: str,  | 
                    
| 3257 | 3733 | 
                        ) -> None:  | 
                    
| 3258 | 3734 | 
                        """Forwarding arguments from top-level to "vault" works."""  | 
                    
| 3259 | 
                        - monkeypatch.setattr(cli, '_prompt_for_passphrase', tests.auto_prompt)  | 
                    |
| 3260 | 3735 | 
                                 option = f'--{charset_name}'
                       | 
                    
| 3261 | 3736 | 
                                 charset = vault.Vault._CHARSETS[charset_name].decode('ascii')
                       | 
                    
| 3262 | 3737 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3263 | 
                        - with tests.isolated_config(  | 
                    |
| 3738 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3739 | 
                        + # with-statements.  | 
                    |
| 3740 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3741 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3742 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3743 | 
                        + stack.enter_context(  | 
                    |
| 3744 | 
                        + tests.isolated_config(  | 
                    |
| 3264 | 3745 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3265 | 3746 | 
                        runner=runner,  | 
                    
| 3266 | 
                        - ):  | 
                    |
| 3747 | 
                        + )  | 
                    |
| 3748 | 
                        + )  | 
                    |
| 3749 | 
                        + monkeypatch.setattr(  | 
                    |
| 3750 | 
                        + cli, '_prompt_for_passphrase', tests.auto_prompt  | 
                    |
| 3751 | 
                        + )  | 
                    |
| 3267 | 3752 | 
                        result_ = runner.invoke(  | 
                    
| 3268 | 3753 | 
                        cli.derivepassphrase,  | 
                    
| 3269 | 3754 | 
                        [option, '0', '-p', '--', DUMMY_SERVICE],  | 
                    
| ... | ... | 
                      @@ -3285,15 +3770,21 @@ class TestCLITransition:  | 
                  
| 3285 | 3770 | 
                         | 
                    
| 3286 | 3771 | 
                        def test_211_forward_vault_empty_command_line(  | 
                    
| 3287 | 3772 | 
                        self,  | 
                    
| 3288 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 3289 | 3773 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 3290 | 3774 | 
                        ) -> None:  | 
                    
| 3291 | 3775 | 
                        """Deferring from top-level to "vault" works."""  | 
                    
| 3292 | 3776 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3293 | 
                        - with tests.isolated_config(  | 
                    |
| 3777 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3778 | 
                        + # with-statements.  | 
                    |
| 3779 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3780 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3781 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3782 | 
                        + stack.enter_context(  | 
                    |
| 3783 | 
                        + tests.isolated_config(  | 
                    |
| 3294 | 3784 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3295 | 3785 | 
                        runner=runner,  | 
                    
| 3296 | 
                        - ):  | 
                    |
| 3786 | 
                        + )  | 
                    |
| 3787 | 
                        + )  | 
                    |
| 3297 | 3788 | 
                        result_ = runner.invoke(  | 
                    
| 3298 | 3789 | 
                        cli.derivepassphrase,  | 
                    
| 3299 | 3790 | 
                        [],  | 
                    
| ... | ... | 
                      @@ -3313,16 +3804,22 @@ class TestCLITransition:  | 
                  
| 3313 | 3804 | 
                         | 
                    
| 3314 | 3805 | 
                        def test_300_export_using_old_config_file(  | 
                    
| 3315 | 3806 | 
                        self,  | 
                    
| 3316 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 3317 | 3807 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 3318 | 3808 | 
                        ) -> None:  | 
                    
| 3319 | 3809 | 
                        """Exporting from (and migrating) the old settings file works."""  | 
                    
| 3320 | 3810 | 
                        caplog.set_level(logging.INFO)  | 
                    
| 3321 | 3811 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3322 | 
                        - with tests.isolated_config(  | 
                    |
| 3812 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3813 | 
                        + # with-statements.  | 
                    |
| 3814 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3815 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3816 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3817 | 
                        + stack.enter_context(  | 
                    |
| 3818 | 
                        + tests.isolated_config(  | 
                    |
| 3323 | 3819 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3324 | 3820 | 
                        runner=runner,  | 
                    
| 3325 | 
                        - ):  | 
                    |
| 3821 | 
                        + )  | 
                    |
| 3822 | 
                        + )  | 
                    |
| 3326 | 3823 | 
                        cli._config_filename(subsystem='old settings.json').write_text(  | 
                    
| 3327 | 3824 | 
                        json.dumps(  | 
                    
| 3328 | 3825 | 
                                             {'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}},
                       | 
                    
| ... | ... | 
                      @@ -3347,15 +3844,21 @@ class TestCLITransition:  | 
                  
| 3347 | 3844 | 
                         | 
                    
| 3348 | 3845 | 
                        def test_300a_export_using_old_config_file_migration_error(  | 
                    
| 3349 | 3846 | 
                        self,  | 
                    
| 3350 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 3351 | 3847 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 3352 | 3848 | 
                        ) -> None:  | 
                    
| 3353 | 3849 | 
                        """Exporting from (and not migrating) the old settings file fails."""  | 
                    
| 3354 | 3850 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 3355 | 
                        - with tests.isolated_config(  | 
                    |
| 3851 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3852 | 
                        + # with-statements.  | 
                    |
| 3853 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3854 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3855 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3856 | 
                        + stack.enter_context(  | 
                    |
| 3857 | 
                        + tests.isolated_config(  | 
                    |
| 3356 | 3858 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3357 | 3859 | 
                        runner=runner,  | 
                    
| 3358 | 
                        - ):  | 
                    |
| 3860 | 
                        + )  | 
                    |
| 3861 | 
                        + )  | 
                    |
| 3359 | 3862 | 
                        cli._config_filename(subsystem='old settings.json').write_text(  | 
                    
| 3360 | 3863 | 
                        json.dumps(  | 
                    
| 3361 | 3864 | 
                                             {'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}},
                       | 
                    
| ... | ... | 
                      @@ -3390,16 +3893,22 @@ class TestCLITransition:  | 
                  
| 3390 | 3893 | 
                         | 
                    
| 3391 | 3894 | 
                        def test_400_completion_service_name_old_config_file(  | 
                    
| 3392 | 3895 | 
                        self,  | 
                    
| 3393 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 3394 | 3896 | 
                        ) -> None:  | 
                    
| 3395 | 3897 | 
                        """Completing service names from the old settings file works."""  | 
                    
| 3396 | 
                        - runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 3397 | 3898 | 
                                 config = {'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS.copy()}}
                       | 
                    
| 3398 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 3899 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 3900 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 3901 | 
                        + # with-statements.  | 
                    |
| 3902 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 3903 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 3904 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 3905 | 
                        + stack.enter_context(  | 
                    |
| 3906 | 
                        + tests.isolated_vault_config(  | 
                    |
| 3399 | 3907 | 
                        monkeypatch=monkeypatch,  | 
                    
| 3400 | 3908 | 
                        runner=runner,  | 
                    
| 3401 | 3909 | 
                        vault_config=config,  | 
                    
| 3402 | 
                        - ):  | 
                    |
| 3910 | 
                        + )  | 
                    |
| 3911 | 
                        + )  | 
                    |
| 3403 | 3912 | 
                        old_name = cli._config_filename(subsystem='old settings.json')  | 
                    
| 3404 | 3913 | 
                        new_name = cli._config_filename(subsystem='vault')  | 
                    
| 3405 | 3914 | 
                        old_name.unlink(missing_ok=True)  | 
                    
| ... | ... | 
                      @@ -4241,18 +4750,24 @@ class TestShellCompletion:  | 
                  
| 4241 | 4750 | 
                        )  | 
                    
| 4242 | 4751 | 
                        def test_203_service_names(  | 
                    
| 4243 | 4752 | 
                        self,  | 
                    
| 4244 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 4245 | 4753 | 
                        config: _types.VaultConfig,  | 
                    
| 4246 | 4754 | 
                        incomplete: str,  | 
                    
| 4247 | 4755 | 
                        completions: AbstractSet[str],  | 
                    
| 4248 | 4756 | 
                        ) -> None:  | 
                    
| 4249 | 4757 | 
                        """Our completion machinery works for vault service names."""  | 
                    
| 4250 | 4758 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 4251 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 4759 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 4760 | 
                        + # with-statements.  | 
                    |
| 4761 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 4762 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 4763 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 4764 | 
                        + stack.enter_context(  | 
                    |
| 4765 | 
                        + tests.isolated_vault_config(  | 
                    |
| 4252 | 4766 | 
                        monkeypatch=monkeypatch,  | 
                    
| 4253 | 4767 | 
                        runner=runner,  | 
                    
| 4254 | 4768 | 
                        vault_config=config,  | 
                    
| 4255 | 
                        - ):  | 
                    |
| 4769 | 
                        + )  | 
                    |
| 4770 | 
                        + )  | 
                    |
| 4256 | 4771 | 
                        comp = self.Completions(['vault'], incomplete)  | 
                    
| 4257 | 4772 | 
                        assert frozenset(comp.get_words()) == completions  | 
                    
| 4258 | 4773 | 
                         | 
                    
| ... | ... | 
                      @@ -4359,7 +4874,6 @@ class TestShellCompletion:  | 
                  
| 4359 | 4874 | 
                        )  | 
                    
| 4360 | 4875 | 
                        def test_300_shell_completion_formatting(  | 
                    
| 4361 | 4876 | 
                        self,  | 
                    
| 4362 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 4363 | 4877 | 
                        shell: str,  | 
                    
| 4364 | 4878 | 
                        format_func: Callable[[click.shell_completion.CompletionItem], str],  | 
                    
| 4365 | 4879 | 
                        config: _types.VaultConfig,  | 
                    
| ... | ... | 
                      @@ -4373,11 +4887,18 @@ class TestShellCompletion:  | 
                  
| 4373 | 4887 | 
                        ) -> None:  | 
                    
| 4374 | 4888 | 
                        """Custom completion functions work for all shells."""  | 
                    
| 4375 | 4889 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 4376 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 4890 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 4891 | 
                        + # with-statements.  | 
                    |
| 4892 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 4893 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 4894 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 4895 | 
                        + stack.enter_context(  | 
                    |
| 4896 | 
                        + tests.isolated_vault_config(  | 
                    |
| 4377 | 4897 | 
                        monkeypatch=monkeypatch,  | 
                    
| 4378 | 4898 | 
                        runner=runner,  | 
                    
| 4379 | 4899 | 
                        vault_config=config,  | 
                    
| 4380 | 
                        - ):  | 
                    |
| 4900 | 
                        + )  | 
                    |
| 4901 | 
                        + )  | 
                    |
| 4381 | 4902 | 
                        expected_items = [assertable_item(item) for item in results]  | 
                    
| 4382 | 4903 | 
                        expected_string = '\n'.join(  | 
                    
| 4383 | 4904 | 
                        format_func(completion_item(item)) for item in results  | 
                    
| ... | ... | 
                      @@ -4566,7 +5087,6 @@ class TestShellCompletion:  | 
                  
| 4566 | 5087 | 
                        )  | 
                    
| 4567 | 5088 | 
                        def test_400_incompletable_service_names(  | 
                    
| 4568 | 5089 | 
                        self,  | 
                    
| 4569 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 4570 | 5090 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 4571 | 5091 | 
                        mode: Literal['config', 'import'],  | 
                    
| 4572 | 5092 | 
                        config: _types.VaultConfig,  | 
                    
| ... | ... | 
                      @@ -4575,13 +5095,20 @@ class TestShellCompletion:  | 
                  
| 4575 | 5095 | 
                        completions: AbstractSet[str],  | 
                    
| 4576 | 5096 | 
                        ) -> None:  | 
                    
| 4577 | 5097 | 
                        """Completion skips incompletable items."""  | 
                    
| 4578 | 
                        - runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 4579 | 5098 | 
                                 vault_config = config if mode == 'config' else {'services': {}}
                       | 
                    
| 4580 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 5099 | 
                        + runner = click.testing.CliRunner(mix_stderr=False)  | 
                    |
| 5100 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 5101 | 
                        + # with-statements.  | 
                    |
| 5102 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 5103 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 5104 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 5105 | 
                        + stack.enter_context(  | 
                    |
| 5106 | 
                        + tests.isolated_vault_config(  | 
                    |
| 4581 | 5107 | 
                        monkeypatch=monkeypatch,  | 
                    
| 4582 | 5108 | 
                        runner=runner,  | 
                    
| 4583 | 5109 | 
                        vault_config=vault_config,  | 
                    
| 4584 | 
                        - ):  | 
                    |
| 5110 | 
                        + )  | 
                    |
| 5111 | 
                        + )  | 
                    |
| 4585 | 5112 | 
                        if mode == 'config':  | 
                    
| 4586 | 5113 | 
                        result_ = runner.invoke(  | 
                    
| 4587 | 5114 | 
                        cli.derivepassphrase_vault,  | 
                    
| ... | ... | 
                      @@ -4609,15 +5136,23 @@ class TestShellCompletion:  | 
                  
| 4609 | 5136 | 
                         | 
                    
| 4610 | 5137 | 
                        def test_410a_service_name_exceptions_not_found(  | 
                    
| 4611 | 5138 | 
                        self,  | 
                    
| 4612 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 4613 | 5139 | 
                        ) -> None:  | 
                    
| 4614 | 5140 | 
                        """Service name completion quietly fails on missing configuration."""  | 
                    
| 4615 | 5141 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 4616 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 5142 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 5143 | 
                        + # with-statements.  | 
                    |
| 5144 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 5145 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 5146 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 5147 | 
                        + stack.enter_context(  | 
                    |
| 5148 | 
                        + tests.isolated_vault_config(  | 
                    |
| 4617 | 5149 | 
                        monkeypatch=monkeypatch,  | 
                    
| 4618 | 5150 | 
                        runner=runner,  | 
                    
| 4619 | 
                        -            vault_config={'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}},
                       | 
                    |
| 4620 | 
                        - ):  | 
                    |
| 5151 | 
                        +                    vault_config={
                       | 
                    |
| 5152 | 
                        +                        'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}
                       | 
                    |
| 5153 | 
                        + },  | 
                    |
| 5154 | 
                        + )  | 
                    |
| 5155 | 
                        + )  | 
                    |
| 4621 | 5156 | 
                        cli._config_filename(subsystem='vault').unlink(missing_ok=True)  | 
                    
| 4622 | 5157 | 
                        assert not cli._shell_complete_service(  | 
                    
| 4623 | 5158 | 
                        click.Context(cli.derivepassphrase),  | 
                    
| ... | ... | 
                      @@ -4628,16 +5163,24 @@ class TestShellCompletion:  | 
                  
| 4628 | 5163 | 
                             @pytest.mark.parametrize('exc_type', [RuntimeError, KeyError, ValueError])
                       | 
                    
| 4629 | 5164 | 
                        def test_410b_service_name_exceptions_custom_error(  | 
                    
| 4630 | 5165 | 
                        self,  | 
                    
| 4631 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 4632 | 5166 | 
                        exc_type: type[Exception],  | 
                    
| 4633 | 5167 | 
                        ) -> None:  | 
                    
| 4634 | 5168 | 
                        """Service name completion quietly fails on configuration errors."""  | 
                    
| 4635 | 5169 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 4636 | 
                        - with tests.isolated_vault_config(  | 
                    |
| 5170 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 5171 | 
                        + # with-statements.  | 
                    |
| 5172 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 5173 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 5174 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 5175 | 
                        + stack.enter_context(  | 
                    |
| 5176 | 
                        + tests.isolated_vault_config(  | 
                    |
| 4637 | 5177 | 
                        monkeypatch=monkeypatch,  | 
                    
| 4638 | 5178 | 
                        runner=runner,  | 
                    
| 4639 | 
                        -            vault_config={'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}},
                       | 
                    |
| 4640 | 
                        - ):  | 
                    |
| 5179 | 
                        +                    vault_config={
                       | 
                    |
| 5180 | 
                        +                        'services': {DUMMY_SERVICE: DUMMY_CONFIG_SETTINGS}
                       | 
                    |
| 5181 | 
                        + },  | 
                    |
| 5182 | 
                        + )  | 
                    |
| 5183 | 
                        + )  | 
                    |
| 4641 | 5184 | 
                         | 
                    
| 4642 | 5185 | 
                        def raiser(*_a: Any, **_kw: Any) -> NoReturn:  | 
                    
| 4643 | 5186 | 
                                         raise exc_type('just being difficult')  # noqa: EM101,TRY003
                       | 
                    
| ... | ... | 
                      @@ -42,7 +42,7 @@ if TYPE_CHECKING:  | 
                  
| 42 | 42 | 
                        class TestCLI:  | 
                    
| 43 | 43 | 
                        """Test the command-line interface for `derivepassphrase export vault`."""  | 
                    
| 44 | 44 | 
                         | 
                    
| 45 | 
                        - def test_200_path_parameter(self, monkeypatch: pytest.MonkeyPatch) -> None:  | 
                    |
| 45 | 
                        + def test_200_path_parameter(self) -> None:  | 
                    |
| 46 | 46 | 
                        """The path `VAULT_PATH` is supported.  | 
                    
| 47 | 47 | 
                         | 
                    
| 48 | 48 | 
                        Using `VAULT_PATH` as the path looks up the actual path in the  | 
                    
| ... | ... | 
                      @@ -51,12 +51,19 @@ class TestCLI:  | 
                  
| 51 | 51 | 
                         | 
                    
| 52 | 52 | 
                        """  | 
                    
| 53 | 53 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 54 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 54 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 55 | 
                        + # with-statements.  | 
                    |
| 56 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 57 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 58 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 59 | 
                        + stack.enter_context(  | 
                    |
| 60 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 55 | 61 | 
                        monkeypatch=monkeypatch,  | 
                    
| 56 | 62 | 
                        runner=runner,  | 
                    
| 57 | 63 | 
                        vault_config=tests.VAULT_V03_CONFIG,  | 
                    
| 58 | 64 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 59 | 
                        - ):  | 
                    |
| 65 | 
                        + )  | 
                    |
| 66 | 
                        + )  | 
                    |
| 60 | 67 | 
                                     monkeypatch.setenv('VAULT_KEY', tests.VAULT_MASTER_KEY)
                       | 
                    
| 61 | 68 | 
                        result_ = runner.invoke(  | 
                    
| 62 | 69 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| ... | ... | 
                      @@ -66,14 +73,21 @@ class TestCLI:  | 
                  
| 66 | 73 | 
                        assert result.clean_exit(empty_stderr=True), 'expected clean exit'  | 
                    
| 67 | 74 | 
                        assert json.loads(result.output) == tests.VAULT_V03_CONFIG_DATA  | 
                    
| 68 | 75 | 
                         | 
                    
| 69 | 
                        - def test_201_key_parameter(self, monkeypatch: pytest.MonkeyPatch) -> None:  | 
                    |
| 76 | 
                        + def test_201_key_parameter(self) -> None:  | 
                    |
| 70 | 77 | 
                        """The `--key` option is supported."""  | 
                    
| 71 | 78 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 72 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 79 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 80 | 
                        + # with-statements.  | 
                    |
| 81 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 82 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 83 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 84 | 
                        + stack.enter_context(  | 
                    |
| 85 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 73 | 86 | 
                        monkeypatch=monkeypatch,  | 
                    
| 74 | 87 | 
                        runner=runner,  | 
                    
| 75 | 88 | 
                        vault_config=tests.VAULT_V03_CONFIG,  | 
                    
| 76 | 
                        - ):  | 
                    |
| 89 | 
                        + )  | 
                    |
| 90 | 
                        + )  | 
                    |
| 77 | 91 | 
                        result_ = runner.invoke(  | 
                    
| 78 | 92 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| 79 | 93 | 
                        ['-k', tests.VAULT_MASTER_KEY, '.vault'],  | 
                    
| ... | ... | 
                      @@ -107,7 +121,6 @@ class TestCLI:  | 
                  
| 107 | 121 | 
                        )  | 
                    
| 108 | 122 | 
                        def test_210_load_vault_v02_v03_storeroom(  | 
                    
| 109 | 123 | 
                        self,  | 
                    
| 110 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 111 | 124 | 
                        format: str,  | 
                    
| 112 | 125 | 
                        config: str | bytes,  | 
                    
| 113 | 126 | 
                        config_data: dict[str, Any],  | 
                    
| ... | ... | 
                      @@ -119,11 +132,18 @@ class TestCLI:  | 
                  
| 119 | 132 | 
                         | 
                    
| 120 | 133 | 
                        """  | 
                    
| 121 | 134 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 122 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 135 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 136 | 
                        + # with-statements.  | 
                    |
| 137 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 138 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 139 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 140 | 
                        + stack.enter_context(  | 
                    |
| 141 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 123 | 142 | 
                        monkeypatch=monkeypatch,  | 
                    
| 124 | 143 | 
                        runner=runner,  | 
                    
| 125 | 144 | 
                        vault_config=config,  | 
                    
| 126 | 
                        - ):  | 
                    |
| 145 | 
                        + )  | 
                    |
| 146 | 
                        + )  | 
                    |
| 127 | 147 | 
                        result_ = runner.invoke(  | 
                    
| 128 | 148 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| 129 | 149 | 
                        ['-f', format, '-k', tests.VAULT_MASTER_KEY, 'VAULT_PATH'],  | 
                    
| ... | ... | 
                      @@ -137,17 +157,23 @@ class TestCLI:  | 
                  
| 137 | 157 | 
                         | 
                    
| 138 | 158 | 
                        def test_301_vault_config_not_found(  | 
                    
| 139 | 159 | 
                        self,  | 
                    
| 140 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 141 | 160 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 142 | 161 | 
                        ) -> None:  | 
                    
| 143 | 162 | 
                        """Fail when trying to decode non-existant files/directories."""  | 
                    
| 144 | 163 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 145 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 164 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 165 | 
                        + # with-statements.  | 
                    |
| 166 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 167 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 168 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 169 | 
                        + stack.enter_context(  | 
                    |
| 170 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 146 | 171 | 
                        monkeypatch=monkeypatch,  | 
                    
| 147 | 172 | 
                        runner=runner,  | 
                    
| 148 | 173 | 
                        vault_config=tests.VAULT_V03_CONFIG,  | 
                    
| 149 | 174 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 150 | 
                        - ):  | 
                    |
| 175 | 
                        + )  | 
                    |
| 176 | 
                        + )  | 
                    |
| 151 | 177 | 
                        result_ = runner.invoke(  | 
                    
| 152 | 178 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| 153 | 179 | 
                        ['does-not-exist.txt'],  | 
                    
| ... | ... | 
                      @@ -164,17 +190,23 @@ class TestCLI:  | 
                  
| 164 | 190 | 
                         | 
                    
| 165 | 191 | 
                        def test_302_vault_config_invalid(  | 
                    
| 166 | 192 | 
                        self,  | 
                    
| 167 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 168 | 193 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 169 | 194 | 
                        ) -> None:  | 
                    
| 170 | 195 | 
                        """Fail to parse invalid vault configurations (files)."""  | 
                    
| 171 | 196 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 172 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 197 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 198 | 
                        + # with-statements.  | 
                    |
| 199 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 200 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 201 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 202 | 
                        + stack.enter_context(  | 
                    |
| 203 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 173 | 204 | 
                        monkeypatch=monkeypatch,  | 
                    
| 174 | 205 | 
                        runner=runner,  | 
                    
| 175 | 206 | 
                        vault_config='',  | 
                    
| 176 | 207 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 177 | 
                        - ):  | 
                    |
| 208 | 
                        + )  | 
                    |
| 209 | 
                        + )  | 
                    |
| 178 | 210 | 
                        result_ = runner.invoke(  | 
                    
| 179 | 211 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| 180 | 212 | 
                        ['.vault'],  | 
                    
| ... | ... | 
                      @@ -188,17 +220,23 @@ class TestCLI:  | 
                  
| 188 | 220 | 
                         | 
                    
| 189 | 221 | 
                        def test_302a_vault_config_invalid_just_a_directory(  | 
                    
| 190 | 222 | 
                        self,  | 
                    
| 191 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 192 | 223 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 193 | 224 | 
                        ) -> None:  | 
                    
| 194 | 225 | 
                        """Fail to parse invalid vault configurations (directories)."""  | 
                    
| 195 | 226 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 196 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 227 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 228 | 
                        + # with-statements.  | 
                    |
| 229 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 230 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 231 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 232 | 
                        + stack.enter_context(  | 
                    |
| 233 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 197 | 234 | 
                        monkeypatch=monkeypatch,  | 
                    
| 198 | 235 | 
                        runner=runner,  | 
                    
| 199 | 236 | 
                        vault_config='',  | 
                    
| 200 | 237 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 201 | 
                        - ):  | 
                    |
| 238 | 
                        + )  | 
                    |
| 239 | 
                        + )  | 
                    |
| 202 | 240 | 
                                     p = pathlib.Path('.vault')
                       | 
                    
| 203 | 241 | 
                        p.unlink()  | 
                    
| 204 | 242 | 
                        p.mkdir()  | 
                    
| ... | ... | 
                      @@ -215,17 +253,23 @@ class TestCLI:  | 
                  
| 215 | 253 | 
                         | 
                    
| 216 | 254 | 
                        def test_403_invalid_vault_config_bad_signature(  | 
                    
| 217 | 255 | 
                        self,  | 
                    
| 218 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 219 | 256 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 220 | 257 | 
                        ) -> None:  | 
                    
| 221 | 258 | 
                        """Fail to parse vault configurations with invalid integrity checks."""  | 
                    
| 222 | 259 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 223 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 260 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 261 | 
                        + # with-statements.  | 
                    |
| 262 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 263 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 264 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 265 | 
                        + stack.enter_context(  | 
                    |
| 266 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 224 | 267 | 
                        monkeypatch=monkeypatch,  | 
                    
| 225 | 268 | 
                        runner=runner,  | 
                    
| 226 | 269 | 
                        vault_config=tests.VAULT_V02_CONFIG,  | 
                    
| 227 | 270 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 228 | 
                        - ):  | 
                    |
| 271 | 
                        + )  | 
                    |
| 272 | 
                        + )  | 
                    |
| 229 | 273 | 
                        result_ = runner.invoke(  | 
                    
| 230 | 274 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| 231 | 275 | 
                        ['-f', 'v0.3', '.vault'],  | 
                    
| ... | ... | 
                      @@ -239,17 +283,23 @@ class TestCLI:  | 
                  
| 239 | 283 | 
                         | 
                    
| 240 | 284 | 
                        def test_500_vault_config_invalid_internal(  | 
                    
| 241 | 285 | 
                        self,  | 
                    
| 242 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 243 | 286 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 244 | 287 | 
                        ) -> None:  | 
                    
| 245 | 288 | 
                        """The decoded vault configuration data is valid."""  | 
                    
| 246 | 289 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 247 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 290 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 291 | 
                        + # with-statements.  | 
                    |
| 292 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 293 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 294 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 295 | 
                        + stack.enter_context(  | 
                    |
| 296 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 248 | 297 | 
                        monkeypatch=monkeypatch,  | 
                    
| 249 | 298 | 
                        runner=runner,  | 
                    
| 250 | 299 | 
                        vault_config=tests.VAULT_V03_CONFIG,  | 
                    
| 251 | 300 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 252 | 
                        - ):  | 
                    |
| 301 | 
                        + )  | 
                    |
| 302 | 
                        + )  | 
                    |
| 253 | 303 | 
                         | 
                    
| 254 | 304 | 
                        def export_vault_config_data(*_args: Any, **_kwargs: Any) -> None:  | 
                    
| 255 | 305 | 
                        return None  | 
                    
| ... | ... | 
                      @@ -300,7 +350,6 @@ class TestStoreroom:  | 
                  
| 300 | 350 | 
                        )  | 
                    
| 301 | 351 | 
                        def test_200_export_data_path_and_keys_type(  | 
                    
| 302 | 352 | 
                        self,  | 
                    
| 303 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 304 | 353 | 
                        path: str | None,  | 
                    
| 305 | 354 | 
                        key: str | Buffer | None,  | 
                    
| 306 | 355 | 
                        handler: exporter.ExportVaultConfigDataFunction,  | 
                    
| ... | ... | 
                      @@ -312,12 +361,19 @@ class TestStoreroom:  | 
                  
| 312 | 361 | 
                         | 
                    
| 313 | 362 | 
                        """  | 
                    
| 314 | 363 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 315 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 364 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 365 | 
                        + # with-statements.  | 
                    |
| 366 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 367 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 368 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 369 | 
                        + stack.enter_context(  | 
                    |
| 370 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 316 | 371 | 
                        monkeypatch=monkeypatch,  | 
                    
| 317 | 372 | 
                        runner=runner,  | 
                    
| 318 | 373 | 
                        vault_config=tests.VAULT_STOREROOM_CONFIG_ZIPPED,  | 
                    
| 319 | 374 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 320 | 
                        - ):  | 
                    |
| 375 | 
                        + )  | 
                    |
| 376 | 
                        + )  | 
                    |
| 321 | 377 | 
                        assert (  | 
                    
| 322 | 378 | 
                        handler(path, key, format='storeroom')  | 
                    
| 323 | 379 | 
                        == tests.VAULT_STOREROOM_CONFIG_DATA  | 
                    
| ... | ... | 
                      @@ -339,7 +395,6 @@ class TestStoreroom:  | 
                  
| 339 | 395 | 
                             @pytest.mark.parametrize('config', ['xxx', 'null', '{"version": 255}'])
                       | 
                    
| 340 | 396 | 
                        def test_401_decrypt_bucket_file_bad_json_or_version(  | 
                    
| 341 | 397 | 
                        self,  | 
                    
| 342 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 343 | 398 | 
                        config: str,  | 
                    
| 344 | 399 | 
                        ) -> None:  | 
                    
| 345 | 400 | 
                        """Fail on bad or unsupported bucket file contents.  | 
                    
| ... | ... | 
                      @@ -354,11 +409,18 @@ class TestStoreroom:  | 
                  
| 354 | 409 | 
                        signing_key=bytes(storeroom.KEY_SIZE),  | 
                    
| 355 | 410 | 
                        hashing_key=bytes(storeroom.KEY_SIZE),  | 
                    
| 356 | 411 | 
                        )  | 
                    
| 357 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 412 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 413 | 
                        + # with-statements.  | 
                    |
| 414 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 415 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 416 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 417 | 
                        + stack.enter_context(  | 
                    |
| 418 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 358 | 419 | 
                        monkeypatch=monkeypatch,  | 
                    
| 359 | 420 | 
                        runner=runner,  | 
                    
| 360 | 421 | 
                        vault_config=tests.VAULT_STOREROOM_CONFIG_ZIPPED,  | 
                    
| 361 | 
                        - ):  | 
                    |
| 422 | 
                        + )  | 
                    |
| 423 | 
                        + )  | 
                    |
| 362 | 424 | 
                                     p = pathlib.Path('.vault', '20')
                       | 
                    
| 363 | 425 | 
                                     with p.open('w', encoding='UTF-8') as outfile:
                       | 
                    
| 364 | 426 | 
                        print(config, file=outfile)  | 
                    
| ... | ... | 
                      @@ -394,7 +456,6 @@ class TestStoreroom:  | 
                  
| 394 | 456 | 
                        )  | 
                    
| 395 | 457 | 
                        def test_402_export_storeroom_data_bad_master_keys_file(  | 
                    
| 396 | 458 | 
                        self,  | 
                    
| 397 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 398 | 459 | 
                        data: str,  | 
                    
| 399 | 460 | 
                        err_msg: str,  | 
                    
| 400 | 461 | 
                        handler: exporter.ExportVaultConfigDataFunction,  | 
                    
| ... | ... | 
                      @@ -405,12 +466,19 @@ class TestStoreroom:  | 
                  
| 405 | 466 | 
                         | 
                    
| 406 | 467 | 
                        """  | 
                    
| 407 | 468 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 408 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 469 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 470 | 
                        + # with-statements.  | 
                    |
| 471 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 472 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 473 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 474 | 
                        + stack.enter_context(  | 
                    |
| 475 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 409 | 476 | 
                        monkeypatch=monkeypatch,  | 
                    
| 410 | 477 | 
                        runner=runner,  | 
                    
| 411 | 478 | 
                        vault_config=tests.VAULT_STOREROOM_CONFIG_ZIPPED,  | 
                    
| 412 | 479 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 413 | 
                        - ):  | 
                    |
| 480 | 
                        + )  | 
                    |
| 481 | 
                        + )  | 
                    |
| 414 | 482 | 
                                     p = pathlib.Path('.vault', '.keys')
                       | 
                    
| 415 | 483 | 
                                     with p.open('w', encoding='UTF-8') as outfile:
                       | 
                    
| 416 | 484 | 
                        print(data, file=outfile)  | 
                    
| ... | ... | 
                      @@ -451,7 +519,6 @@ class TestStoreroom:  | 
                  
| 451 | 519 | 
                        )  | 
                    
| 452 | 520 | 
                        def test_403_export_storeroom_data_bad_directory_listing(  | 
                    
| 453 | 521 | 
                        self,  | 
                    
| 454 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 455 | 522 | 
                        zipped_config: bytes,  | 
                    
| 456 | 523 | 
                        error_text: str,  | 
                    
| 457 | 524 | 
                        handler: exporter.ExportVaultConfigDataFunction,  | 
                    
| ... | ... | 
                      @@ -475,6 +542,7 @@ class TestStoreroom:  | 
                  
| 475 | 542 | 
                        # with-statements.  | 
                    
| 476 | 543 | 
                        # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    
| 477 | 544 | 
                        with contextlib.ExitStack() as stack:  | 
                    
| 545 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 478 | 546 | 
                        stack.enter_context(  | 
                    
| 479 | 547 | 
                        tests.isolated_vault_exporter_config(  | 
                    
| 480 | 548 | 
                        monkeypatch=monkeypatch,  | 
                    
| ... | ... | 
                      @@ -621,7 +689,6 @@ class TestVaultNativeConfig:  | 
                  
| 621 | 689 | 
                        )  | 
                    
| 622 | 690 | 
                        def test_201_export_vault_native_data_explicit_version(  | 
                    
| 623 | 691 | 
                        self,  | 
                    
| 624 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 625 | 692 | 
                        config: str,  | 
                    
| 626 | 693 | 
                        format: Literal['v0.2', 'v0.3'],  | 
                    
| 627 | 694 | 
                        result: _types.VaultConfig | type[Exception],  | 
                    
| ... | ... | 
                      @@ -638,12 +705,19 @@ class TestVaultNativeConfig:  | 
                  
| 638 | 705 | 
                         | 
                    
| 639 | 706 | 
                        """  | 
                    
| 640 | 707 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 641 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 708 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 709 | 
                        + # with-statements.  | 
                    |
| 710 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 711 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 712 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 713 | 
                        + stack.enter_context(  | 
                    |
| 714 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 642 | 715 | 
                        monkeypatch=monkeypatch,  | 
                    
| 643 | 716 | 
                        runner=runner,  | 
                    
| 644 | 717 | 
                        vault_config=config,  | 
                    
| 645 | 718 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 646 | 
                        - ):  | 
                    |
| 719 | 
                        + )  | 
                    |
| 720 | 
                        + )  | 
                    |
| 647 | 721 | 
                        if isinstance(result, type):  | 
                    
| 648 | 722 | 
                        with pytest.raises(result):  | 
                    
| 649 | 723 | 
                        handler(None, format=format)  | 
                    
| ... | ... | 
                      @@ -677,7 +751,6 @@ class TestVaultNativeConfig:  | 
                  
| 677 | 751 | 
                        )  | 
                    
| 678 | 752 | 
                        def test_202_export_data_path_and_keys_type(  | 
                    
| 679 | 753 | 
                        self,  | 
                    
| 680 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 681 | 754 | 
                        path: str | None,  | 
                    
| 682 | 755 | 
                        key: str | Buffer | None,  | 
                    
| 683 | 756 | 
                        handler: exporter.ExportVaultConfigDataFunction,  | 
                    
| ... | ... | 
                      @@ -689,12 +762,19 @@ class TestVaultNativeConfig:  | 
                  
| 689 | 762 | 
                         | 
                    
| 690 | 763 | 
                        """  | 
                    
| 691 | 764 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 692 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 765 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 766 | 
                        + # with-statements.  | 
                    |
| 767 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 768 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 769 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 770 | 
                        + stack.enter_context(  | 
                    |
| 771 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 693 | 772 | 
                        monkeypatch=monkeypatch,  | 
                    
| 694 | 773 | 
                        runner=runner,  | 
                    
| 695 | 774 | 
                        vault_config=tests.VAULT_V03_CONFIG,  | 
                    
| 696 | 775 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 697 | 
                        - ):  | 
                    |
| 776 | 
                        + )  | 
                    |
| 777 | 
                        + )  | 
                    |
| 698 | 778 | 
                        assert (  | 
                    
| 699 | 779 | 
                        handler(path, key, format='v0.3')  | 
                    
| 700 | 780 | 
                        == tests.VAULT_V03_CONFIG_DATA  | 
                    
| ... | ... | 
                      @@ -719,7 +799,6 @@ class TestVaultNativeConfig:  | 
                  
| 719 | 799 | 
                        )  | 
                    
| 720 | 800 | 
                        def test_300_result_caching(  | 
                    
| 721 | 801 | 
                        self,  | 
                    
| 722 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 723 | 802 | 
                        parser_class: type[vault_native.VaultNativeConfigParser],  | 
                    
| 724 | 803 | 
                        config: str,  | 
                    
| 725 | 804 | 
                        result: dict[str, Any],  | 
                    
| ... | ... | 
                      @@ -734,11 +813,18 @@ class TestVaultNativeConfig:  | 
                  
| 734 | 813 | 
                        return func  | 
                    
| 735 | 814 | 
                         | 
                    
| 736 | 815 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 737 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 816 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 817 | 
                        + # with-statements.  | 
                    |
| 818 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 819 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 820 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 821 | 
                        + stack.enter_context(  | 
                    |
| 822 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 738 | 823 | 
                        monkeypatch=monkeypatch,  | 
                    
| 739 | 824 | 
                        runner=runner,  | 
                    
| 740 | 825 | 
                        vault_config=config,  | 
                    
| 741 | 
                        - ):  | 
                    |
| 826 | 
                        + )  | 
                    |
| 827 | 
                        + )  | 
                    |
| 742 | 828 | 
                        parser = parser_class(  | 
                    
| 743 | 829 | 
                        base64.b64decode(config), tests.VAULT_MASTER_KEY  | 
                    
| 744 | 830 | 
                        )  | 
                    
| ... | ... | 
                      @@ -43,7 +43,6 @@ class Test001ExporterUtils:  | 
                  
| 43 | 43 | 
                        )  | 
                    
| 44 | 44 | 
                        def test_200_get_vault_key(  | 
                    
| 45 | 45 | 
                        self,  | 
                    
| 46 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 47 | 46 | 
                        expected: str,  | 
                    
| 48 | 47 | 
                        vault_key: str | None,  | 
                    
| 49 | 48 | 
                        logname: str | None,  | 
                    
| ... | ... | 
                      @@ -63,9 +62,16 @@ class Test001ExporterUtils:  | 
                  
| 63 | 62 | 
                                     ('USERNAME', username),
                       | 
                    
| 64 | 63 | 
                        ]  | 
                    
| 65 | 64 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 66 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 65 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 66 | 
                        + # with-statements.  | 
                    |
| 67 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 68 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 69 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 70 | 
                        + stack.enter_context(  | 
                    |
| 71 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 67 | 72 | 
                        monkeypatch=monkeypatch, runner=runner  | 
                    
| 68 | 
                        - ):  | 
                    |
| 73 | 
                        + )  | 
                    |
| 74 | 
                        + )  | 
                    |
| 69 | 75 | 
                        for key, value in priority_list:  | 
                    
| 70 | 76 | 
                        if value is not None:  | 
                    
| 71 | 77 | 
                        monkeypatch.setenv(key, value)  | 
                    
| ... | ... | 
                      @@ -81,7 +87,6 @@ class Test001ExporterUtils:  | 
                  
| 81 | 87 | 
                        )  | 
                    
| 82 | 88 | 
                        def test_210_get_vault_path(  | 
                    
| 83 | 89 | 
                        self,  | 
                    
| 84 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 85 | 90 | 
                        expected: pathlib.Path,  | 
                    
| 86 | 91 | 
                        path: str | os.PathLike[str] | None,  | 
                    
| 87 | 92 | 
                        ) -> None:  | 
                    
| ... | ... | 
                      @@ -91,9 +96,16 @@ class Test001ExporterUtils:  | 
                  
| 91 | 96 | 
                         | 
                    
| 92 | 97 | 
                        """  | 
                    
| 93 | 98 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 94 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 99 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 100 | 
                        + # with-statements.  | 
                    |
| 101 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 102 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 103 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 104 | 
                        + stack.enter_context(  | 
                    |
| 105 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 95 | 106 | 
                        monkeypatch=monkeypatch, runner=runner  | 
                    
| 96 | 
                        - ):  | 
                    |
| 107 | 
                        + )  | 
                    |
| 108 | 
                        + )  | 
                    |
| 97 | 109 | 
                        if path:  | 
                    
| 98 | 110 | 
                        monkeypatch.setenv(  | 
                    
| 99 | 111 | 
                        'VAULT_PATH', os.fspath(path) if path is not None else None  | 
                    
| ... | ... | 
                      @@ -103,9 +115,7 @@ class Test001ExporterUtils:  | 
                  
| 103 | 115 | 
                        == expected.expanduser().resolve()  | 
                    
| 104 | 116 | 
                        )  | 
                    
| 105 | 117 | 
                         | 
                    
| 106 | 
                        - def test_220_register_export_vault_config_data_handler(  | 
                    |
| 107 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 108 | 
                        - ) -> None:  | 
                    |
| 118 | 
                        + def test_220_register_export_vault_config_data_handler(self) -> None:  | 
                    |
| 109 | 119 | 
                        """Register vault config data export handlers."""  | 
                    
| 110 | 120 | 
                         | 
                    
| 111 | 121 | 
                        def handler( # pragma: no cover  | 
                    
| ... | ... | 
                      @@ -117,6 +127,7 @@ class Test001ExporterUtils:  | 
                  
| 117 | 127 | 
                        del path, key  | 
                    
| 118 | 128 | 
                        raise ValueError(format)  | 
                    
| 119 | 129 | 
                         | 
                    
| 130 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 120 | 131 | 
                                     registry = {'dummy': handler}
                       | 
                    
| 121 | 132 | 
                        monkeypatch.setattr(  | 
                    
| 122 | 133 | 
                        exporter, '_export_vault_config_data_registry', registry  | 
                    
| ... | ... | 
                      @@ -132,10 +143,9 @@ class Test001ExporterUtils:  | 
                  
| 132 | 143 | 
                        'name2': handler,  | 
                    
| 133 | 144 | 
                        }  | 
                    
| 134 | 145 | 
                         | 
                    
| 135 | 
                        - def test_300_get_vault_key_without_envs(  | 
                    |
| 136 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 137 | 
                        - ) -> None:  | 
                    |
| 146 | 
                        + def test_300_get_vault_key_without_envs(self) -> None:  | 
                    |
| 138 | 147 | 
                        """Fail to look up the vault key in the empty environment."""  | 
                    
| 148 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 139 | 149 | 
                                     monkeypatch.delenv('VAULT_KEY', raising=False)
                       | 
                    
| 140 | 150 | 
                                     monkeypatch.delenv('LOGNAME', raising=False)
                       | 
                    
| 141 | 151 | 
                                     monkeypatch.delenv('USER', raising=False)
                       | 
                    
| ... | ... | 
                      @@ -143,14 +153,13 @@ class Test001ExporterUtils:  | 
                  
| 143 | 153 | 
                        with pytest.raises(KeyError, match='VAULT_KEY'):  | 
                    
| 144 | 154 | 
                        exporter.get_vault_key()  | 
                    
| 145 | 155 | 
                         | 
                    
| 146 | 
                        - def test_310_get_vault_path_without_home(  | 
                    |
| 147 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 148 | 
                        - ) -> None:  | 
                    |
| 156 | 
                        + def test_310_get_vault_path_without_home(self) -> None:  | 
                    |
| 149 | 157 | 
                        """Fail to look up the vault path without `HOME`."""  | 
                    
| 150 | 158 | 
                         | 
                    
| 151 | 159 | 
                        def raiser(*_args: Any, **_kwargs: Any) -> Any:  | 
                    
| 152 | 160 | 
                                     raise RuntimeError('Cannot determine home directory.')  # noqa: EM101,TRY003
                       | 
                    
| 153 | 161 | 
                         | 
                    
| 162 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 154 | 163 | 
                        monkeypatch.setattr(pathlib.Path, 'expanduser', raiser)  | 
                    
| 155 | 164 | 
                        monkeypatch.setattr(os.path, 'expanduser', raiser)  | 
                    
| 156 | 165 | 
                        with pytest.raises(  | 
                    
| ... | ... | 
                      @@ -176,7 +185,6 @@ class Test001ExporterUtils:  | 
                  
| 176 | 185 | 
                        )  | 
                    
| 177 | 186 | 
                        def test_320_register_export_vault_config_data_handler_errors(  | 
                    
| 178 | 187 | 
                        self,  | 
                    
| 179 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 180 | 188 | 
                        namelist: tuple[str, ...],  | 
                    
| 181 | 189 | 
                        err_pat: str,  | 
                    
| 182 | 190 | 
                        ) -> None:  | 
                    
| ... | ... | 
                      @@ -196,6 +204,7 @@ class Test001ExporterUtils:  | 
                  
| 196 | 204 | 
                        del path, key  | 
                    
| 197 | 205 | 
                        raise ValueError(format)  | 
                    
| 198 | 206 | 
                         | 
                    
| 207 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 199 | 208 | 
                                     registry = {'dummy': handler}
                       | 
                    
| 200 | 209 | 
                        monkeypatch.setattr(  | 
                    
| 201 | 210 | 
                        exporter, '_export_vault_config_data_registry', registry  | 
                    
| ... | ... | 
                      @@ -205,11 +214,12 @@ class Test001ExporterUtils:  | 
                  
| 205 | 214 | 
                        handler  | 
                    
| 206 | 215 | 
                        )  | 
                    
| 207 | 216 | 
                         | 
                    
| 208 | 
                        - def test_321_export_vault_config_data_bad_handler(  | 
                    |
| 209 | 
                        - self, monkeypatch: pytest.MonkeyPatch  | 
                    |
| 210 | 
                        - ) -> None:  | 
                    |
| 217 | 
                        + def test_321_export_vault_config_data_bad_handler(self) -> None:  | 
                    |
| 211 | 218 | 
                        """Fail to export vault config data without known handlers."""  | 
                    
| 212 | 
                        -        monkeypatch.setattr(exporter, '_export_vault_config_data_registry', {})
                       | 
                    |
| 219 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 220 | 
                        + monkeypatch.setattr(  | 
                    |
| 221 | 
                        +                exporter, '_export_vault_config_data_registry', {}
                       | 
                    |
| 222 | 
                        + )  | 
                    |
| 213 | 223 | 
                        monkeypatch.setattr(  | 
                    
| 214 | 224 | 
                        exporter, 'find_vault_config_data_handlers', lambda: None  | 
                    
| 215 | 225 | 
                        )  | 
                    
| ... | ... | 
                      @@ -223,18 +233,22 @@ class Test001ExporterUtils:  | 
                  
| 223 | 233 | 
                        class Test002CLI:  | 
                    
| 224 | 234 | 
                        """Test the command-line functionality of the `exporter` subpackage."""  | 
                    
| 225 | 235 | 
                         | 
                    
| 226 | 
                        - def test_300_invalid_format(  | 
                    |
| 227 | 
                        - self,  | 
                    |
| 228 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 229 | 
                        - ) -> None:  | 
                    |
| 236 | 
                        + def test_300_invalid_format(self) -> None:  | 
                    |
| 230 | 237 | 
                        """Reject invalid vault configuration format names."""  | 
                    
| 231 | 238 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 232 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 239 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 240 | 
                        + # with-statements.  | 
                    |
| 241 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 242 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 243 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 244 | 
                        + stack.enter_context(  | 
                    |
| 245 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 233 | 246 | 
                        monkeypatch=monkeypatch,  | 
                    
| 234 | 247 | 
                        runner=runner,  | 
                    
| 235 | 248 | 
                        vault_config=tests.VAULT_V03_CONFIG,  | 
                    
| 236 | 249 | 
                        vault_key=tests.VAULT_MASTER_KEY,  | 
                    
| 237 | 
                        - ):  | 
                    |
| 250 | 
                        + )  | 
                    |
| 251 | 
                        + )  | 
                    |
| 238 | 252 | 
                        result_ = runner.invoke(  | 
                    
| 239 | 253 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| 240 | 254 | 
                        ['-f', 'INVALID', 'VAULT_PATH'],  | 
                    
| ... | ... | 
                      @@ -272,7 +286,6 @@ class Test002CLI:  | 
                  
| 272 | 286 | 
                        )  | 
                    
| 273 | 287 | 
                        def test_999_no_cryptography_error_message(  | 
                    
| 274 | 288 | 
                        self,  | 
                    
| 275 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 276 | 289 | 
                        caplog: pytest.LogCaptureFixture,  | 
                    
| 277 | 290 | 
                        format: str,  | 
                    
| 278 | 291 | 
                        config: str | bytes,  | 
                    
| ... | ... | 
                      @@ -280,12 +293,19 @@ class Test002CLI:  | 
                  
| 280 | 293 | 
                        ) -> None:  | 
                    
| 281 | 294 | 
                        """Abort export call if no cryptography is available."""  | 
                    
| 282 | 295 | 
                        runner = click.testing.CliRunner(mix_stderr=False)  | 
                    
| 283 | 
                        - with tests.isolated_vault_exporter_config(  | 
                    |
| 296 | 
                        + # TODO(the-13th-letter): Rewrite using parenthesized  | 
                    |
| 297 | 
                        + # with-statements.  | 
                    |
| 298 | 
                        + # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9  | 
                    |
| 299 | 
                        + with contextlib.ExitStack() as stack:  | 
                    |
| 300 | 
                        + monkeypatch = stack.enter_context(pytest.MonkeyPatch.context())  | 
                    |
| 301 | 
                        + stack.enter_context(  | 
                    |
| 302 | 
                        + tests.isolated_vault_exporter_config(  | 
                    |
| 284 | 303 | 
                        monkeypatch=monkeypatch,  | 
                    
| 285 | 304 | 
                        runner=runner,  | 
                    
| 286 | 305 | 
                        vault_config=config,  | 
                    
| 287 | 306 | 
                        vault_key=key,  | 
                    
| 288 | 
                        - ):  | 
                    |
| 307 | 
                        + )  | 
                    |
| 308 | 
                        + )  | 
                    |
| 289 | 309 | 
                        result_ = runner.invoke(  | 
                    
| 290 | 310 | 
                        cli.derivepassphrase_export_vault,  | 
                    
| 291 | 311 | 
                        ['-f', format, 'VAULT_PATH'],  | 
                    
| ... | ... | 
                      @@ -132,11 +132,11 @@ class TestStaticFunctionality:  | 
                  
| 132 | 132 | 
                         | 
                    
| 133 | 133 | 
                        def test_200_constructor_no_running_agent(  | 
                    
| 134 | 134 | 
                        self,  | 
                    
| 135 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 136 | 135 | 
                        skip_if_no_af_unix_support: None,  | 
                    
| 137 | 136 | 
                        ) -> None:  | 
                    
| 138 | 137 | 
                        """Abort if the running agent cannot be located."""  | 
                    
| 139 | 138 | 
                        del skip_if_no_af_unix_support  | 
                    
| 139 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 140 | 140 | 
                                     monkeypatch.delenv('SSH_AUTH_SOCK', raising=False)
                       | 
                    
| 141 | 141 | 
                        with pytest.raises(  | 
                    
| 142 | 142 | 
                        KeyError, match='SSH_AUTH_SOCK environment variable'  | 
                    
| ... | ... | 
                      @@ -467,26 +467,20 @@ class TestAgentInteraction:  | 
                  
| 467 | 467 | 
                         | 
                    
| 468 | 468 | 
                        def test_300_constructor_bad_running_agent(  | 
                    
| 469 | 469 | 
                        self,  | 
                    
| 470 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 471 | 470 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 472 | 471 | 
                        ) -> None:  | 
                    
| 473 | 472 | 
                        """Fail if the agent address is invalid."""  | 
                    
| 474 | 
                        - with monkeypatch.context() as monkeypatch2:  | 
                    |
| 475 | 
                        - monkeypatch2.setenv(  | 
                    |
| 476 | 
                        - 'SSH_AUTH_SOCK', running_ssh_agent.socket + '~'  | 
                    |
| 477 | 
                        - )  | 
                    |
| 473 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 474 | 
                        +            monkeypatch.setenv('SSH_AUTH_SOCK', running_ssh_agent.socket + '~')
                       | 
                    |
| 478 | 475 | 
                        sock = socket.socket(family=socket.AF_UNIX)  | 
                    
| 479 | 476 | 
                        with pytest.raises(OSError): # noqa: PT011  | 
                    
| 480 | 477 | 
                        ssh_agent.SSHAgentClient(socket=sock)  | 
                    
| 481 | 478 | 
                         | 
                    
| 482 | 
                        - def test_301_constructor_no_af_unix_support(  | 
                    |
| 483 | 
                        - self,  | 
                    |
| 484 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 485 | 
                        - ) -> None:  | 
                    |
| 479 | 
                        + def test_301_constructor_no_af_unix_support(self) -> None:  | 
                    |
| 486 | 480 | 
                        """Fail without [`socket.AF_UNIX`][] support."""  | 
                    
| 487 | 
                        - with monkeypatch.context() as monkeypatch2:  | 
                    |
| 488 | 
                        -            monkeypatch2.setenv('SSH_AUTH_SOCK', "the value doesn't matter")
                       | 
                    |
| 489 | 
                        - monkeypatch2.delattr(socket, 'AF_UNIX', raising=False)  | 
                    |
| 481 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 482 | 
                        +            monkeypatch.setenv('SSH_AUTH_SOCK', "the value doesn't matter")
                       | 
                    |
| 483 | 
                        + monkeypatch.delattr(socket, 'AF_UNIX', raising=False)  | 
                    |
| 490 | 484 | 
                        with pytest.raises(  | 
                    
| 491 | 485 | 
                        NotImplementedError,  | 
                    
| 492 | 486 | 
                        match='UNIX domain sockets',  | 
                    
| ... | ... | 
                      @@ -503,7 +497,6 @@ class TestAgentInteraction:  | 
                  
| 503 | 497 | 
                        )  | 
                    
| 504 | 498 | 
                        def test_310_truncated_server_response(  | 
                    
| 505 | 499 | 
                        self,  | 
                    
| 506 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 507 | 500 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 508 | 501 | 
                        response: bytes,  | 
                    
| 509 | 502 | 
                        ) -> None:  | 
                    
| ... | ... | 
                      @@ -520,6 +513,7 @@ class TestAgentInteraction:  | 
                  
| 520 | 513 | 
                        return response_stream.read(*args, **kwargs)  | 
                    
| 521 | 514 | 
                         | 
                    
| 522 | 515 | 
                        pseudo_socket = PseudoSocket()  | 
                    
| 516 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 523 | 517 | 
                        monkeypatch.setattr(client, '_connection', pseudo_socket)  | 
                    
| 524 | 518 | 
                        with pytest.raises(EOFError):  | 
                    
| 525 | 519 | 
                        client.request(255, b'')  | 
                    
| ... | ... | 
                      @@ -552,7 +546,6 @@ class TestAgentInteraction:  | 
                  
| 552 | 546 | 
                        )  | 
                    
| 553 | 547 | 
                        def test_320_list_keys_error_responses(  | 
                    
| 554 | 548 | 
                        self,  | 
                    
| 555 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 556 | 549 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 557 | 550 | 
                        response_code: _types.SSH_AGENT,  | 
                    
| 558 | 551 | 
                        response: bytes | bytearray,  | 
                    
| ... | ... | 
                      @@ -602,9 +595,9 @@ class TestAgentInteraction:  | 
                  
| 602 | 595 | 
                        )  | 
                    
| 603 | 596 | 
                        return response  | 
                    
| 604 | 597 | 
                         | 
                    
| 605 | 
                        - with monkeypatch.context() as monkeypatch2:  | 
                    |
| 598 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 606 | 599 | 
                        client = ssh_agent.SSHAgentClient()  | 
                    
| 607 | 
                        - monkeypatch2.setattr(client, 'request', request)  | 
                    |
| 600 | 
                        + monkeypatch.setattr(client, 'request', request)  | 
                    |
| 608 | 601 | 
                        with pytest.raises(exc_type, match=exc_pattern):  | 
                    
| 609 | 602 | 
                        client.list_keys()  | 
                    
| 610 | 603 | 
                         | 
                    
| ... | ... | 
                      @@ -640,7 +633,6 @@ class TestAgentInteraction:  | 
                  
| 640 | 633 | 
                        )  | 
                    
| 641 | 634 | 
                        def test_330_sign_error_responses(  | 
                    
| 642 | 635 | 
                        self,  | 
                    
| 643 | 
                        - monkeypatch: pytest.MonkeyPatch,  | 
                    |
| 644 | 636 | 
                        running_ssh_agent: tests.RunningSSHAgentInfo,  | 
                    
| 645 | 637 | 
                        key: bytes | bytearray,  | 
                    
| 646 | 638 | 
                        check: bool,  | 
                    
| ... | ... | 
                      @@ -692,16 +684,16 @@ class TestAgentInteraction:  | 
                  
| 692 | 684 | 
                        )  | 
                    
| 693 | 685 | 
                        return response # pragma: no cover  | 
                    
| 694 | 686 | 
                         | 
                    
| 695 | 
                        - with monkeypatch.context() as monkeypatch2:  | 
                    |
| 687 | 
                        + with pytest.MonkeyPatch.context() as monkeypatch:  | 
                    |
| 696 | 688 | 
                        client = ssh_agent.SSHAgentClient()  | 
                    
| 697 | 
                        - monkeypatch2.setattr(client, 'request', request)  | 
                    |
| 689 | 
                        + monkeypatch.setattr(client, 'request', request)  | 
                    |
| 698 | 690 | 
                        Pair = _types.SSHKeyCommentPair # noqa: N806  | 
                    
| 699 | 691 | 
                        com = b'no comment'  | 
                    
| 700 | 692 | 
                        loaded_keys = [  | 
                    
| 701 | 693 | 
                        Pair(v.public_key_data, com).toreadonly()  | 
                    
| 702 | 694 | 
                        for v in tests.SUPPORTED_KEYS.values()  | 
                    
| 703 | 695 | 
                        ]  | 
                    
| 704 | 
                        - monkeypatch2.setattr(client, 'list_keys', lambda: loaded_keys)  | 
                    |
| 696 | 
                        + monkeypatch.setattr(client, 'list_keys', lambda: loaded_keys)  | 
                    |
| 705 | 697 | 
                        with pytest.raises(exc_type, match=exc_pattern):  | 
                    
| 706 | 698 | 
                        client.sign(key, b'abc', check_if_key_loaded=check)  | 
                    
| 707 | 699 | 
                         | 
                    
| 708 | 700 |