[PyKDE] ANN: New Releases of PyQt, PyKDE, SIP and QScintilla

Phil Thompson phil at riverbankcomputing.co.uk
Sun Sep 4 20:30:32 BST 2005


On Sunday 04 September 2005 7:51 pm, David Boddie wrote:
> On Thursday 01 September 2005 09:10, Phil Thompson wrote:
> > > I'm not sure where the changes have occurred but, without applying any
> > > patches of my own, I now find that:
> > >
> > >  * None of my KPart plugins work any more - the receivers for the
> > >    KActions I set up are never called. I'm still chasing this bug but
> > > it seems that, unlike C++ slots, Python functions/methods are never
> > > called. It seems that the Python slot is somehow transferred out of
> > > existance by the KAction because, if I assign the method to an instance
> > > variable (keeping a copy around), the slot is called when the action is
> > > activated.
>
> Just to provide an update - but still no test script, unfortunately - I've
> subsequently discovered that keeping another reference to the slot is also
> not sufficient to get the plugin to work. I've since discovered another,
> possibly more reliable, workaround is to keep a reference to the plugin in
> the object that creates it (an instance of a KLibFactory subclass):
>
> class FactoryClass(KLibFactory):
>
>     instance = None
>
>     def __init__(self, parent = None, name = None):
>
>         KLibFactory.__init__(self, parent, name)
>         if FactoryClass.instance is None:
>             FactoryClass.instance = KInstance("Highlighter")
>
>     def createObject(self, parent=None, name=None, class_name="QObject",
>                      args=None):
>         if args is None:
>             args = []
>
>         self.plugin = Highlighter(parent, name)
>         self.emit(SIGNAL("objectCreated(QObject)"), (self.plugin,))
>         return self.plugin
>
> > Got a test script? When a connection is made to a Python slot the
> > reference count of the slot is not increased (never has been). The
> > current garbage collection is much more "correct" than in previous
> > versions, so (perhaps) it's exposed an existing bug rather than created a
> > new one. Have you been using previous snapshots, or were you using
> > 4.2.1/3.14.1?
>
> I began to suspect that something is happening to the Python object when it
> is returned by the createObject() method. The code for the createObject()
> function in sipKLibFactory uses another function to call the relevant
> Python method, if it has been implemented:
>
> QObject * sipVH_kdecore_29(sip_gilstate_t sipGILState, PyObject *sipMethod,
>           QObject *a0, const char *a1, const char *a2, const QStringList
> &a3) {
>  QObject * sipRes = 0;
>  PyObject *sipResObj = sipCallMethod(0, sipMethod, "MssO", a0,
>             sipClass_QObject, a1, a2, const_cast<QStringList*>(&a3),
>             sipClass_QStringList);
>
>  if (!sipResObj || sipParseResult(0, sipMethod, sipResObj, "L",
>             sipForceConvertTo_QObject, &sipRes) < 0)
>   PyErr_Print();
>
>  Py_XDECREF(sipResObj);
>  Py_DECREF(sipMethod);
>
>  SIP_RELEASE_GIL(sipGILState)
>
>  return sipRes;
> }
>
> My question is: doesn't the call to Py_XDECREF(sipResObj) cause problems
> for Python objects that have gone out of scope? For example, if I don't
> store the plugin in the factory and use
>
>         plugin = Highlighter(parent, name)
>         self.emit(SIGNAL("objectCreated(QObject)"), (plugin,))
>         return plugin
>
> instead, it seems that it is collected. To test this, I implemented a
> __del__ method in my Highlighter class to print a message when this occurs
> and, sure enough, it appeared just after the plugin was created. Keeping a
> reference to the plugin means that I never see this message. :-/

It looks like the KLibFactory::createObject() SIP specification is missing 
a /Factory/ annotation. This cause the generated virtual handler to transfer 
ownership to C++ before calling Py_XDECREF(sipResObj) so the C++ dtor doesn't 
get called when sipResObj is garbage collected.

If you are reimplementing createObject() then (I think) you will need to do 
the same...

    sip.transferto(plugin, None)
    return plugin

Phil




More information about the PyQt mailing list