Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reraising an exception in Cython on Python 2 and Python3

I have some Cython code that currently looks

exc = sys.exc_info()
raise exc[0], exc[1], exc[2]

This doesn't work on Python3, since the "raise from tuple" form is no longer allowed. Were this normal Python code, I would just use six.reraise, but that's not available to me here. What's the Cython friendly way to do the same, which works on both Python2 and Python3?

like image 694
Alex Gaynor Avatar asked Sep 30 '22 20:09

Alex Gaynor


1 Answers

One great Cython feature is that the generated C code can be compiled for either Python 2 or Python 3. So your example above will work with either version of Python, unmodified.

You can tell Cython to compile code assuming Python 2 syntax and semantics (the -2 argument, which is on by default) or assuming Python 3 (the -3 argument). In either case, the resulting extension module source code can be compiled and used for Python 2 or Python 3, as long as the dynamic components (imports, etc.) are compatible.

For example:

def raises_exception():
    raise KeyError("what you doin'?")


def foobar():
    try:
        raises_exception()
    except Exception:
        import sys
        exc = sys.exc_info()
        raise exc[0], exc[1], exc[2]

Here's a setup.py that will work on either Py2 or Py3:

from distutils.core import setup
from Cython.Build import cythonize

setup(ext_modules=cythonize("reraise.pyx"))

I can run python setup.py build_ext -i on either version of Python (provided I have cython installed for each), and the resulting extension module will work.

$ python setup.py build_ext -i # Py3 python

$ ipython3
Python 3.3.2 (v3.3.2:d047928ae3f6, Oct  4 2013, 15:49:17)
Type "copyright", "credits" or "license" for more information.

IPython 1.2.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import reraise

In [2]: reraise.foobar()
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-2-9e20eacfd84e> in <module>()
----> 1 reraise.foobar()

/.../reraise.so in reraise.foobar (reraise.c:916)()

/.../reraise.so in reraise.foobar (reraise.c:847)()

/.../reraise.so in reraise.raises_exception (reraise.c:762)()

KeyError: "what you doin'?"

In [3]:
like image 193
lothario Avatar answered Oct 03 '22 10:10

lothario