[PyQt] Re: SIP bug with object lifetime

Phil Thompson phil at riverbankcomputing.co.uk
Sun May 13 11:41:26 BST 2007

On Friday 11 May 2007 4:07 pm, Giovanni Bajo wrote:
> Hi Phil,
> I've got another bug with object lifetimes:
> =========================================
> from qt import *
> import weakref
> app = QApplication([])
> ql = QListView(None)
> viewport = ql.viewport()
> o = QObject(viewport)
> o.xxx = viewport  # bug-trigger!
> destroyed = []
> def cb(wr):
>      destroyed.append(1)
> wr = weakref.ref(o, cb)
> del o
> del viewport
> assert not destroyed, "object destroyed too early #1!"
> import gc
> gc.collect()
> assert not destroyed, "object destroyed too early #2!"
> del ql
> import gc
> gc.collect()
> assert destroyed, "object never destroyed!"
> =========================================
> Traceback (most recent call last):
>    File "pyqtbug19.py", line 25, in ?
>      assert not destroyed, "object destroyed too early #2!"
> AssertionError: object destroyed too early #2!
> This happens with latest PyQt and SIP official releases (3.17.1 and
> 4.6). The line that seems to trigger the bug is the one marked with a
> comment.

This behaves as I would expect - ie. it's a missing feature rather than a bug.

Although ql is the parent of viewport, Python doesn't know that and there is 
no hidden extra reference to viewport to keep it alive when collect() is run.

The solution is to allow /Transfer/ to be used with method results, so the SIP 
specification would be...

    QWidget *viewport() const /Transfer/;

What this gives you is the ability to stash any data in objects created 
internally by Qt and know they won't get lost if you don't keep a reference 
around - which I guess is pretty neat.

I will implement this for SIP, but I'm not sure I'll use it in PyQt3 as it is 
effectively a new feature and PyQt3 is just about at the end of its life. 
However, if somebody gave me a list of the places it should be applied then 
I'd reconsider.


More information about the PyQt mailing list