How can I port this code to Python 3 so that it would run in both, Python 2 and Python3?
raise BarException, BarException(e), sys.exc_info()[2]
(copied from http://blog.ionelmc.ro/2014/08/03/the-most-underrated-feature-in-python-3/)
Bonus question
Does it make sense to do something like
IS_PYTHON2 = sys.version_info < (3, 0)
if IS_PYTHON2:
raise BarException, BarException(e), sys.exc_info()[2]
# replace with the code that would run in Python 2 and Python 3 respectively
else:
raise BarException("Bar is closed on Christmas")
You'll have to resort to using exec()
because you cannot use the 3-argument syntax in Python 3; it'll raise a syntax error.
As always the six
library already has you covered, ported to not depend on other six
definitions their version looks like this:
import sys
if sys.version_info[0] == 3:
def reraise(tp, value, tb=None):
if value is None:
value = tp()
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
else:
exec("def reraise(tp, value, tb=None):\n raise tp, value, tb\n")
Now you can use:
reraise(BarException, BarException(e), sys.exc_info()[2])
without further testing for a Python version.
Six provides simple utilities for wrapping over differences between Python 2 and Python 3. It is intended to support codebases that work on both Python 2 and 3 without modification. six consists of only one Python file, so it is painless to copy into a project. http://pythonhosted.org/six/
from six import reraise as raise_ # or from future.utils import raise_
traceback = sys.exc_info()[2]
err_msg = "Bar is closed on Christmas"
raise_(ValueError, err_msg, traceback)
You can make a Python 3 copy of the code using 2to3.
2to3 is a Python program that reads Python 2.x source code and applies a series of fixers to transform it into valid Python 3.x code. The standard library contains a rich set of fixers that will handle almost all code. 2to3 supporting library lib2to3 is, however, a flexible and generic library, so it is possible to write your own fixers for 2to3. lib2to3 could also be adapted to custom applications in which Python code needs to be edited automatically.
...
2to3 can also write the needed modifications right back to the source file. (Of course, a backup of the original is also be made unless -n is also given.) Writing the changes back is enabled with the -w flag:
$ 2to3 -w example.py
(from https://docs.python.org/3.0/library/2to3.html)
If you want to determine the python version, I recommend:
PY2 = sys.version_info.major == 2
PY3 = sys.version_info.major == 3
# or
import six # Python 2 / 3 compatability module
six.PY2 # is this Python 2
six.PY3 # is this Python 3
Don't forget that early versions of Python 2 will vary from 2.7. I like to plan for all contingencies, so the following code takes exception (litteraly) if a Python version prior to 2.7 is used.
# If you want to use and if/then/else block...
import sys
major = sys.version_info.major
minor = sys.version_info.minor
if major == 3: # Python 3 exception handling
print("Do something with Python {}.{} code.".format(major, minor))
elif major == 2: # Python 2 exception handling
if minor >= 7: # Python 2.7
print("Do something with Python {}.{} code.".format(major, minor))
else: # Python 2.6 and earlier exception handling
assert minor >= 2, "Please use Python 2.7 or later, not {}.{}.".format(major,minor)
else:
assert major >= 2, "Sorry, I'm not writing code for pre-version 2 Python. It just ain't happening. You are using Python {}.{}.".format(major,minor)
assert major > 3, "I can't handle Python versions that haven't been written yet.. You are using Python {}.{}.".format(major,minor)
python-future is the missing compatibility layer between Python 2 and Python 3. It allows you to use a single, clean Python 3.x-compatible codebase to support both Python 2 and Python 3 with minimal overhead.
It provides future and past packages with backports and forward ports of features from Python 3 and 2. It also comes with futurize and pasteurize, customized 2to3-based scripts that helps you to convert either Py2 or Py3 code easily to support both Python 2 and 3 in a single clean Py3-style codebase, module by module. http://python-future.org/overview.html
See python's future module documentation at http://python-future.org/. Below is a copy of the Raising Excettions and Cathcing Exceptions portions of the page.
import future # pip install future
import builtins # pip install future
import past # pip install future
import six # pip install six
raise ValueError, "dodgy value"
raise ValueError("dodgy value")
Raising exceptions with a traceback:
traceback = sys.exc_info()[2]
raise ValueError, "dodgy value", traceback
raise ValueError("dodgy value").with_traceback()
from six import reraise as raise_
# or
from future.utils import raise_
traceback = sys.exc_info()[2]
raise_(ValueError, "dodgy value", traceback)
from future.utils import raise_with_traceback
raise_with_traceback(ValueError("dodgy value"))
Exception chaining (PEP 3134):
class DatabaseError(Exception):
pass
class FileDatabase:
def __init__(self, filename):
try:
self.file = open(filename)
except IOError as exc:
raise DatabaseError('failed to open') from exc
from future.utils import raise_from
class FileDatabase:
def __init__(self, filename):
try:
self.file = open(filename)
except IOError as exc:
raise_from(DatabaseError('failed to open'), exc)
try:
fd = FileDatabase('non_existent_file.txt')
except Exception as e:
assert isinstance(e.__cause__, IOError) # FileNotFoundError on Py3.3+ inherits from IOError
try:
...
except ValueError, e:
...
try:
...
except ValueError as e:
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With