Exceptions from callbacks

Eric Dorland dorland at lords.com
Thu Nov 4 02:16:15 CET 1999


Randall Hopper wrote:
> I've done this, and I got the impression that Jonathan understood your
> question.  What he described works and it's what I'm using.
> 
> To extend your description, you don't say "Wake up, Python!" from the
> callback.  You say it from the C function(s) from which you entered the C
> library that invoked the callback.  Return NULL, and the exception is
> restarted with the Python stack frames saved in the callback in-tow.
> 
> To make this concrete, for a C library API that might potentially invoke a
> callback (which in-turn would relay to Python) would look like this:
> 
>   (Python) -> HandlePendingMessages -> MYLIB -> Callback -> (Python)
> 
> And your wrapper code might look like this:
> 
> ------------------------------------------------------------------------------
>   PyObject *_wrap_MYLIBHandlePendingMessages( PyObject *self, PyObject *args )
>   {
>     PyErr_Clear();
> 
>     <<< call C function here >>>
> 
>     /*  If a Python callback threw an exception, restart its propagation  */
>     /*    in the controlling Python.                                      */
>     if ( PyErr_Occurred() )
>       return NULL;
> 
>     ...
>   }
> 
> ------------------------------------------------------------------------------
>   static void _wrap_MYLIBCallback( void )
>     /*  C callback used to relay to Python callable objects.  */
>   {
>     ...
> 
>     /*  Pass the buck onto Python  */
>     pyresult = PyEval_CallObject( pyfunc, pyargs );     /*  Call Python     */
>     Py_DECREF( pyargs );                                /*  Trash arg list  */
>     if ( pyresult )
>       Py_DECREF( pyresult );                            /*  Trash any result*/
> 
>     /*  If the callback threw an exception, it will be propagated across    */
>     /*    the C layer ( we check PyErr_Occurred() on the other side).       */
>   }
> ------------------------------------------------------------------------------
> 
> If the Python callback tossed an exception, then it's still lying around
> when _wrap_MYLIBCallback() returns.  We then return through the C library,
> which eventually returns to _wrap_MYLIBHandlePendingMessages, who
> recognizes that a Python exception is pending and restarts its propagation
> in the controlling Python stack frames.
> 
> Note that if you have a C library layer that isn't Python-exception-aware,
> then it could go on to perform useless or invalid work after a Python
> callback throws an exception.  In this case you'll need to "make" it aware.
> That is, have it call PyErr_Occurred(), or turn Python exceptions into C
> library errors inside of your callback wrappers.
> 
> Hope this clarifies things a bit.

I understand what you mean exactly. The problem is I can't do it that
way. Basically, the way the library works is that you register a bunch
of callbacks and then call a function (eg. Loop()) that doesn't return.
The HandlePendingEvents (its equivalent I mean :)) isn't exposed by the
library, so I can't wrap it :). That's way I want a way to force the
interpreter to realize an exception is there. Is there a way, or a work
around, to do this?

-- 

Eric Dorland
dorland at lords.com




More information about the Python-list mailing list