Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions tests/test_click_tree_attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from unittest import mock

import base_cli
from base_cli._runtime import RuntimeDirectoryError
from base_cli.testing import invoke


Expand Down Expand Up @@ -619,6 +620,55 @@ def context_factory(context: base_cli.Context) -> object:
with self.assertRaisesRegex(RuntimeError, "context is not active"):
base_cli.get_current_context()

def test_factory_configuration_and_runtime_failures_translate_to_click_errors(self) -> None:
import click

cases = (
(base_cli.ConfigurationError("invalid application configuration"), click.UsageError),
(RuntimeDirectoryError("runtime directory unavailable"), click.ClickException),
)
for failure, expected_type in cases:
with self.subTest(failure=type(failure).__name__):

@click.command(name=f"factory-{type(failure).__name__.lower()}")
def command() -> None:
self.fail("factory failure should prevent callback execution")

app = _CountingApp(name=command.name or "factory", log_to_file=False)
app.attach(command, context_factory=lambda _context, failure=failure: (_ for _ in ()).throw(failure))
with tempfile.TemporaryDirectory() as tmpdir:
result = invoke(app, [], home=Path(tmpdir))

self.assertEqual(result.exit_code, 2 if expected_type is click.UsageError else 1, _all_output(result))
self.assertIn(str(failure), _all_output(result))
self.assertEqual(app.context_cleanup_count, 1)

def test_partial_attachment_initialization_finalizes_before_reraising(self) -> None:
import click

class PartialInitializationFailure(BaseException):
pass

@click.command(name="partial-attachment")
def command() -> None:
self.fail("partial initialization should prevent callback execution")

app = _CountingApp(name="partial-attachment", log_to_file=False)
app.attach(command)
failure = PartialInitializationFailure("context activation interrupted")
with tempfile.TemporaryDirectory() as tmpdir:
with mock.patch(
"base_cli._attach.set_current_context",
side_effect=failure,
):
with self.assertRaises(PartialInitializationFailure) as raised:
invoke(app, [], home=Path(tmpdir), reraise_unexpected=True)

self.assertIs(raised.exception, failure)
self.assertEqual(app.context_cleanup_count, 1)
with self.assertRaisesRegex(RuntimeError, "context is not active"):
base_cli.get_current_context()

def test_factory_registered_click_resources_close_inside_lifecycle(self) -> None:
import click

Expand Down
Loading