Context Suppression in Python Exceptions

Catching and re-raising a different exception
It is sometimes useful to catch one exception and raise another exception. For example, a higher software layer may not care where exactly an algorithm fails, but merely that the input is invalid. Or it may not care which parsing routine fails, just that the data was truncated.

For example:

def process(iterable): try: x = next(iterable) except StopIteration: raise ValueError("can't process empty iterable") continue_processing

def reciprocal(x): try: return 1/x except ZeroDivisionError: raise ValueError("divisor must not be zero")

Python 2 Output
In Python 2,  only displays the inner exception:

Traceback (most recent call last): File "test.py", line 12, in     reciprocal(0) File "test.py", line 10, in reciprocal raise ValueError("divisor must not be zero") ValueError: divisor must not be zero

Python 3 Output: Exception Context
In Python 3,  displays the context of the exception as well:

Traceback (most recent call last): File "test.py", line 8, in reciprocal return 1/x ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "test.py", line 12, in     reciprocal(0) File "test.py", line 10, in reciprocal raise ValueError("divisor must not be zero") ValueError: divisor must not be zero

Python 3 Output: Exception Cause
In Python 3 it is possible to set the cause of an Exception, which displays a similar message:

raise ValueError("divisor must not be zero") from ZeroDivisionError('division by zero')

which prints:

ZeroDivisionError: division by zero The above exception was the direct cause of the following exception: Traceback (most recent call last): File "test.py", line 13, in     raise ValueError("divisor must not be zero") from ZeroDivisionError('division by zero') ValueError: divisor must not be zero

Suppressing Context in Python 3.3
In Python 3.3 is possible to suppress the context by setting the cause to None:

def reciprocal(x): try: return 1/x except ZeroDivisionError: raise ValueError("divisor must not be zero") from None

which prints:

Traceback (most recent call last): File "test.py", line 12, in     reciprocal(0) File "test.py", line 10, in reciprocal raise ValueError("divisor must not be zero") from None ValueError: divisor must not be zero

Python 2 Valid Syntax for Suppressing Context
is not valid Python 2 syntax. If you want to write your code such that it works with Python 2, the following syntax is equivalent:

def reciprocal(x): try: return 1/x except ZeroDivisionError: _exception = ValueError("divisor must not be zero") _exception.__cause__ = None raise _exception

Suppressing Context in Python 3.1 and 3.2
The above code will still print the exception in Python 3.1 and Python 3.2. If you want to suppress the context there too, the following hack-ish solutions works accross all Python versions (2.6, 2.7 and 3):

_exception = None try: i = 1/0 except ZeroDivisionError as e:    _exception = ValueError("divisor must not be zero") finally: if _exception: raise _exception