Awasu » Extending Python: Handling errors
Monday 4th November 2019 4:29 PM

Any robust code needs to handle error conditions, so we'll add some simple examples of how to return errors back to the calling Python code.

Using a standard Python exception

As an example, let's change our code to disallow negative values:

PyObject*
py_add( PyObject* pSelf, PyObject* pArgs )
{
    // extract the arguments
    int val1, val2 ;
    if ( ! PyArg_ParseTuple( pArgs, "ii", &val1, &val2 ) )
        return NULL ;

    // check the value
    if ( val1 < 0 || val2 < 0 ) {
        PyErr_SetString( PyExc_ValueError, "Can't handle negative values." ) ;
        return NULL ;
    }

    // add the numbers
    int result = val1 + val2 ;

    return PyLong_FromLong( result ) ;
}

If either of the values is negative, we call PyErr_SetString() to specify the type of exception we want to return to the caller (ValueError), and an error message.

Build and install the extension as before, and we can see it in action:

  

Note that this is equivalent to throw'ing a ValueError exception in Python code, and so it can be caught as such:

try:
    print( demo.add( 5, -2 ) )
except ValueError as ex:
    print( "ERROR: {}".format( ex ) )

Defining a custom exception class

If you want to use your own custom exception class, this needs to be set up when the module is loaded:

PyObject* gpZeroError = NULL ;

PyMODINIT_FUNC
PyInit_demo()
{
    // create the Python module
    PyObject* pModule = PyModule_Create( &gModuleDef ) ;
    if ( pModule == NULL )
        return NULL ;

    // create our custom exception
    gpZeroError = PyErr_NewException( "demo.ZeroError", NULL, NULL ) ;
    PyModule_AddObject( pModule, "ZeroError", gpZeroError ) ;

    return pModule ;
}

We call PyErr_NewException() to create a new exception class, then add it to the module.

This new exception class can now be used as any other:

if ( val1 == 0 || val2 == 0 ) {
    PyErr_SetString( gpZeroError, "Can't handle zero." ) ;
    return NULL ;
}
Download the source code here.


« Calling functions

Tutorial index

Callbacks »

Have your say