I'm rather new to python and I'm stuck with the following problem. I have a script that processes files one-by-one and writes output into separate files according to input file name. Sometimes I need to break the script, but I'd like to let it finish processing current file and then terminate (to avoid result files with incomplete information). How to code this behavior in python?
Here is what I tried.
a) Try-except block
x = 1 print "Script started." while True: try: print "Processing file #",x,"started...", # do something time-cosnuming time.sleep(1) x += 1 print " finished." except KeyboardInterrupt: print "Bye" print "x=",x sys.exit() sys.exit()
Output:
Script started. Processing file # 1 started... finished. Processing file # 2 started... finished. Processing file # 3 started... Bye x= 3
Iteration #3 is not finished gracefully.
b) sys.excepthook
OriginalExceptHook = sys.excepthook def NewExceptHook(type, value, traceback): global Terminator Terminator = True if type == KeyboardInterrupt: #exit("\nExiting by CTRL+C.") # this line was here originally print("\n\nExiting by CTRL+C.\n\n") else: OriginalExceptHook(type, value, traceback) sys.excepthook = NewExceptHook global Terminator Terminator = False x = 1 while True: print "Processing file #",x,"started...", # do something time-cosnuming time.sleep(1) x += 1 print " finished." if Terminator: print "I'll be back!" break print "Bye" print "x=",x sys.exit()
Output:
Script started. Processing file # 1 started... finished. Processing file # 2 started... finished. Processing file # 3 started... Exiting by CTRL+C.
Iteration #3 is not finished gracefully.
@mguijarr , I slightly modified code like this:
import time, sys x = 1 print "Script started." stored_exception=None while True: try: print "Processing file #",x,"started...", # do something time-cosnuming time.sleep(1) print "Processing file #",x,"part two...", time.sleep(1) print " finished." if stored_exception: break x += 1 except KeyboardInterrupt: print "[CTRL+C detected]", stored_exception=sys.exc_info() print "Bye" print "x=",x if stored_exception: raise stored_exception[0], stored_exception[1], stored_exception[2] sys.exit()
The output is (tested using "Python 2.7.6 :: Anaconda 2.0.0 (64-bit)" on Win7-64bit):
Script started. Processing file # 1 started... Processing file # 1 part two... finished. Processing file # 2 started... Processing file # 2 part two... finished. Processing file # 3 started... [CTRL+C detected] Processing file # 3 started... Processing file # 3 part two... finished. Bye x= 3 Traceback (most recent call last): File "test2.py", line 12, in <module> time.sleep(1) KeyboardInterrupt
In this case iteration #3 was effectively restarted, which looks odd and is not a desired behavior. Is it possible to avoid this?
I removed commas in 'print' statements and added more stuff to see that iteration is actually restarted:
import time, sys x = 1 y = 0 print "Script started." stored_exception=None while True: try: y=x*1000 y+=1 print "Processing file #",x,y,"started..." y+=1 # do something time-cosnuming y+=1 time.sleep(1) y+=1 print "Processing file #",x,y,"part two..." y+=1 time.sleep(1) y+=1 print " finished.",x,y y+=1 if stored_exception: break y+=1 x += 1 y+=1 except KeyboardInterrupt: print "[CTRL+C detected]", stored_exception=sys.exc_info() print "Bye" print "x=",x print "y=",y if stored_exception: raise stored_exception[0], stored_exception[1], stored_exception[2] sys.exit()
and the output is:
Script started. Processing file # 1 1001 started... Processing file # 1 1004 part two... finished. 1 1006 Processing file # 2 2001 started... Processing file # 2 2004 part two... [CTRL+C detected] Processing file # 2 2001 started... Processing file # 2 2004 part two... finished. 2 2006 Bye x= 2 y= 2007 Traceback (most recent call last): File "test2.py", line 20, in <module> time.sleep(1) KeyboardInterrupt
Graceful exit You can use the bash command echo $? to get the exit code of the Python interpreter.
You can handle CTRL + C by catching the KeyboardInterrupt exception. You can implement any clean-up code in the exception handler.
An infinite loop is a loop that runs indefinitely and it only stops with external intervention or when a break statement is found. You can stop an infinite loop with CTRL + C .
I would simply use an exception handler, which would catch KeyboardInterrupt
and store the exception. Then, at the moment an iteration is finished, if an exception is pending I would break the loop and re-raise the exception (to let normal exception handling a chance to happen).
This works (tested with Python 2.7):
x = 1 print "Script started." stored_exception=None while True: try: print "Processing file #",x,"started...", # do something time-cosnuming time.sleep(1) print " finished." if stored_exception: break x += 1 except KeyboardInterrupt: stored_exception=sys.exc_info() print "Bye" print "x=",x if stored_exception: raise stored_exception[0], stored_exception[1], stored_exception[2] sys.exit()
EDIT: as it has been spotted in the comments, this answer is not satisfying for the original poster, here is a solution based on threads:
import time import sys import threading print "Script started." class MyProcessingThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): print "Processing file #",x,"started...", # do something time-cosnuming time.sleep(1) print " finished." for x in range(1,4): task = MyProcessingThread() task.start() try: task.join() except KeyboardInterrupt: break print "Bye" print "x=",x sys.exit()
You can write a signal handling function
import signal,sys,time terminate = False def signal_handling(signum,frame): global terminate terminate = True signal.signal(signal.SIGINT,signal_handling) x=1 while True: print "Processing file #",x,"started..." time.sleep(1) x+=1 if terminate: print "I'll be back" break print "bye" print x
pressing Ctrl+c sends a SIGINT interrupt which would output:
Processing file # 1 started... Processing file # 2 started... ^CI'll be back bye 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With