Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Getting a traceback from a multiprocessing.Process

I am trying to get hold of a traceback object from a multiprocessing.Process. Unfortunately passing the exception info through a pipe does not work because traceback objects can not be pickled:

def foo(pipe_to_parent):     try:         raise Exception('xxx')     except:         pipe_to_parent.send(sys.exc_info())  to_child, to_self = multiprocessing.Pipe() process = multiprocessing.Process(target = foo, args = (to_self,)) process.start() exc_info = to_child.recv() process.join() print traceback.format_exception(*exc_info) to_child.close() to_self.close() 

Traceback:

Traceback (most recent call last):   File "/usr/lib/python2.6/multiprocessing/process.py", line 231, in _bootstrap     self.run()   File "/usr/lib/python2.6/multiprocessing/process.py", line 88, in run     self._target(*self._args, **self._kwargs)   File "foo", line 7, in foo     to_parent.send(sys.exc_info()) PicklingError: Can't pickle <type 'traceback'>: attribute lookup __builtin__.traceback failed 

Is there another way to access the exception info? I'd like to avoid passing the formatted string.

like image 688
knipknap Avatar asked May 25 '11 14:05

knipknap


People also ask

How do I get data back from multiprocessing in Python?

Items can be retrieved from the queue by calls to get(). By default, the call to get() will block until an item is available to retrieve from the queue and will not use a timeout. You can learn more about multiprocessing queues in the tutorial: Multiprocessing Queue in Python.

How do you capture a traceback in Python?

Method 1: By using print_exc() method. This method prints exception information and stack trace entries from traceback object tb to file.

How do you catch exceptions in multiprocessing?

If a task issued asynchronously raises an exception, it will be caught by the process pool and re-raised if you call get() function in the AsyncResult object in order to get the result. It means that you have two options for handling exceptions in tasks, they are: Handle exceptions within the task function.


1 Answers

Using tblib you can pass wrapped exceptions and reraise them later:

import tblib.pickling_support tblib.pickling_support.install()  from multiprocessing import Pool import sys   class ExceptionWrapper(object):      def __init__(self, ee):         self.ee = ee         __, __, self.tb = sys.exc_info()      def re_raise(self):         raise self.ee.with_traceback(self.tb)         # for Python 2 replace the previous line by:         # raise self.ee, None, self.tb   # example of how to use ExceptionWrapper  def inverse(i):     """ will fail for i == 0 """     try:         return 1.0 / i     except Exception as e:         return ExceptionWrapper(e)   def main():     p = Pool(1)     results = p.map(inverse, [0, 1, 2, 3])     for result in results:         if isinstance(result, ExceptionWrapper):             result.re_raise()   if __name__ == "__main__":     main() 

So, if you catch an exception in your remote process, wrap it with ExceptionWrapper and then pass it back. Calling re_raise() in the main process will do the work.

like image 180
rocksportrocker Avatar answered Sep 28 '22 17:09

rocksportrocker