From 6998d1d3d7580818fd88e0a8c4d3590f7e7d8688 Mon Sep 17 00:00:00 2001 From: Ramesh Padmanabhaiah <22363102+codeforester@users.noreply.github.com> Date: Tue, 11 Aug 2026 05:18:45 -0700 Subject: [PATCH] Log interrupted invocations to primary log --- lib/python/base_cli/app.py | 15 ++++++++------- tests/test_adversarial_regressions.py | 4 ++++ tests/test_app_run_metadata.py | 5 ++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/python/base_cli/app.py b/lib/python/base_cli/app.py index 829e0ab..52ff866 100644 --- a/lib/python/base_cli/app.py +++ b/lib/python/base_cli/app.py @@ -327,11 +327,12 @@ def _capture_effective_output_options( state.json_output = json_output -def _record_unexpected_traceback(context: Context[Any, Any, Any], outcome: InvocationOutcome) -> None: - if outcome.kind != "unexpected_error": - return +def _record_lifecycle_diagnostic(context: Context[Any, Any, Any], outcome: InvocationOutcome) -> None: try: - context.log.debug("Unexpected command exception", exc_info=True) + if outcome.kind == "interrupted": + context.log.warning("Interrupted.") + elif outcome.kind == "unexpected_error": + context.log.debug("Unexpected command exception", exc_info=True) except BaseException: # pylint: disable=broad-exception-caught pass @@ -1045,7 +1046,7 @@ def wrapper(**kwargs: Any) -> Any: except BaseException as exc: if context is not None: outcome = outcome_from_exception(click, exc) - _record_unexpected_traceback(context, outcome) + _record_lifecycle_diagnostic(context, outcome) raise finally: if context is not None: @@ -1399,7 +1400,7 @@ def lifecycle_aware_exit(code: int = 0) -> Any: except BaseException as exc: if self.context is not None: self.outcome = outcome_from_exception(self.click, exc) - _record_unexpected_traceback(self.context, self.outcome) + _record_lifecycle_diagnostic(self.context, self.outcome) self._finalize() raise @@ -1445,7 +1446,7 @@ def record_exception(self, exc: BaseException) -> None: state.attached_completion = False if self.context is not None: self.outcome = outcome_from_exception(self.click, exc) - _record_unexpected_traceback(self.context, self.outcome) + _record_lifecycle_diagnostic(self.context, self.outcome) def __exit__( self, diff --git a/tests/test_adversarial_regressions.py b/tests/test_adversarial_regressions.py index a10f81c..2f8ac08 100644 --- a/tests/test_adversarial_regressions.py +++ b/tests/test_adversarial_regressions.py @@ -277,12 +277,14 @@ def main(ctx: base_cli.Context) -> None: result = invoke(app, [], home=home) metadata_paths = tuple((home / ".cache").rglob("run.json")) payload = json.loads(metadata_paths[0].read_text(encoding="utf-8")) + log_text = (metadata_paths[0].parent / "logs" / "primary.log").read_text(encoding="utf-8") temp_dir = Path(seen["temp_dir"]) temp_contents = tuple(temp_dir.iterdir()) if temp_dir.is_dir() else () logger_handlers = list(seen["logger"].handlers) # type: ignore[union-attr] self.assertEqual(result.exit_code, base_cli.ExitCode.INTERRUPTED) self.assertIn("Interrupted.", result.stderr) + self.assertIn("Interrupted.", log_text) self.assertEqual(len(metadata_paths), 1) self.assertEqual(payload["outcome"], "interrupted") self.assertEqual(payload["status"], "error") @@ -374,11 +376,13 @@ def main(ctx: base_cli.Context) -> None: metadata_paths = tuple(cache.rglob("run.json")) payload = json.loads(metadata_paths[0].read_text(encoding="utf-8")) + log_text = (metadata_paths[0].parent / "logs" / "primary.log").read_text(encoding="utf-8") temp_dir = metadata_paths[0].parent / "tmp" / "signal-child" / payload["run_id"] temp_contents = tuple(temp_dir.iterdir()) self.assertEqual(process.returncode, base_cli.ExitCode.INTERRUPTED, stderr) self.assertIn("Interrupted.", stderr) + self.assertIn("Interrupted.", log_text) self.assertEqual(len(metadata_paths), 1) self.assertEqual(payload["outcome"], "interrupted") self.assertEqual(payload["status"], "error") diff --git a/tests/test_app_run_metadata.py b/tests/test_app_run_metadata.py index 98f1658..bebb162 100644 --- a/tests/test_app_run_metadata.py +++ b/tests/test_app_run_metadata.py @@ -220,11 +220,14 @@ def main( home = Path(tmpdir) status, stderr = _run(app, home) - _, metadata = _load_only_metadata(self, home) + metadata_path, metadata = _load_only_metadata(self, home) + log_text = (metadata_path.parent / "logs" / "primary.log").read_text(encoding="utf-8") self.assertEqual(status, expected_code) self.assertIn(expected_message, stderr) self.assertNotIn("Traceback", stderr) + if expected_outcome == "interrupted": + self.assertIn("Interrupted.", log_text) _assert_terminal_metadata( self, metadata,