@@ -2411,7 +2411,7 @@ def get_help_topics(self) -> List[str]:
2411
2411
def sigint_handler (self , signum : int , _ : FrameType ) -> None :
2412
2412
"""Signal handler for SIGINTs which typically come from Ctrl-C events.
2413
2413
2414
- If you need custom SIGINT behavior, then override this function .
2414
+ If you need custom SIGINT behavior, then override this method .
2415
2415
2416
2416
:param signum: signal number
2417
2417
:param _: required param for signal handlers
@@ -2430,6 +2430,23 @@ def sigint_handler(self, signum: int, _: FrameType) -> None:
2430
2430
if raise_interrupt :
2431
2431
self ._raise_keyboard_interrupt ()
2432
2432
2433
+ def termination_signal_handler (self , signum : int , _ : FrameType ) -> None :
2434
+ """
2435
+ Signal handler for SIGHUP and SIGTERM. Only runs on Linux and Mac.
2436
+
2437
+ SIGHUP - received when terminal window is closed
2438
+ SIGTERM - received when this app has been requested to terminate
2439
+
2440
+ The basic purpose of this method is to call sys.exit() so our exit handler will run
2441
+ and save the persistent history file. If you need more complex behavior like killing
2442
+ threads and performing cleanup, then override this method.
2443
+
2444
+ :param signum: signal number
2445
+ :param _: required param for signal handlers
2446
+ """
2447
+ # POSIX systems add 128 to signal numbers for the exit code
2448
+ sys .exit (128 + signum )
2449
+
2433
2450
def _raise_keyboard_interrupt (self ) -> None :
2434
2451
"""Helper function to raise a KeyboardInterrupt"""
2435
2452
raise KeyboardInterrupt ("Got a keyboard interrupt" )
@@ -5434,12 +5451,19 @@ def cmdloop(self, intro: Optional[str] = None) -> int: # type: ignore[override]
5434
5451
if not threading .current_thread () is threading .main_thread ():
5435
5452
raise RuntimeError ("cmdloop must be run in the main thread" )
5436
5453
5437
- # Register a SIGINT signal handler for Ctrl+C
5454
+ # Register signal handlers
5438
5455
import signal
5439
5456
5440
5457
original_sigint_handler = signal .getsignal (signal .SIGINT )
5441
5458
signal .signal (signal .SIGINT , self .sigint_handler ) # type: ignore
5442
5459
5460
+ if not sys .platform .startswith ('win' ):
5461
+ original_sighup_handler = signal .getsignal (signal .SIGHUP )
5462
+ signal .signal (signal .SIGHUP , self .termination_signal_handler ) # type: ignore
5463
+
5464
+ original_sigterm_handler = signal .getsignal (signal .SIGTERM )
5465
+ signal .signal (signal .SIGTERM , self .termination_signal_handler ) # type: ignore
5466
+
5443
5467
# Grab terminal lock before the command line prompt has been drawn by readline
5444
5468
self .terminal_lock .acquire ()
5445
5469
@@ -5472,9 +5496,13 @@ def cmdloop(self, intro: Optional[str] = None) -> int: # type: ignore[override]
5472
5496
# This will also zero the lock count in case cmdloop() is called again
5473
5497
self .terminal_lock .release ()
5474
5498
5475
- # Restore the original signal handler
5499
+ # Restore original signal handlers
5476
5500
signal .signal (signal .SIGINT , original_sigint_handler )
5477
5501
5502
+ if not sys .platform .startswith ('win' ):
5503
+ signal .signal (signal .SIGHUP , original_sighup_handler )
5504
+ signal .signal (signal .SIGTERM , original_sigterm_handler )
5505
+
5478
5506
return self .exit_code
5479
5507
5480
5508
###
0 commit comments