This question already has answers here:
How do I capture SIGINT in Python?
(12 answers)
Closed 9 years ago.
When i press CTRL+C to cancel a running python script, is there a way to run a certain python code before the script terminates?
Use try/except to capture for KeyboardInterrupt, which is raised when you press CTRL+C.
Here is a basic script to demonstrate:
try:
# Main code
while True:
print 'hi!'
except KeyboardInterrupt:
# Cleanup/exiting code
print 'done!'
This will continually print 'hi!' until you press CTRL+C. Then, it prints 'done!' and exits.
CTRL+C raises KeyboardInterrupt. You can catch it just like any other exception:
try:
main()
except KeyboardInterrupt:
cleanup()
If you really don't like that, you can also use atexit.register to register cleanup actions to run (provided that you don't do something really nasty and cause the interpreter to exit in a funky way)
try:
# something
except KeyboardInterrupt:
# your code after ctrl+c
I'm pretty sure you just need a try/finally block.
Try out this script:
import time
def main():
try:
while True:
print("blah blah")
time.sleep(5)
except KeyboardInterrupt:
print("caught CTRL-C")
finally:
print("do cleanup")
if __name__ == '__main__':
main()
Output should be something like:
blah blah
caught CTRL-C
do cleanup
This code
import time
try:
while True:
time.sleep(2)
except KeyboardInterrupt:
print "Any clean"
gives
deck#crunch ~/tmp $ python test.py
^CAny clean
when I press Ctrl+C when executing.
You just have to handle KeyboardInterrupt exception.
Also you can deal with signals to set handlers.
Related
Was given a script I would reuse more or less, I need to be able to to both :
end the execution by itself
capture ctrl-c to exit on user action
I saw many clues to the second part on other answers/question of stackoverflow similar to :
try:
while True:
time.sleep(1)
except (KeyboardInterrupt, SystemExit):
pass
In my point of view I should run the execution functions (main) in
while mycondition:
try:
mainfunction()
except KeyboardInterrupt:
personalised_exit()
Why not (if I undersoud well as I am still a python noob), but why not a more declarative code with usage of signal modules ?
something might look then like
import signal
import sys
def signal_handler(sig, frame):
[...]
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
main()
signal.pause()
PDB's quit command works by raising an exception (Bdb.BdbQuit). If that exception gets caught, I cannot figure out a way to kill the program short of killing the entire shell. CTRL+C works by raising a KeyboardInterrupt exception, which can also be caught.
You can recreate this problem with this simple script.
foo = 0
while True:
try:
import pdb; pdb.set_trace()
foo += 1
except:
pass
This script cannot be stopped from within PDB with the quit command or CTRL+C.
I'm aware this is bad programming and you should never use an except without an exception type. I ask because I ran into this issue while debugging and a third-party library trapped me in the loop.
You can try killing the python process with os._exit.
import os
try:
print("Exiting")
os._exit(1)
except:
print("Caught!")
Output:
Exiting
Why not re-raise the exception:
import bdb
try:
something_i_might_want_to_debug_with_pdb()
except bdb.BdbQuit as exc:
raise exc
except:
print("Caught!")
I am running a python script in the background using the command python script.py &. The script might look like this.
import time
def loop():
while True:
time.sleep(1)
if __name__=='__main__':
try:
loop()
except KeyboardInterrupt:
print("Terminated properly")
When it comes to terminating the script, I would like to do some cleanup before it is stopped (such as printing "Terminated properly"). If I run as a current process, this would be handled by the except statement after a keyboard interrupt.
Using the kill PID command means the cleanup is never executed. How can I stop a background process and execute some lines of code before it is terminated?
You can use signal module to catch any signals sent to your script via kill.
You setup a signal handler to catch the signal in question that would perform the cleanup.
import signal
import time
running = 0
def loop ():
global running
running = 1
while running:
try: time.sleep(0.25)
except KeyboardInterrupt: break
print "Ended nicely!"
def cleanup (signumber, stackframe):
global running
running = 0
signal.signal(signal.SIGABRT, cleanup)
signal.signal(signal.SIGTERM, cleanup)
signal.signal(signal.SIGQUIT, cleanup)
loop()
Use finally clause:
def loop():
while True:
time.sleep(1)
if __name__=='__main__':
try:
loop()
except KeyboardInterrupt:
print("Terminated properly")
finally:
print('executes always')
If I am running a python program on linux terminal and i abort it manually by pressing ctrl+c, how can i make my program do something when this event occurs.
something like:
if sys.exit():
print "you chose to end the program"
You can write a signal handling function
import signal,sys
def signal_handling(signum,frame):
print "you chose to end the program"
sys.exit()
signal.signal(signal.SIGINT,signal_handling)
while True:
pass
pressing Ctrl+c sends a SIGINT interrupt which would output:
you chose to end the program
Well, you can use KeyBoardInterrupt, using a try-except block:
try:
# some code here
except KeyboardInterrupt:
print "You exited
Try the following in your command line:
import time
try:
while True:
time.sleep(1)
print "Hello"
except KeyboardInterrupt:
print "No more Hellos"
Check the KeyboardInterrupt exception in Python.
You can put your code in a try block, catch the KeyboardInterrupt exception with except and let the user know that he has exited.
I have my main application thread that spawns 2 threads and I catch SIGINT in my main thread to quit them nicely.
On linux, I'm using signal.pause() and it works perfectly.
What is the best way to implement signal.pause() on Windows?
My ugly solution is:
my_queue.get(True, averylongtime)
And put something in my_queue in my signal handler. Note that if I don't specify a timeout, SIGINT is not caught. But I wonder if there's a better solution.
Thank you
I use this:
#another:
while not self.quit:
# your code
# main
try:
# your code
except KeyboardInterrupt:
another.quit = True
time.sleep(5) # or wait for threading.enumerate() or similar
If I want it more robust, say, exit in presence of bugs too:
except KeyboardInterrupt:
another.quit = True
signal.alarm(5)
time.sleep(6)
A side effect to this is that every block where you except: or except Exception, e: (which is not something you should do anyway/much) you have to prepend except KeyboardInterrupt: raise so that the exception is not "eaten".
I use this for catching a ctrl-c on windows. In case I'm writing to a pipe or file or what have you.. I want to exit gracefully. Below is a toy example
import signal
import sys
def signal_handler(signal, frame):
print('Process Interrupted!\n\a')
sys.exit(0)
signal.signal(signal.SIGINT,signal_handler)
#Rest of your code