@@ -2405,13 +2405,13 @@ def get_help_topics(self) -> List[str]:
2405
2405
return [topic for topic in all_topics if topic not in self .hidden_commands and topic not in self .disabled_commands ]
2406
2406
2407
2407
# noinspection PyUnusedLocal
2408
- def sigint_handler (self , signum : int , _ : FrameType ) -> None :
2408
+ def sigint_handler (self , signum : int , _ : Optional [ FrameType ] ) -> None :
2409
2409
"""Signal handler for SIGINTs which typically come from Ctrl-C events.
2410
2410
2411
- If you need custom SIGINT behavior, then override this function .
2411
+ If you need custom SIGINT behavior, then override this method .
2412
2412
2413
2413
:param signum: signal number
2414
- :param _: required param for signal handlers
2414
+ :param _: the current stack frame or None
2415
2415
"""
2416
2416
if self ._cur_pipe_proc_reader is not None :
2417
2417
# Pass the SIGINT to the current pipe process
@@ -2427,6 +2427,23 @@ def sigint_handler(self, signum: int, _: FrameType) -> None:
2427
2427
if raise_interrupt :
2428
2428
self ._raise_keyboard_interrupt ()
2429
2429
2430
+ def termination_signal_handler (self , signum : int , _ : Optional [FrameType ]) -> None :
2431
+ """
2432
+ Signal handler for SIGHUP and SIGTERM. Only runs on Linux and Mac.
2433
+
2434
+ SIGHUP - received when terminal window is closed
2435
+ SIGTERM - received when this app has been requested to terminate
2436
+
2437
+ The basic purpose of this method is to call sys.exit() so our exit handler will run
2438
+ and save the persistent history file. If you need more complex behavior like killing
2439
+ threads and performing cleanup, then override this method.
2440
+
2441
+ :param signum: signal number
2442
+ :param _: the current stack frame or None
2443
+ """
2444
+ # POSIX systems add 128 to signal numbers for the exit code
2445
+ sys .exit (128 + signum )
2446
+
2430
2447
def _raise_keyboard_interrupt (self ) -> None :
2431
2448
"""Helper function to raise a KeyboardInterrupt"""
2432
2449
raise KeyboardInterrupt ("Got a keyboard interrupt" )
@@ -5426,11 +5443,18 @@ def cmdloop(self, intro: Optional[str] = None) -> int: # type: ignore[override]
5426
5443
if not threading .current_thread () is threading .main_thread ():
5427
5444
raise RuntimeError ("cmdloop must be run in the main thread" )
5428
5445
5429
- # Register a SIGINT signal handler for Ctrl+C
5446
+ # Register signal handlers
5430
5447
import signal
5431
5448
5432
5449
original_sigint_handler = signal .getsignal (signal .SIGINT )
5433
- signal .signal (signal .SIGINT , self .sigint_handler ) # type: ignore
5450
+ signal .signal (signal .SIGINT , self .sigint_handler )
5451
+
5452
+ if not sys .platform .startswith ('win' ):
5453
+ original_sighup_handler = signal .getsignal (signal .SIGHUP )
5454
+ signal .signal (signal .SIGHUP , self .termination_signal_handler )
5455
+
5456
+ original_sigterm_handler = signal .getsignal (signal .SIGTERM )
5457
+ signal .signal (signal .SIGTERM , self .termination_signal_handler )
5434
5458
5435
5459
# Grab terminal lock before the command line prompt has been drawn by readline
5436
5460
self .terminal_lock .acquire ()
@@ -5464,9 +5488,13 @@ def cmdloop(self, intro: Optional[str] = None) -> int: # type: ignore[override]
5464
5488
# This will also zero the lock count in case cmdloop() is called again
5465
5489
self .terminal_lock .release ()
5466
5490
5467
- # Restore the original signal handler
5491
+ # Restore original signal handlers
5468
5492
signal .signal (signal .SIGINT , original_sigint_handler )
5469
5493
5494
+ if not sys .platform .startswith ('win' ):
5495
+ signal .signal (signal .SIGHUP , original_sighup_handler )
5496
+ signal .signal (signal .SIGTERM , original_sigterm_handler )
5497
+
5470
5498
return self .exit_code
5471
5499
5472
5500
###
0 commit comments