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