I have a problem with stack frames hanging around after exceptions in PyQt 
objects.

A particular method on a PyQt object is connected to a signal. This method 
is called because of the signal is raised.

If I get an uncaught exception in that method, then there appears to be a 
stack frame left around which doesn't get cleaned up. This means that the 
python part of the PyQt object isn't deleted until the end of the program 
(the C++ is, leading to the nasty exception about the C++ object not 
existing).

This wouldn't be so bad because you shouldn't leave uncaught exceptions, 
however if you use an exception hook then the same thing happens. You end up 
with PyQt objects which never get deleted until the end of the program.

There's an example program here. Click on the button to create a new dialog. 
If you close the dialog, __del__ gets called and prints a message. If you 
click on the exception button in the dialog first, __del__ never gets 
called.

You can insert gc.get_referrers to see the reference to the dialog appears 
to be in a frame object.

I assume this is a PyQt bug as I can't replicate it with pure Python, but 
it's not simple to reproduce.

Jeremy

-- 
http://www.jeremysanders.net/
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class DataCreateDialog(QDialog):
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        layout = QVBoxLayout()
        exceptionbutton = QPushButton("raise exception!", self)
        self.connect( exceptionbutton, SIGNAL('clicked()'),
                      self.exceptionButtonClicked )
        layout.addWidget(exceptionbutton)
        self.setLayout(layout)

    def exceptionButtonClicked(self):
        """Cause exception if button pressed"""
        print "here"
        xxx

    def __del__(self):
        print "deleted dialog okay", self
        
    def hideEvent(self, event):
        """Emits dialogFinished if hidden."""
        if not event.spontaneous():
            print "dialog got hide event", self
            self.emit( SIGNAL('dialogFinished'), self )
        return QDialog.hideEvent(self, event)

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        layout = QVBoxLayout()
        createbutton = QPushButton("make test dialog")
        self.connect( createbutton, SIGNAL('clicked()'),
                      self.createButtonClicked )
        layout.addWidget(createbutton)
        self.setLayout(layout)
        
    def createButtonClicked(self):
        """Create button pressed."""

        # make new dialog and keep reference
        self.d = DataCreateDialog(self)
        self.connect(self.d, SIGNAL('dialogFinished'), self.dialogFinished)
        self.d.show()

    def dialogFinished(self):
        """Delete reference."""
        del self.d

def excepthook(excepttype, exceptvalue, tracebackobj):
    return

#sys.excepthook = excepthook

app = QApplication([])
w = Window()
w.show()
app.exec_()

_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

Reply via email to