11th November 2007
It has been said that one of Pyrex's strengths is that it inherits the full power of Python's exception catching. Unfortunately this statement became untrue with the advent of Python 2.5.
The reason for this is that under Python 2.5 exceptions have become
new-style classes and the Pyrex compiler code which checks for valid
exception types to be raised does not recognise them. This results in
Python returning with an exception - not the expected one, of course, but
a TypeError like this: TypeError: exceptions must be strings, classes
or instances, not [whatever the exception raised was].
The prana leaks from the code at c function __Pyx_Raise found
at line 3590 of Pyrex/Compiler/Node.py in the official release.
11th November 2007
One of the warlocks of the Pyrex circle, Stefan Behnel, has re-written the
__Pyx_Raise function in such a way that it works fine with
Python 2.5's new-style exceptions.
While this patch has not been incorporated into the official Pyrex code, I've seen it perform well in the context of Project Ouroborus.
For those interested in trying it out, simply copy and paste into the corresponding Pyrex module.
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
Py_XINCREF(type);
Py_XINCREF(value);
Py_XINCREF(tb);
/* First, check the traceback argument, replacing None with NULL. */
if (tb == Py_None) {
Py_DECREF(tb);
tb = 0;
}
else if (tb != NULL && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"raise: arg 3 must be a traceback or None");
goto raise_error;
}
/* Next, replace a missing value with None */
if (value == NULL) {
value = Py_None;
Py_INCREF(value);
}
/* Next, repeatedly, replace a tuple exception with its first item */
while (PyTuple_Check(type) && PyTuple_Size(type) > 0) {
PyObject *tmp = type;
type = PyTuple_GET_ITEM(type, 0);
Py_INCREF(type);
Py_DECREF(tmp);
}
if (PyString_CheckExact(type)) {
/* Raising builtin string is deprecated but still allowed --
* do nothing. Raising an instance of a new-style str
* subclass is right out. */
if (PyErr_Warn(PyExc_DeprecationWarning,
"raising a string exception is deprecated"))
goto raise_error;
}
else if (PyType_Check(type) || PyClass_Check(type))
; /* PyErr_NormalizeException(&type, &value, &tb); */
else if (PyInstance_Check(type)) {
/* Raising an instance. The value should be a dummy. */
if (value != Py_None) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto raise_error;
}
else {
/* Normalize to raise
11th November 2007
Related material: