[PyKDE] More sip on C fun!

Phil Thompson phil at riverbankcomputing.co.uk
Sat May 31 11:56:00 BST 2003


On Saturday 31 May 2003 9:52 am, Jonathan Gardner wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On Tuesday 20 May 2003 00:37, Phil Thompson wrote:
> > On Tuesday 20 May 2003 3:22 am, Jonathan Gardner wrote:
> > > 3) There is a callback function that I would like to use. How would I
> > > go about doing this in sip? What kind of function should I put as the
> > > callback? What kind of arguments should I expect from sip?
> > >
> > > Let's just keep it simple:
> > >
> > > The callback prototype: typedef void (*callback_func)(int);
> > >
> > > The "set callback" prototype: int set_callback(callback_func *);
> > > (And there is a corresponding release_callback() function as well, of
> > > course).
> > >
> > > What I would like to see in python:
> > >
> > > def callback(x):	print x
> > > set_callback(callback)
> > >
> > > how do I get from C to Python via sip?
> >
> > You will have to store the Python callback object somewhere (remembering
> > that there may be several of them around at a time). You will have to
> > provide a C callback that is permanently installed which will find the
> > correct Python callback object and use the standard Python API to call it
> > - after having converted the C callback arguments to the appropriate
> > Python equivalents.
> >
> > Phil
>
> Okay, I gave it a go.
>
> The actual prototype for the callback is:
>
> 	typedef void (*PQnoticeProcessor) (void *arg, const char *message);
>
> The actual function to set the callback is:
>
> 	extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
> 					 PQnoticeProcessor proc,
> 					 void *arg);
>
> 'arg' is whatever I want it to be. In this case, it is going to be a
> pointer to the "Conn" object I am wrapping.
>
> I add a member to Conn: PyObject noticeProcessor
> I make sure all the constructors set it to Py_None.
> I add the following method:
>
>         void setNoticeProcessor(PyObject *np) {
>             // Don't change anything if it is the same thing
>             if (np == noticeProcessor)
>                 return;
>
>             if (np == Py_None) {
>                 // Clear it out
>                 Py_DECREF(noticeProcessor);
>                 noticeProcessor = Py_None;
>                 Py_INCREF(noticeProcessor);
>                 PQsetNoticeProcessor(conn, NULL, NULL);
>             } else {
>                 // Set it up
>                 Py_DECREF(noticeProcessor);
>                 noticeProcessor = np;
>                 Py_INCREF(noticeProcessor);
>                 PQsetNoticeProcessor(conn, pyNoticeProcessor, (void
> *)this); }
>         }
>
> Looks pretty good, I think. Suggestions welcome, of course.

My coding style would use NULL rather than Py_None and...

void setNoticeProcessor(PyObject *np) {
    Py_XINCREF(np);
    Py_XDECREF(noticeProcessor);
    noticeProcessor = np;
    PQsetNoticeProcessor(conn, (np ? pyNoticeProcessor : NULL), (void *)this);
}

> I put this in the sip file:
>
> 	void setNoticeProcessor(int);
> %MemberCode
> 		PyObject *np;
> 		Conn *ptr;
>
> 		if (sipParseArgs(&sipArgsParsed,sipArgs,
> 			"mO",
>             sipThisObj,sipClass_Conn,&ptr,
> 			&np))
> 		{
> 			if (np != Py_None && !PyCallable_Check(np)) {
> 				PyErr_SetString(PyExc_ValueError,
> 				"NoticeProcessor must be a callable or None.");
> 				return NULL;
> 			}
>
> 			ptr->setNoticeProcessor(np);
>
> 			return Py_None;
> 		}
> %End
>
> I try to compile it. It complains about a double declaration of
> "pyNoticeProcessor". I had to put a declaration before Conn. So I switch it
> around - declare Conn, describe pyNoticeProcessor, then describe Conn. That
> won't work either.
>
> So I move the 'pyNoticeProcessor' body into a  %C++Code section in the sip
> file. The code doesn't show up anywhere in the cc files (it is declared
> outside of any class). I thought it would put the body in sippqcmodule.cc
> or something like that, which is what I really want (I think).

%C++Code outside of a class defintion should appear in the sippqcmodule file 
(although I'm not sure there is an example in PyQt at the moment).

Inside a class definition, the code should appear towards the start of the 
class specific generated code.

> But anyway, it compiles fine. It is only when I try to use it that it
> realizes there is no definition for pyNoticeProcessor. That is of course
> because the code wasn't put in any cc file that I could see.
>
> Any suggestions? I wanted to avoid making a new cc file manually, mostly
> because I am lazy. I am hoping there is a mechanism in sip to handle this
> sort of thing and throw it into sippqcmodule.cc.
>
> I finish this, and I will be done with the PostgreSQL interface, at least
> as far as it is reasonable to take it. I will release it to this list, and
> to the world immediately thereafter.
>
> Must sleep now... nearly 2:00 AM...

Phil




More information about the PyQt mailing list