Mailing List Archive

Extension types as exceptions (Wrapup)
Thanks for the help,

for those with similar problems, code to create the exception type
follows:

static PyObject *
createExceptionKind (
const char * exceptionName,
const char * exceptionCode)
{
PyObject * result;
PyObject * runResult = NULL;
PyObject * globals = NULL;
PyObject * locals = NULL;

if (exceptionCode != NULL) {
globals = PyDict_New ();
locals = PyDict_New ();
runResult = PyRun_String ((char *) exceptionCode,\
Py_file_input,
globals, locals);
}
result = PyErr_NewException ((char *) exceptionName, \
NULL,locals);
Py_XDECREF (locals);
Py_XDECREF (globals);
Py_XDECREF (runResult);
return result;
}

Parameter exceptionName is something of the form "mymod.ExceptionName"
Parameter exceptionCode is something like
"def __str__ (self):\n return 'ExceptionName: %d %s' % (self.code,
self.msg\n"

Error handling is a bit weak as I call this from module
initialization, which does it's own checking

Code to create a new exception:

static void
raiseError (
int code,
const char * msg)
{
PyObject * exception = PyInstance_New (ErrorType, NULL, NULL);

if (exception == NULL) {
return;
}
PyObject_SetAttrString(exception,"code", PyInt_FromLong (code));
PyObject_SetAttrString(exception,"msg", PyString_FromString(msg));
PyErr_SetObject (ErrorType, exception);
}

ErrorType is a c module static which contains the result of
createExceptionKind
Extension types as exceptions (Wrapup) [ In reply to ]
Daniel Dittmar <daniel.dittmar@sap-ag.de> wrote:
: Thanks for the help,

: for those with similar problems, code to create the exception type
: follows:

: static PyObject *
: createExceptionKind (
: const char * exceptionName,
: const char * exceptionCode)
: {
: PyObject * result;
: PyObject * runResult = NULL;
: PyObject * globals = NULL;
: PyObject * locals = NULL;

: if (exceptionCode != NULL) {
: globals = PyDict_New ();
: locals = PyDict_New ();
: runResult = PyRun_String ((char *) exceptionCode,\
: Py_file_input,
: globals, locals);
: }
: result = PyErr_NewException ((char *) exceptionName, \
: NULL,locals);
: Py_XDECREF (locals);
: Py_XDECREF (globals);
: Py_XDECREF (runResult);
: return result;
: }

: Parameter exceptionName is something of the form "mymod.ExceptionName"
: Parameter exceptionCode is something like
: "def __str__ (self):\n return 'ExceptionName: %d %s' % (self.code,
: self.msg\n"

: Error handling is a bit weak as I call this from module
: initialization, which does it's own checking

: Code to create a new exception:

: static void
: raiseError (
: int code,
: const char * msg)
: {
: PyObject * exception = PyInstance_New (ErrorType, NULL, NULL);

: if (exception == NULL) {
: return;
: }
: PyObject_SetAttrString(exception,"code", PyInt_FromLong (code));
: PyObject_SetAttrString(exception,"msg", PyString_FromString(msg));
: PyErr_SetObject (ErrorType, exception);
: }

: ErrorType is a c module static which contains the result of
: createExceptionKind

You could probably also do:

PyObject *exc_args;
exc_args = Py_BuildValue("is", code, msg);
PyErr_SetObject(ErrorType, exc_args);

If the data isn't an exception instance, it creates one with the data
given.

As a good tip, return (PyObject *)NULL in your function, this lets you
use in your code:
return raiseError(27, "I don't know what happened");

instead of:
{ raiseError(27, "I don't know what happened");
return NULL;
}

-Arcege
Extension types as exceptions (Wrapup) [ In reply to ]
My code creates an actual instance of the exception class, which might
be a bit more self documenting (as the attributes have names) and is
easier to handle when there are many attributes.

This has the one disadvantage that you have to create a __str__ method
for the class (that's what the exceptionCode parameter in
createExceptionKind is for), because without it, a traceback will show
only the class name.

Actually, my current code first tries to create the instance. If this
fails, it will try to create the tuple.

There is a reference counting error in my raiseError routine:
PyInt_FromLong (code) will set the ref count to 1,
PyObject_SetAttrString will set it to 2, so the object can never be
reclaimed.

The hopefully correct version is:

static PyObject*
raiseCommunicationError (
int code,
const char * msg)
{
PyObject * exception = PyInstance_New (CommunicationErrorType,
NULL, NULL);
PyObject * pycode = NULL;
PyObject * pymsg = NULL;

pycode = PyInt_FromLong (code);
pymsg = PyString_FromString (msg);
if (exception != NULL) {
PyObject_SetAttrString (exception, "errorCode", pycode) ;
PyObject_SetAttrString (exception, "message", pymsg);
Py_XDECREF (pycode);
Py_XDECREF (pymsg);
}
else {
exception = Py_BuildValue ("NN", pycode, pymsg);
}
PyErr_SetObject (CommunicationErrorType, exception);
return NULL;
}


Daniel Dittmar
daniel.dittmar@sap-ag.de
SAP AG, Basis Entwicklung Berlin