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