8/6/24, 3:15 PM signals - How do I capture SIGINT in Python?
- Stack Overflow
More documentation on signal can be found here.
Share Follow edited Aug 4, 2023 at 3:46 answered Jul 10, 2009 at 22:52
Gabriel Staples Matt J
47.9k 24 253 333 44.7k 7 50 57
22 Could you tell me why to use this in stead of a KeyboardInterrupt exception? Isn't that more intuitive to
use? – noio Jun 10, 2011 at 14:07
61 Noio: 2 reasons. First, SIGINT can be sent to your process any number of ways (e.g., 'kill -s INT <pid>'); I'm
not sure if KeyboardInterruptException is implemented as a SIGINT handler or if it really only catches
Ctrl+C presses, but either way, using a signal handler makes your intent explicit (at least, if your intent is
the same as OP's). More importantly though, with a signal you don't have to wrap try-catches around
everything to make them work, which can be more or less of a composability and general software
engineering win depending on the structure of your application. – Matt J Jun 20, 2011 at 7:55
57 Example of why you want to trap the signal instead of catch the Exception. Say you run your program and
redirect the output to a log file, ./program.py > output.log . When you press Ctrl-C you want your
program to exit gracefully by having it log that all data files have been flushed and marked clean to
confirm they are left in a known good state. But Ctrl-C sends SIGINT to all processes in a pipeline, so the
shell may close STDOUT (now "output.log") before program.py finishes printing the final log. Python will
complain, "close failed in file object destructor: Error in sys.excepthook:". – Noah Spurrier Jul 3, 2011 at
22:07
27 Note that signal.pause() is unavailable on Windows. docs.python.org/dev/library/signal.html – May Oakes
Aug 3, 2011 at 16:30
19 -1 unicorns for using signal.pause(), suggests that I would have to wait at such a blocking call instead of
doing some real work. ;) – Nick T Aug 3, 2014 at 15:49
You can treat it like an exception ( KeyboardInterrupt ), like any other. Make a new file and run it
from your shell with the following contents to see what I mean:
215
import time, sys
x = 1
while True:
try:
print x
time.sleep(.3)
x += 1
except KeyboardInterrupt:
print "Bye"
sys.exit()
Share Follow edited Jun 2, 2022 at 17:22 answered Jul 10, 2009 at 22:54
Neuron rledley
5,643 5 42 61 2,393 1 12 7
https://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python 2/10
8/6/24, 3:15 PM signals - How do I capture SIGINT in Python? - Stack Overflow
time.sleep(1)
if h.interrupted:
print "interrupted!"
time.sleep(2)
break
Nested handlers:
with GracefulInterruptHandler() as h1:
while True:
print "(1)..."
time.sleep(1)
with GracefulInterruptHandler() as h2:
while True:
print "\t(2)..."
time.sleep(1)
if h2.interrupted:
print "\t(2) interrupted!"
time.sleep(2)
break
if h1.interrupted:
print "(1) interrupted!"
time.sleep(2)
break
From here: https://gist.github.com/2907502
Share Follow answered Jun 10, 2012 at 22:23
Udi
30.1k 9 101 131
It could also throw a StopIteration to break the innermost loop when a ctrl-C is pressed, right?
– Theo Belaire Feb 5, 2014 at 1:28
@TheoBelaire Instead of just throwing a StopIteration, I would create a generator that accepts an iterable
as a parameter and registers/releases the signal handler. – Udi Sep 18, 2014 at 8:27
You can handle CTRL + C by catching the KeyboardInterrupt exception. You can implement
any clean-up code in the exception handler.
33
Share Follow edited Oct 21, 2017 at 12:56 answered Jul 10, 2009 at 22:52
Mwiza Jay Conrod
8,567 3 52 43 29.4k 20 98 110
Yet Another Snippet
https://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python 4/10
8/6/24, 3:15 PM signals - How do I capture SIGINT in Python? - Stack Overflow
import signal
import sys
def signal_handler(signum, frame):
signal.signal(signum, signal.SIG_IGN) # ignore additional signals
cleanup() # give your process a chance to clean up
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) # register the signal with the
signal handler first
do_stuff()
Share Follow answered Jan 30, 2020 at 18:32
Josh Correia
4,224 3 39 61
1 Thx. This is the sensible way of doing it, by clearly registering the signal handler. – not2qubit Sep 27, 2023
at 18:32
I adapted the code from @udi to support multiple signals (nothing fancy) :
12 class GracefulInterruptHandler(object):
def __init__(self, signals=(signal.SIGINT, signal.SIGTERM)):
self.signals = signals
self.original_handlers = {}
def __enter__(self):
self.interrupted = False
self.released = False
for sig in self.signals:
self.original_handlers[sig] = signal.getsignal(sig)
signal.signal(sig, self.handler)
return self
def handler(self, signum, frame):
self.release()
self.interrupted = True
def __exit__(self, type, value, tb):
self.release()
def release(self):
if self.released:
return False
for sig in self.signals:
signal.signal(sig, self.original_handlers[sig])
self.released = True
return True
https://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python 6/10
8/6/24, 3:15 PM signals - How do I capture SIGINT in Python? - Stack Overflow
Udi/Cyril N.'s solutions to be very complete, but much more complex. – Aaron Ciuffo Oct 23, 2020 at 19:58
I don't like to call this solution superior over another. A good developer looks at different answers and
distills its own application-specific solution out of the available suggestions. But to give one advantage, it's
pretty simple to use and implement. A rather big disadvantage is the need for a non-blocking loop in the
thread that is handled. – Thomas Devoogdt Oct 25, 2020 at 13:40
You can use the functions in Python's built-in signal module to set up signal handlers in python.
Specifically the signal.signal(signalnum, handler) function is used to register the handler
4 function for signal signalnum .
Share Follow answered Jul 10, 2009 at 22:54
Brandon E Taylor
25.3k 6 49 71
thanks for existing answers, but added signal.getsignal()
3 import signal
# store default handler of signal.SIGINT
default_handler = signal.getsignal(signal.SIGINT)
catch_count = 0
def handler(signum, frame):
global default_handler, catch_count
catch_count += 1
print ('wait:', catch_count)
if catch_count > 3:
# recover handler for signal.SIGINT
signal.signal(signal.SIGINT, default_handler)
print('expecting KeyboardInterrupt')
signal.signal(signal.SIGINT, handler)
print('Press Ctrl+c here')
while True:
pass
Share Follow answered Dec 31, 2018 at 5:50
gsw945
98 2 6
An alternative to signal.getsignal is to save the return value of signal.signal , which is the same
thing. – Alex Peters Apr 5, 2021 at 8:01
https://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python 8/10
8/6/24, 3:15 PM signals - How do I capture SIGINT in Python? - Stack Overflow
Here's a one-liner (minus the imports), tested with Python 3.10 (not sure about other versions):
0 #!/usr/bin/env python3
from signal import SIGINT, SIGTERM, sigwait
print('received', sigwait({SIGINT, SIGTERM}))
Though the behavior is funny if you send another signal, like USR1, before INT/TERM. sigwait will
wait for INT/TERM, but won't output the "received {signal}" line as expected.
$ ./test.py # ctrl + c
^Creceived Signals.SIGINT
$ ./test.py # kill -TERM <pid>
received Signals.SIGTERM
$ ./test.py # kill -USR1 <pid> ; kill -TERM <pid>
User defined signal 1: 30
Share Follow answered Mar 21, 2023 at 19:29
jtribble
1,151 1 9 6
This is weird. You don't have to register the signal handler? – not2qubit Sep 27, 2023 at 18:31
1 @not2qubit sigwait blocks the current thread (in this case, the main thread) until one of the signals
you've provided is received: docs.python.org/3/library/signal.html#signal.sigwait – jtribble Sep 28, 2023 at
20:57
Highly active question. Earn 10 reputation (not counting the association bonus) in order to answer this question.
The reputation requirement helps protect this question from spam and non-answer activity.
https://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python 10/10