How to avoid python exception in while handling SIGINT - python

import signal
import time
def sigint_handler(signum, frame):
print 'User pressed CTRL+C!'
signal.signal(signal.SIGINT, sigint_handler)
def main():
while True:
print 'Script to handle SIGINT'
time.sleep(2)
##########
if __name__ == "__main__":
main()
How can I block this below exception thrown by python itself when executing the code:
File "D:\Documents\scripts\ctrlc handler.py", line 19, in <module> main()
File "D:\Documents\scripts\ctrlc handler.py", line 14, in main
time.sleep(2) OError: [Errno 4] Interrupted function call

The issue seems to have something to do with different signals being received and different errors being thrown. See also this maybe for reference. The work around I could come up with was to catch and ignore the OSError/IOError that is being thrown like so:
import signal
import time
def sigint_handler(signum, frame):
print 'User pressed CTRL+C!'
signal.signal(signal.SIGINT, sigint_handler)
def main():
while True:
print 'Script to handle SIGINT'
try:
time.sleep(2)
except IOError:
pass
##########
if __name__ == "__main__":
main()
Which works perfectly.
Script to handle SIGINT
User pressed CTRL+C!
Script to handle SIGINT
User pressed CTRL+C!
Script to handle SIGINT
User pressed CTRL+C!
Script to handle SIGINT
User pressed CTRL+C!
Script to handle SIGINT
User pressed CTRL+C!
Script to handle SIGINT
User pressed CTRL+C!
Script to handle SIGINT
User pressed CTRL+C!
Script to handle SIGINT
User pressed CTRL+C!

Related

How to disable interruption with Ctrl+C in cmd/python

I have a program that has quite a few functions, each running on a separate thread.
When the user presses Ctrl+C, only 1 thread crashes with an exception, but because of this, the whole program may not work correctly.
Of course, I can write this construction in each function:
try:
do_something()
except KeyboardInterrupt as e:
pass
but, as I said, there are many functions, perhaps there is an option not to prescribe this construction in each function?
Or is it possible to disable Ctrl+C interrupt in cmd settings?
For example, in the registry. The program creates its own registry key in HKEY_CURRENT_USER\Console\MyProgrammKey
UPD 1
signal.signal(signal.SIGINT, signal.SIG_IGN)
It helped in almost all cases except one: a thread that has an infinite loop with the input() function anyway interrupts.
UPD 2
Here is a sample code
import signal, time
from threading import Thread
def one():
while True:
inp = input("INPUT: ")
def two():
while True:
print("I just printing...")
time.sleep(1)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal.SIG_IGN)
Thread(target=one).start()
Thread(target=two).start()
UPD 3
Screenshot of exception.
Ctrl+C will send SIGINT signal to program, so you could define a global signal handler to ignore that SIGINT, something like next:
test.py:
import signal, os, time
def handler(signum, frame):
pass
signal.signal(signal.SIGINT, handler)
time.sleep(10)
print("done")
During the program run, if you input Ctrl+c, the program will ignore it, and continue to run, finally print done:
$ python3 test.py
^Cdone

Is there a way to never exit on KeyboardInterrupt in python?

I'm creating sort of a interactive command line in python. I have something like this:
def complete_menu():
while True:
cmd = input('cmd> ')
if cmd == "help":
print('help')
elif cmd == "?":
print('?')
When the user presses CTRL-C, instead of exiting the program I'm trying to make it so that it prints "please type exit to exit" and goes back to the while True. I have something like this at the moment:
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print('Please use exit to exit')
complete_menu()
Although this works, there is a number of issues. For one, when CTRL-C is pressed the first time, it prints out the text and works perfectly. However, the second time the user presses CTRL-C, it exists with a bunch of messy text like any other program after pressing CTRL-C. Can this be fixed?
The better way to do this is to register a signal handler:
import signal
def handler(signum, frame):
print("Please use exit to exit")
# or: just call sys.exit("goodbye")
...
def main():
signal.signal(signal.SIGINT, handler) # prevent "crashing" with ctrl+C
...
if __name__ == "__main__":
main()
Now when a Ctrl+C is received in your code, instead of a KeyboardInterrupt exception being raised, the function handler will be executed. This is a basic example, customize the code within handler to do what you want.
Note: My recommendation is to actually let the user exit with Ctrl+C, i.e. execute any cleanup code that you might need to run and then call sys.exit here. Programs that require a stronger signal to kill are annoying.

