Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python exception chaining [duplicate]

Is there a standard way of using exception chains in Python? Like the Java exception 'caused by'?

Here is some background.

I have a module with one main exception class DSError:

 class DSError(Exception):      pass 

Somewhere within this module there will be:

try:     v = my_dict[k]     something(v) except KeyError as e:     raise DSError("no key %s found for %s" % (k, self)) except ValueError as e:     raise DSError("Bad Value %s found for %s" % (v, self)) except DSError as e:     raise DSError("%s raised in %s" % (e, self)) 

Basically this snippet should throw only DSError and tell me what happened and why. The thing is that the try block might throw lots of other exceptions, so I'd prefer if I can do something like:

try:     v = my_dict[k]     something(v) except Exception as e:     raise DSError(self, v, e)  # Exception chained... 

Is this standard pythonic way? I did not see exception chains in other modules so how is that done in Python?

like image 797
Ayman Avatar asked May 07 '13 08:05

Ayman


People also ask

How to chain exceptions in Python?

To chain exceptions, use the raise from statement instead of a simple raise statement. This will give you information about both errors. except ValueError as e: raise RuntimeError( 'A parsing error occurred' ) from e...

How do you except multiple errors in Python?

By handling multiple exceptions, a program can respond to different exceptions without terminating it. In Python, try-except blocks can be used to catch and respond to one or multiple exceptions. In cases where a process raises more than one possible exception, they can all be handled using a single except clause.

What are chained exceptions?

Chained Exception helps to identify a situation in which one exception causes another Exception in an application. For instance, consider a method which throws an ArithmeticException because of an attempt to divide by zero but the actual cause of exception was an I/O error which caused the divisor to be zero.

How do you raise in Python 3?

The raise keyword is used to raise an exception. You can define what kind of error to raise, and the text to print to the user.


1 Answers

Exception chaining is only available in Python 3, where you can write:

try:     v = {}['a'] except KeyError as e:     raise ValueError('failed') from e 

which yields an output like

Traceback (most recent call last):   File "t.py", line 2, in <module>     v = {}['a'] KeyError: 'a'  The above exception was the direct cause of the following exception:  Traceback (most recent call last):   File "t.py", line 4, in <module>     raise ValueError('failed') from e ValueError: failed 

In most cases, you don't even need the from; Python 3 will by default show all exceptions that occured during exception handling, like this:

Traceback (most recent call last):   File "t.py", line 2, in <module>     v = {}['a'] KeyError: 'a'  During handling of the above exception, another exception occurred:  Traceback (most recent call last):   File "t.py", line 4, in <module>     raise ValueError('failed') ValueError: failed 

What you can do in Python 2 is adding custom attributes to your exception class, like:

class MyError(Exception):     def __init__(self, message, cause):         super(MyError, self).__init__(message + u', caused by ' + repr(cause))         self.cause = cause  try:     v = {}['a'] except KeyError as e:     raise MyError('failed', e) 
like image 185
phihag Avatar answered Sep 23 '22 04:09

phihag