[PyQt] Bug Report: pyqt5 discard silently signal with missing optional parameters (dataChanged roles for example)

Phil Thompson phil at riverbankcomputing.com
Fri Jan 10 22:59:06 GMT 2014


On 10-01-2014 10:08 pm, Baptiste Lepilleur wrote:
> The issue is demonstrated in the attached example (pyqt 5.2, python
> 3.3). Below is the relevant excerpt:
>
> class ListModel(QAbstractItemModel):
>     def __init__(self, parent=None):
>         super(ListModel, self).__init__(parent)
>
>     def testEmit(self):
>         # This signal is silently dropped by pyqt (missing
> optional 3rd parameters). Why?
>         self.dataChanged.emit(self.createIndex(1,0),
> QModelIndex())
>         # This signal is sent as expected
>         self.dataChanged.emit(self.createIndex(2,0),
> QModelIndex(), [])
>
> * Bug description:
>
> The signal QAbstractItemModel::dataChanged has the following
> signature:
> void QAbstractItemModel::dataChanged(
>     const QModelIndex & topLeft, 
>     const QModelIndex & bottomRight, 
>     const QVector<int> & roles = QVector<int> ())
>
> If the optional roles parameters is not given when calling emit, the
> signal emission is discarded without any error reporting.
>
> For example:
>
>         self.dataChanged.emit(self.createIndex(1,0),
> QModelIndex())
>
> Below is the output of the attached example showing that the expected
> first emit "onDataChanged 1" is missing:
>
> C:Python33python.exe debugemit.py
>  onDataChanged 2
> ------------done-------------
>
> * Work-around:
>
> Pass the optional roles signal parameter:
>
>         self.dataChanged.emit(self.createIndex(2,0),
> QModelIndex(), [])
>
> * Remarks:
>
> This bug usually goes unseen because the views are usually
> automatically refreshed if the mouse if moved over the view 
> associated
> to the model.
>
> It was exposed by a model shared by multiple editable views with a
> custom setData(). It took many hours to figure out the root cause of
> the lack of refresh.
>
> IMHO a fairly serious bug as Ive never seen an example of
> dataChanged.emit() with the roles parameter...
>
> Lets me know if the above is unclear or more details are required, Id
> hate to see anyone else losing time on this issue,
> Baptiste.

Qt signals with an optional argument are actually implemented as two 
separate signals. One with the argument and one without it. PyQt treats 
the first as the default (ie. the one that doesn't require an explicit 
signature to select it). PyQt 5.2 included a change that meant you 
didn't have to specify an explicit signature to emit() because it works 
out the one you mean by the number of arguments you have passed to it.  
connect() cannot do the same thing because it doesn't have the 
information. You are only connecting the default signal - there is no 
connection made to the 2 argument signal, so your first call to emit() 
is ignored.

I'll have a think to see if I can find some way to make it work more 
naturally.

Phil


More information about the PyQt mailing list