handling unexpected shutdown python

is there any way to catch an exception for an unexpected shutdown of program in python ?
let say I am running a python script in a console then I don't press control+c to stop the program but rather just click the close button of the console is there any way to catch the error before the console close?
like this:
try:
print("hello")
except KeyboardInterrupt:
exit()
except UnexpectedClose:
print("unexpected shutoff")
exit()
thanks in advance
Following the link I put in the comment above already and reading here that forced closing is sending a SIGHUP this modified version writes an output file when the terminal window is closed and the python process is "killed".
Note, I just combined information (as cited) available on SE.
import signal
import time
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
signal.signal(signal.SIGHUP, self.exit_gracefully)
def exit_gracefully(self,signum, frame):
with open('kill.txt', 'w') as fpntr:
fpntr.write('killed')
self.kill_now = True
if __name__ == '__main__':
killer = GracefulKiller()
while True:
time.sleep(1)
print("doing something in a loop ...")
if killer.kill_now:
break
print "End of the program. I was killed gracefully :)"

Why is signal.SIGTERM not dealt with properly in my main thread?

I have python code which runs continuously (collecting sensor data). It is supposed to be launched at boot using start-stop-daemon. However, I'd like to be able to kill the process gracefully, so I've started from the advice in the post How to process SIGTERM signal gracefully? and put my main loop in a separate thread. I'd like to be able to gracefully shut it down both when it is running as a daemon (the start-stop-daemon will send a kill signal) and when I launch it briefly for testing in a terminal myself (me pressing ctrl-c).
However, the signal handler doesn't seem to be called if I kill the process (even without using the thread, the "done (killed)" never ends up in the file I've redirected to). And when I press ctrl-c, the collecting just continues and keeps printing data in the terminal (or to the file I am redirecting to).
What am I doing wrong in the following code?
from threading import Thread
import time, sys, signal
shutdown_flag = False #used for gracefull shutdown
def main_loop():
while not shutdown_flag:
collect_data() # contains some print "data" statements
time.sleep(5)
print "done (killed)"
def sighandler(signum, frame):
print 'signal handler called with signal: %s ' % signum
global shutdown_flag
shutdown_flag = True
def main(argv=None):
signal.signal(signal.SIGTERM, sighandler) # so we can handle kill gracefully
signal.signal(signal.SIGINT, sighandler) # so we can handle ctrl-c
try:
Thread(target=main_loop, args=()).start()
except Exception, reason:
print reason
if __name__ == '__main__':
sys.exit(main(sys.argv))
You are terminating your main thread with this statement:
if __name__ == '__main__':
sys.exit(main(sys.argv))
So your signal handler never gets to run. The signal handler is part of the main thread not the main_loop thread you created. So once the main thread exits there's no signal handler function to call anymore.
You need something like this:
def sighandler(signum, frame):
print 'signal handler called with signal: %s ' % signum
global shutdown_flag
shutdown_flag = True
sys.exit() # make sure you add this so the main thread exits as well.
if __name__ == '__main__':
main(sys.argv)
while 1: # this will force your main thread to live until you terminate it.
time.sleep(1)
A simple test to see how many threads are running in your program is this:
def main_loop():
while not shutdown_flag:
collect_data() # contains some print "data" statements
time.sleep(5)
import threading
print threading.enumerate()
print "done (killed)"

How can I override the keyboard interrupt? (Python)

Is there anyway I can make my script execute one of my functions when Ctrl+c is hit when the script is running?
Take a look at signal handlers. CTRL-C corresponds to SIGINT (signal #2 on posix systems).
Example:
#!/usr/bin/env python
import signal
import sys
def signal_handler(signal, frame):
print("You pressed Ctrl+C - or killed me with -2")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print("Press Ctrl+C")
signal.pause()
Sure.
try:
# Your normal block of code
except KeyboardInterrupt:
# Your code which is executed when CTRL+C is pressed.
finally:
# Your code which is always executed.
Use the KeyboardInterrupt exception and call your function in the except block.

Categories