How to exit Python nicely after error in embedded C code?

Robin Thomas robin.thomas at starmedia.net
Tue Feb 27 12:56:12 EST 2001


At 12:30 AM 2/27/01 -0500, Edward C. Jones wrote:
>Suppose I have a C function that is called only by other C functions (so it
>doesn't return a PyObject *). If I find an error condition in the the C
>function, is there function I can call that will exit the C code back into
>Python so Python can clean up and exit. The function is called by many 
>different
>C function in case of error.

Your "wrapper" C function -- the one that returns a PyObject* -- is of 
course responsible for doing all this work. In most all cases, Python 
expects your wrapper function to return a non-NULL PyObject* if no error 
occurred. If an error occurred, Python expects your wrapper function to set 
the exception state and return NULL. So:

PyObject *
mywrapperfunc (void)
{
     int result;
     result = my_pure_c_function();
     if ( result == -1 )
     {
         PyErr_SetString(PyExc_RuntimeError, "error in C func");
         return NULL;
     }
     /* on success, your wrapper function must return *some*
        valid PyObject; in this example, there is no "return value"
        from the pure C function, so you want to return None */
     /* new reference to None required */
     Py_INCREF(PyNone);
     return PyNone;
}

>int error_callback(int status, char * funcname) {
>     if (status != 0) {
>         printf("Error occured in %s\n", funcname);
>         /* Is this part of what I want: */
>         PyErr_SetString(PyExc_Exception, "Error in C function");
>         /* ... what goes here ... */
>     }
>     return 0;
>}

Very close, but instead of having a general function *decide* whether to 
set the Python exception state, use a general function only to set the 
exception state because you're *certain* that an exception must be set. And 
of course the general function must return the same type that your wrapper 
functions return -- PyObject*.

This approach occurs in Python's own source code. An example from 
Objects/abstract.c:

static PyObject *
type_error(const char *msg)
{
         PyErr_SetString(PyExc_TypeError, msg);
         return NULL;
}

and it's only used when a "wrapper" function wants to do an error. The 
wrapper function must do the work if there is no error. To merge the two 
examples:

static PyObject *
myerror(const char *msg)
{
         PyErr_SetString(PyExc_RuntimeError, msg);
         return NULL;
}

PyObject *
mywrapperfunc (void)
{
     int result;
     result = my_pure_c_function();
     if ( result == -1 )
     {
         /* use the new general error function */
         return myerror("my_pure_c_function bailed");
     }
     /* on success, your wrapper function must return *some*
        valid PyObject; in this example, there is no "return value"
        from the pure C function, so you want to return None */
     /* new reference to None required */
     Py_INCREF(PyNone);
     return PyNone;
}

Hope this helps.



--
Robin Thomas
Engineering
StarMedia Network, Inc.
robin.thomas at starmedia.net





More information about the Python-list mailing list