On Tue, 27 Jul 2010 06:12:23 +0200, Sybren A. Stüvel <[email protected]>
wrote:
> Dear list,
> 
> I've just upgraded from PyQt 4.6 (PyQt-Py2.6-gpl-4.6-1.exe) to version
> 4.7.4 (PyQt-Py2.6-gpl-4.7.4-1.exe), and the upgrade introduced a crash
> in my program. I've narrowed it down to this example:
> 
>     from PyQt4 import QtCore, QtGui
> 
>     class Dialog(QtGui.QDialog):
>         def __init__(self, parent=None):
>             QtGui.QDialog.__init__(self, parent)
> 
>             self.resultsModel = QtGui.QStandardItemModel()
>             self.resultsModel.appendRow(QtGui.QStandardItem('Item 1'))
>             self.resultsModel.appendRow(QtGui.QStandardItem('Item 2'))
>             self.resultsModel.appendRow(QtGui.QStandardItem('Item 3'))
> 
>             self.layout = QtGui.QVBoxLayout(self)
>             self.resultsView = QtGui.QTreeView(self)
>             self.resultsView.setModel(self.resultsModel)
> 
>             self.layout.addWidget(self.resultsView)
>             
>             smodel = self.resultsView.selectionModel()
>             smodel.currentChanged.connect(self.on_change)
> 
>         @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex)
>         def on_change(self, current, previous):
>             print 'Changed from %s to %s' % (previous.row(),
current.row())
> 
>     app = QtGui.QApplication([])
>     win = Dialog()
>     win.show()
>     app.exec_()
> 
> The program crashes with this error:
> 
>     Traceback (most recent call last):
>       File "qttest.py", line 26, in <module>
>         win = Dialog()
>       File "qttest.py", line 19, in __init__
>         smodel.currentChanged.connect(self.on_change)
>     TypeError: on_change() has no overload that is compatible with
>     currentChanged(QModelIndex,QModelIndex)
> 
> When I remove the @QtCore.pyqtSlot() decorator the code runs just
> fine. It's a workaround, but I would prefer a clearner solution, or at
> least an understanding as to the cause of the exception.
> 
> The exception occurs when running on PyQt 4.7.4, Qt 4.6.2 and Python
> 2.6 on Windows XP.
> 
> The same code runs without error on PyQt 4.7.3, Qt 4.6.3 and Python
> 2.6 on Ubuntu Linux.

Should be fixed in tonight's snapshot - a patch is attached if you can't
wait.

As this is a regression I'll make a new PyQt release in a few days - once
I've had confirmation that the fix doesn't cause any other problems.

Thanks for the test case,
Phil
diff -r 17bbf4f4d4fc qpy/QtCore/qpycore_pyqtboundsignal.cpp
--- a/qpy/QtCore/qpycore_pyqtboundsignal.cpp	Sun Jul 25 21:51:46 2010 +0100
+++ b/qpy/QtCore/qpycore_pyqtboundsignal.cpp	Tue Jul 27 12:00:47 2010 +0100
@@ -617,8 +617,8 @@
         for (int ol = overload->parsed_arguments.count(); ol >= 0; --ol)
         {
             // If there are decorations then we compare the signal's signature
-            // against it so that we distinguish between Python types that are
-            // passed to Qt as PyQt_PyObject objects.  Qt will not make the
+            // against them so that we distinguish between Python types that
+            // are passed to Qt as PyQt_PyObject objects.  Qt will not make the
             // distinction.  If there are no decorations then let Qt determine
             // if a slot is available.
             if (decorations)
@@ -669,17 +669,45 @@
             const Chimera *sig_arg = signal->parsed_arguments.at(a);
             const Chimera *slot_arg = slot->parsed_arguments.at(a);
 
-            if (sig_arg->metatype() != slot_arg->metatype())
+            // The same type names must be compatible.
+            if (sig_arg->name() == slot_arg->name())
+                continue;
+
+            enum Match {
+                // The type is PyQt_PyObject because it was explicitly
+                // specified as such as a string.
+                MatchesAll,
+
+                // The type is PyQt_PyObject because it was specified as a type
+                // object that needed wrapping.
+                MatchesPyType,
+
+                // The type is something other than PyQt_PyObject.
+                MatchesName
+            };
+
+            Match sig_match, slot_match;
+
+            if (sig_arg->name() != "PyQt_PyObject")
+                sig_match = MatchesName;
+            else
+                sig_match = sig_arg->py_type() ? MatchesPyType : MatchesAll;
+
+            if (slot_arg->name() != "PyQt_PyObject")
+                slot_match = MatchesName;
+            else
+                slot_match = slot_arg->py_type() ? MatchesPyType : MatchesAll;
+
+            // They are incompatible unless one is called PyQt_PyObject.
+            if (sig_match == MatchesName || slot_match == MatchesName)
                 break;
 
-            if (sig_arg->metatype() != PyQt_PyObject::metatype)
+            // They are compatible if neither was a Python type.
+            if (sig_match == MatchesAll || slot_match == MatchesAll)
                 continue;
 
-            // See if the slot type was 'PyQt_PyObject'.
-            if (!slot_arg->py_type())
-                continue;
-
-            if (sig_arg->py_type() != slot_arg->py_type())
+            // The signal type can be a sub-type of the slot type.
+            if (!PyType_IsSubtype((PyTypeObject *)sig_arg->py_type(), (PyTypeObject *)slot_arg->py_type()))
                 break;
         }
 
_______________________________________________
PyQt mailing list    [email protected]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

Reply via email to