Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-raise Python exception and preserve stack trace

I'm trying to catch an exception in a thread and re-raise it in the main thread:

import threading import sys  class FailingThread(threading.Thread):     def run(self):         try:             raise ValueError('x')         except ValueError:             self.exc_info = sys.exc_info()  failingThread = FailingThread() failingThread.start() failingThread.join()  print failingThread.exc_info raise failingThread.exc_info[1] 

This basically works and yields the following output:

(<type 'exceptions.ValueError'>, ValueError('x',), <traceback object at 0x1004cc320>) Traceback (most recent call last):   File "test.py", line 16, in <module>     raise failingThread.exc_info[1] 

However, the source of the exception points to line 16, where the re-raise occurred. The original exception comes from line 7. How do I have to modify the main thread so that the output reads:

Traceback (most recent call last):   File "test.py", line 7, in <module> 
like image 483
roskakori Avatar asked Jan 06 '12 15:01

roskakori


People also ask

How do you reraise an exception in Python?

Python Language Exceptions Re-raising exceptions In this case, simply use the raise statement with no parameters. But this has the drawback of reducing the exception trace to exactly this raise while the raise without argument retains the original exception trace.

Does raising an exception stop the program Python?

except block is completed and the program will proceed. However, if an exception is raised in the try clause, Python will stop executing any more code in that clause, and pass the exception to the except clause to see if this particular error is handled there.

What happens after raise exception in Python?

When an exception is raised, no further statements in the current block of code are executed. Unless the exception is handled (described below), the interpreter will return directly to the interactive read-eval-print loop, or terminate entirely if Python was started with a file argument.

How do you handle a raised exception?

In Python, exceptions can be handled using a try statement. The critical operation which can raise an exception is placed inside the try clause. The code that handles the exceptions is written in the except clause. We can thus choose what operations to perform once we have caught the exception.


2 Answers

In Python 2 you need to use all three arguments to raise:

raise failingThread.exc_info[0], failingThread.exc_info[1], failingThread.exc_info[2] 

passing the traceback object in as the third argument preserves the stack.

From help('raise'):

If a third object is present and not None, it must be a traceback object (see section The standard type hierarchy), and it is substituted instead of the current location as the place where the exception occurred. If the third object is present and not a traceback object or None, a TypeError exception is raised. The three-expression form of raise is useful to re-raise an exception transparently in an except clause, but raise with no expressions should be preferred if the exception to be re-raised was the most recently active exception in the current scope.

In this particular case you cannot use the no expression version.

For Python 3 (as per the comments):

raise failingThread.exc_info[1].with_traceback(failingThread.exc_info[2]) 

or you can simply chain the exceptions using raise ... from ... but that raises a chained exception with the original context attached in the cause attribute and that may or may not be what you want.

like image 58
Duncan Avatar answered Sep 17 '22 19:09

Duncan


This code snippet works in both python 2 & 3:

      1 try: ----> 2     raise KeyError('Default key error message')       3 except KeyError as e:       4     e.args = ('Custom message when get re-raised',) #The comma is not a typo, it's there to indicate that we're replacing the tuple that e.args pointing to with another tuple that contain the custom message.       5     raise 
like image 33
Steven Than Avatar answered Sep 18 '22 19:09

Steven Than