Skip to content
Snippets Groups Projects
Select Git revision
  • 4b30c69101a272fbcbfefb4c697e2df6aee4b503
  • master default
  • pcl_expect_0_1_0
3 results

spawn.py

Blame
  • remote_exception.py 2.93 KiB
    """Exception handling for remote processes.
    
       If you have a controller process that spawns a child process, and
       an unexpected exception occurs in the child process, you often want
       to report it via the controller process.  Perhaps it can be handled
       in the controller process.  At the very least, you want to get a
       traceback from the child process.
    
       This module defines a new exception, Remote, which encapsulates any
       other exception (as long as the other exception only contains data
       that can be cPickled).  It also provides two functions:
    
        - serialize: call this in an exception handler in the child
          process.  It will create a Remote exception based on
          sys.exc_info(), serialize it, and return it as a string.
    
        - re_raise: when given a string produced by serialize(), it will
          raise the Remote exception.
    
       This module does not attempt to transfer the serialized exception
       from the child process to the controller process.  It is assumed
       that you already have a channel where that can be done.
    
       Typical usage:
    
       In the client:
    
           try:
               # Code that can raise an exception
           except:
               x = remote_exception.serialize()
               # Somehow send x to the controller.
    
       In the server:
    
           # Somehow receive the serialized string into x.
           remote_exception.re_raise(x)
    
       See the test code at the end of this module for working demo code.
    """
    
    import sys
    import cPickle
    import traceback
    
    class Remote(Exception):
        """An exception occured in a remote process.
        
           This exception defines these attributes:
    
            - exc_type  -- The type of the original exception.
            - exc_value -- The value of the original exception.
            - traceback -- A preformatted traceback string, ready for
                           printing (or writing to a log file, et c).
        """
    
        def __init__(self):
            """Create a Remote exception.
    
               The exception data will be gathered using sys.exc_info(),
               so this must be created inside an except clause.
            """
            self.exc_type, self.exc_value, tb = sys.exc_info()
            self.traceback = ''.join(traceback.format_exception(
                self.exc_type, self.exc_value, tb))
            Exception.__init__(self, self.exc_type.__name__, str(self.exc_value))
    
    def serialize():
        """Create a Remote exception, serialize it, and return the string.
    
           This must be called from within an except clause.
    
        """
    
        x = Remote()
        return cPickle.dumps(x, cPickle.HIGHEST_PROTOCOL)
    
    def re_raise(s):
        """Decode a serialized Remote exception, and raise it."""
    
        raise cPickle.loads(s)
    
    # Demo code follows.
    if __name__ == "__main__":
        try:
            x
        except:
            y = serialize()
    
        try:
            re_raise(y)
        except Remote, z:
            print "Remote exception follows:"
            print z.traceback
            print "The exception was re-generated here:"
            print ''.join(traceback.format_exception(*sys.exc_info()))