Tutorial :Saving work after a SIGINT



Question:

I have a program which takes a long time to complete. I would like it to be able to catch SIGINT (ctrl-c) and call the self.save_work() method.

As it stands, my signal_hander() does not work since self is not defined by the time the program reaches signal_handler().

How can I set it up so self.save_work gets called after a SIGINT?

#!/usr/bin/env python  import signal     def signal_handler(signal, frame):          self.save_work()   # Does not work      exit(1)  signal.signal(signal.SIGINT, signal_handler)    class Main(object):      def do_stuff(self):          ...      def save_work(self):          ...      def __init__(self):          self.do_stuff()          self.save_work()    if __name__=='__main__':      Main()  


Solution:1

If you just want to catch ctr+c then you can catch the KeyboardInterrupt exception:

class Main(object):      def do_stuff(self):          ...      def save_work(self):          ...      def __init__(self):          try:              self.do_stuff()          except KeyboardInterrupt:              pass # Or print helpful info          self.save_work()  

Not that I think this is a good design after all. It looks like you need to be using a function instead of a constructor.


Solution:2

Usually, "work" involves some kind of a big loop. To tame your loop, and prevent it from breaking in an unknown step, you can use the following context manager:

import signal    class GracefulInterruptHandler(object):        def __init__(self, sig=signal.SIGINT):          self.sig = sig        def __enter__(self):            self.interrupted = False          self.released = False            self.original_handler = signal.getsignal(self.sig)            def handler(signum, frame):              self.release()              self.interrupted = True            signal.signal(self.sig, handler)            return self        def __exit__(self, type, value, tb):          self.release()        def release(self):            if self.released:              return False            signal.signal(self.sig, self.original_handler)            self.released = True            return True  

To use:

import time    /// do stuff:  with GracefulInterruptHandler() as h:      for i in xrange(1000):          print "..."          time.sleep(1)          if h.interrupted:              print "interrupted!"              time.sleep(5)              break    save_work()  

From here: https://gist.github.com/2907502


Solution:3

import signal    def signal_handler(signal, frame):         #do some stuff    def main():     #do some more stuff      if __name__=='__main__':      signal.signal(signal.SIGINT, signal_handler)      main()  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »