Python exception chains

Is there a standard way to use exception chains in Python? How is the Java exception thrown by '?

Here is the background.

I have a module with one main DSError exception DSError :

  class DSError(Exception): pass 

Somewhere inside this module 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 a DSError and tell me what happened and why. The thing is, the try block can throw many other exceptions, so I would prefer to do something like:

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

Is this the standard pythonic way? I have not seen the exception chain in other modules, so how is this done in Python?

+56
python coding-style exception
May 7 '13 at 8:39
source share
2 answers

The exception chain is only available in Python 3, where you can write:

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

which gives a similar output

 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 do not even need from ; Python 3 by default displays all exceptions that occurred during exception handling, for example:

 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, for example:

 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) 
+78
May 7, '13 at 8:48
source share

Is this what you are asking for?

 class MyError(Exception): def __init__(self, other): super(MyError, self).__init__(other.message) >>> try: ... 1/0 ... except Exception, e: ... raise MyError(e) Traceback (most recent call last): File "<pyshell#27>", line 4, in <module> raise MyError(e) MyError: division by zero 

If you want to keep the original exception object, you can do this in your own __init__ exception class. You might want to keep the trace, as the exception object itself does not contain much useful information about where the exception occurred:

 class MyError(Exception): def __init__(self, other): self.traceback = sys.exc_info() super(MyError, self).__init__(other.message) 

After that, you can access the traceback attribute of your exception to get information about the original exception. (Python 3 already provides this as the __traceback__ attribute of the __traceback__ object.)

+3
May 7 '13 at 8:47
source share



All Articles