diff --git a/src/tower/cli.py b/src/tower/cli.py index d846ac4a..30272891 100644 --- a/src/tower/cli.py +++ b/src/tower/cli.py @@ -1,7 +1,13 @@ +import signal import sys from ._native import _run_cli def main(): + # When invoked via Python, SIGINT defaults to raising KeyboardInterrupt + # in the interpreter instead of terminating the process immediately. + # Restore default SIGINT behavior so Ctrl+C reliably cancels interactive + # CLI flows (matching behavior of the standalone Rust binary). + signal.signal(signal.SIGINT, signal.SIG_DFL) _run_cli(sys.argv) diff --git a/tests/tower/test_cli.py b/tests/tower/test_cli.py new file mode 100644 index 00000000..948d4d97 --- /dev/null +++ b/tests/tower/test_cli.py @@ -0,0 +1,24 @@ +import signal + +import tower.cli + + +def test_main_restores_default_sigint_and_calls_native(monkeypatch): + captured = {} + + def fake_signal(sig, handler): + captured["sig"] = sig + captured["handler"] = handler + + def fake_run_cli(argv): + captured["argv"] = argv + + monkeypatch.setattr(tower.cli.signal, "signal", fake_signal) + monkeypatch.setattr(tower.cli, "_run_cli", fake_run_cli) + + tower.cli.main() + + assert captured["sig"] == signal.SIGINT + assert captured["handler"] == signal.SIG_DFL + assert isinstance(captured["argv"], list) + assert len(captured["argv"]) > 0