From bef45e2c6d6ce97c3e00ccc8d589771a019f684d Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Tue, 22 Sep 2026 12:45:13 -0700 Subject: [PATCH] Handle sigint gracefully in main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanly catch the signal and teardown to avoid this traceback Traceback (most recent call last): File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main return _run_code(code, main_globals, None, File "/usr/lib/python3.8/runpy.py", line 87, in _run_code exec(code, run_globals) File "/mnt/data/repos/revup/revup/__main__.py", line 48, in _main() File "/mnt/data/repos/revup/revup/__main__.py", line 26, in _main sys.exit(loop.run_until_complete(main(revup_parser, all_parsers))) File "/usr/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete self.run_forever() File "/usr/lib/python3.8/asyncio/base_events.py", line 570, in run_forever self._run_once() File "/usr/lib/python3.8/asyncio/base_events.py", line 1823, in _run_once event_list = self._selector.select(timeout) File "/usr/lib/python3.8/selectors.py", line 468, in select fd_event_list = self._selector.poll(timeout, max_ev) KeyboardInterrupt ⠼ Querying github…Exception ignored in: RuntimeError: coroutine ignored GeneratorExit --- revup/__main__.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/revup/__main__.py b/revup/__main__.py index 8c1104a..858fbaa 100644 --- a/revup/__main__.py +++ b/revup/__main__.py @@ -1,6 +1,7 @@ # PYTHON_ARGCOMPLETE_OK import asyncio import logging +import signal import sys from revup.core_types import ( @@ -22,8 +23,17 @@ def _main() -> None: # Instead, we can manually create the event loop and prevent the RuntimeError on shutdown. revup_parser, all_parsers = build_parser() loop = asyncio.new_event_loop() + task = loop.create_task(main(revup_parser, all_parsers)) + # Let the loop cancel main on sigint, so it unwinds and cleans up instead of being + # abandoned suspended. Windows has no signal handling for loops. + if sys.platform != "win32": + loop.add_signal_handler(signal.SIGINT, task.cancel) try: - sys.exit(loop.run_until_complete(main(revup_parser, all_parsers))) + sys.exit(loop.run_until_complete(task)) + except (asyncio.CancelledError, KeyboardInterrupt): + # Exit code of 130 is the shell convention for death by sigint. + logging.error("Interrupted") + sys.exit(130) finally: loop.close() except RevupUsageException as e: