Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent a block of code from being interrupted by KeyboardInterrupt in Python?

Tags:

python

I'm writing a program that caches some results via the pickle module. What happens at the moment is that if I hit ctrl-c at while the dump operation is occurring, dump gets interrupted and the resulting file is corrupted (i.e. only partially written, so it cannot be loaded again.

Is there a way to make dump, or in general a block of code, uninterruptable? My current workaround looks something like this:

try:   file = open(path, 'w')   dump(obj, file)   file.close() except KeyboardInterrupt:   file.close()   file.open(path,'w')   dump(obj, file)   file.close()   raise 

It seems silly to restart the operation if it is interrupted, so I am searching for a way to defer the interrupt. How do I do this?

like image 462
saffsd Avatar asked May 09 '09 02:05

saffsd


People also ask

How does Python handle KeyboardInterrupt?

In Python, there is no special syntax for the KeyboardInterrupt exception; it is handled in the usual try and except block. The code that potentially causes the problem is written inside the try block, and the 'raise' keyword is used to raise the exception, or the python interpreter raises it automatically.

What does KeyboardInterrupt mean in Python?

The KeyboardInterrupt error occurs when a user manually tries to halt the running program by using the Ctrl + C or Ctrl + Z commands or by interrupting the kernel in the case of Jupyter Notebook.

What does Ctrl C do in Python?

Python allows us to set up signal -handlers so when a particular signal arrives to our program we can have a behavior different from the default. For example when you run a program on the terminal and press Ctrl-C the default behavior is to quit the program.


2 Answers

The following is a context manager that attaches a signal handler for SIGINT. If the context manager's signal handler is called, the signal is delayed by only passing the signal to the original handler when the context manager exits.

import signal import logging  class DelayedKeyboardInterrupt:      def __enter__(self):         self.signal_received = False         self.old_handler = signal.signal(signal.SIGINT, self.handler)                      def handler(self, sig, frame):         self.signal_received = (sig, frame)         logging.debug('SIGINT received. Delaying KeyboardInterrupt.')          def __exit__(self, type, value, traceback):         signal.signal(signal.SIGINT, self.old_handler)         if self.signal_received:             self.old_handler(*self.signal_received)  with DelayedKeyboardInterrupt():     # stuff here will not be interrupted by SIGINT     critical_code() 
like image 155
Gary van der Merwe Avatar answered Sep 21 '22 03:09

Gary van der Merwe


Put the function in a thread, and wait for the thread to finish.

Python threads cannot be interrupted except with a special C api.

import time from threading import Thread  def noInterrupt():     for i in xrange(4):         print i         time.sleep(1)  a = Thread(target=noInterrupt) a.start() a.join() print "done"   0 1 2 3 Traceback (most recent call last):   File "C:\Users\Admin\Desktop\test.py", line 11, in <module>     a.join()   File "C:\Python26\lib\threading.py", line 634, in join     self.__block.wait()   File "C:\Python26\lib\threading.py", line 237, in wait     waiter.acquire() KeyboardInterrupt 

See how the interrupt was deferred until the thread finished?

Here it is adapted to your use:

import time from threading import Thread  def noInterrupt(path, obj):     try:         file = open(path, 'w')         dump(obj, file)     finally:         file.close()  a = Thread(target=noInterrupt, args=(path,obj)) a.start() a.join() 
like image 27
Unknown Avatar answered Sep 21 '22 03:09

Unknown