R
Randall Hopper
What is the correct way to propagate exceptions from Python callbacks?
When I do this:
Python -> C++ -> Python Callback
(example attached) an exception raised in the callback doesn't make it back
across C++ to Python.
It appears that PyGILState_Release() at the bottom of the callback
wrapper is resetting the error state (as I can set a global based on
PyErr_Occurred() there, and can catch that up in the exception handler in
Python).
This obviously isn't correct. What should I be doing?
Thanks,
Randall
------------------------------------------------------------------------------
void callback_wrapper( void *user_data )
{
// Acquire interpreter lock
PyGILState_STATE gstate = PyGILState_Ensure();
...
// Call Python
pyresult = PyEval_CallObject( pyfunc, pyargs );
...
/*********** At this point, PyErr_Occurred() is true **************/
/****** But it's not true when we return through C++ to Python ******/
// Free interpreter lock
PyGILState_Release(gstate);
}
void registerCallback( PyObject *pyfunc )
{
...
// Ensure threads inited, so we can use Ensure/Release in callbacks
PyEval_InitThreads();
// Ref pyfunc
Py_INCREF( pyfunc );
// Call underlying C++ method, registering the above C++ callback
realRegisterCallback( callback_wrapper, pyfunc );
}
When I do this:
Python -> C++ -> Python Callback
(example attached) an exception raised in the callback doesn't make it back
across C++ to Python.
It appears that PyGILState_Release() at the bottom of the callback
wrapper is resetting the error state (as I can set a global based on
PyErr_Occurred() there, and can catch that up in the exception handler in
Python).
This obviously isn't correct. What should I be doing?
Thanks,
Randall
------------------------------------------------------------------------------
void callback_wrapper( void *user_data )
{
// Acquire interpreter lock
PyGILState_STATE gstate = PyGILState_Ensure();
...
// Call Python
pyresult = PyEval_CallObject( pyfunc, pyargs );
...
/*********** At this point, PyErr_Occurred() is true **************/
/****** But it's not true when we return through C++ to Python ******/
// Free interpreter lock
PyGILState_Release(gstate);
}
void registerCallback( PyObject *pyfunc )
{
...
// Ensure threads inited, so we can use Ensure/Release in callbacks
PyEval_InitThreads();
// Ref pyfunc
Py_INCREF( pyfunc );
// Call underlying C++ method, registering the above C++ callback
realRegisterCallback( callback_wrapper, pyfunc );
}