Python Language Incompatibilities moving from Python 2 to Python 3 Raising and handling Exceptions

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Extensions
> Step 2: And Like the video. BONUS: You can also share it!

Example

This is the Python 2 syntax, note the commas , on the raise and except lines:

Python 2.x2.3
try:
    raise IOError, "input/output error"
except IOError, exc:
    print exc

In Python 3, the , syntax is dropped and replaced by parenthesis and the as keyword:

try:
    raise IOError("input/output error")
except IOError as exc:
    print(exc)

For backwards compatibility, the Python 3 syntax is also available in Python 2.6 onwards, so it should be used for all new code that does not need to be compatible with previous versions.


Python 3.x3.0

Python 3 also adds exception chaining, wherein you can signal that some other exception was the cause for this exception. For example

try:
    file = open('database.db')
except FileNotFoundError as e:
    raise DatabaseError('Cannot open {}') from e

The exception raised in the except statement is of type DatabaseError, but the original exception is marked as the __cause__ attribute of that exception. When the traceback is displayed, the original exception will also be displayed in the traceback:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
FileNotFoundError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')

If you throw in an except block without explicit chaining:

try:
    file = open('database.db')
except FileNotFoundError as e:
    raise DatabaseError('Cannot open {}')

The traceback is

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
FileNotFoundError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
Python 2.x2.0

Neither one is supported in Python 2.x; the original exception and its traceback will be lost if another exception is raised in the except block. The following code can be used for compatibility:

import sys
import traceback

try:
    funcWithError()
except:
    sys_vers = getattr(sys, 'version_info', (0,))
    if sys_vers < (3, 0):
        traceback.print_exc()
    raise Exception("new exception")
Python 3.x3.3

To "forget" the previously thrown exception, use raise from None

try:
    file = open('database.db')
except FileNotFoundError as e:
    raise DatabaseError('Cannot open {}') from None

Now the traceback would simply be

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')

Or in order to make it compatible with both Python 2 and 3 you may use the six package like so:

import six
try:
    file = open('database.db')
except FileNotFoundError as e:
    six.raise_from(DatabaseError('Cannot open {}'), None)


Got any Python Language Question?