[Bf-python] Callback types

Yann Vernier yann at algonet.se
Mon Jan 17 06:47:36 CET 2005


On Mon, Jan 17, 2005 at 06:15:25AM +0100, Yann Vernier wrote:
> On Sun, Jan 16, 2005 at 12:43:58PM +0100, Michael Reimpell wrote:
> > I realized that I forgot to decrease the reference count after using the
> > callback. Although it will hardly matter, here is a patch with the missing line
> > added. It replaces the patch from my prevoius post.
> 
> And the reference the call itself returns, both bugs from the old code.
> 
> Great work! (:

And then I realized PyArg_ParseTuple borrows references. There is also
the possibility of exceptions to consider.

As it turns out, the callback decref probably should not be in 
getSelectedFile; that decref is performed on the argument tuple when 
M_Window_{File,Image}Selector returns. As such, those should also be
sure to clear EXPP_FS_PyCallback when they return. The return value
however is a new reference.


Exceptions occuring in the callback function should be propagated by
returning NULL; one potentially useful way to do this is by having a
second PyObject* for the return value. This gives us something like:

static struct {
  PyObject *callable;
  PyObject *retval;
} cb_state;

static void callback(char *str) {
  if (cb_state.callable) {
    cb_state.retval=PyObject_CallFunction(cb_state.callable, "s", str);
  } else {
    cb_state.retval=PyString_FromString(str)
  }
}

...function using callback initializes:
  ...ParseTuple..."|O", &cb_state.callable);
  cb_state.retval=NULL;
  if(cb_state.callable==Py_None)
    cb_state.callable=NULL;
...end of function using callback:
  cb_state.callable=NULL;
  if(cb_state.retval==NULL && !PyErr_Occurred()) {
    /* callback was not called */
    Py_INCREF(Py_None);
    return Py_None;
  } else {
    PyObject *v=cb_state.retval;
    cb_state.retval=NULL;
    return v;
  }
}

This gives a very simple callback function and a useful return value.
In fact it makes the callback optional, and this code is not reentrant
in the first place. Exceptions should be propagated, and the case of the
callback not being used can be detected. You do not have to make the
callback call in the callback function, either. 

The simpler way of propagating any exception is just to return NULL if
PyErr_Occurred().



More information about the Bf-python mailing list