[PyQt] PyQt 5.7, QSqlQueryModel.data() sub-classed override bug?

J Barchan jnbarchan at gmail.com
Thu May 10 11:31:01 BST 2018

On 9 May 2018 at 15:36, J Barchan <jnbarchan at gmail.com> wrote:

> On 9 May 2018 at 14:53, Ricardo Araoz <ricaraoz at gmail.com> wrote:
>> On 09/05/18 05:57, Phil Thompson wrote:
>>>>> def data(self, index: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole)
>>>>>>> -> typing.Any:
>>>>>>>      was_enabled = sip.enableautoconversion(QtCore.QVariant, False)
>>>>>>>      value = super().data(index, role)
>>>>>>>      sip.enableautoconversion(QtCore.QVariant, was_enabled)
>>>>>>>      return value
>>>>  From your Python data() you call the C++ data(). This returns a
>>> QVariant to PyQt. With auto-conversion enabled this is converted to a
>>> Python value before being passed back to your Python data(). This loses the
>>> null information. Your Python data() then returns this value. The C++ code
>>> that invoked it requires a QVariant so (with auto-conversion enabled) PyQt
>>> first converts it back to a QVariant.
>>> The only way to keep the null information is to disable auto-conversion.
>>> This means that the object that your Python data() got back from calling
>>> the C++ data() is the QVariant (with intact null information). You then
>>> return this and it then makes its way back to the invoking C++.
>>> Phil
>>> _______________________________________________
>>> PyQt mailing list    PyQt at riverbankcomputing.com
>>> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>> Sorry to chime in but I also don't completely get it.
>> AFAIK the call to super() should return a reference to the parent class,
>> that is pyqt's QSqlQueryModel, not the C++ class. And in case there is a
>> reason for that (which I'm sure there is), is there a way to call the pyqt
>> parent class' data() method and not the c++ method?
>> Isn't there a way to call the pyqt method so that IT may call the c++
>> method and all would be nice? (I don't know, would "super(QSqlQueryModel,
>> self).data()" do the trick?)
>> In case there isn't, would there be a way to call the conversion method
>> pyqt's data() class uses and feed it the c++ data() results so that they
>> are properly converted in the same way it's done originally?
>> Because I understand Jonathan's concern that he wants a way to replicate
>> what would be going on if he hadn't subclassed the method.
>> TIA
>> Ricardo
>> _______________________________________________
>> PyQt mailing list    PyQt at riverbankcomputing.com
>> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
> ​Thanks for your moral support, Ricardo!  We shall see what Phil has to
> say, as only he can answer this.
> For my own part, ​having finally understood what was necessary, with great
> regret I am abandoning my whole PyQt sub-classing of this method and just
> having to manage without.  The outcome was that the *caller* code has to
> be changed to either execute .value() on every result (iff I do the
> sub-classing, which has to suppress the auto-conversion, and returns a
> QVariant), or not to do .value() (iff, say, I decide to get rid of my
> override at some point, and it returns native type).  The two are
> incompatible, and technically it is not possible to write calling code
> which works regardless of whether there is sub-classing going on.  I can
> see it's not PyQt/Phil's "fault", but that is very strange behaviour to
> accept in overriding a method, it would be expected to behave identically.
> I do not wish to carry that burden in my code, and/or have to change
> hundreds of callers in existing code.
> I'll keep an eye out in case Phil has something to say about your
> suggestions, as you guys understand much better than I.
> --
> Kindest,
> Jonathan

​Hi Phil,

Sorry, but I have one more related question about surprise behaviour.  I
will try to keep this as brief as possible.

Yesterday I came to understand why overriding, say, QSqlTableModel.data()
came to grief on database-NULL, because of the Python loss of distinction
on the QVariants representing ​"null" versus "default/invalid".  I would
get back the "default" value where I expected the "null" value.

In sorting my code out now in that light, I began to assume that
None) would effectively suffer from exactly the same problem, in the
opposite direction, i.e. it would set it to the "default" value not the
"null" one.  And so I would need to deal with too.

However, I find that, *whether I do or do not override* (in similar
fashion) QSqlTableModel.setData(index: QModelIndex, value: QVariant)  ​it
*does* set the value to database-NULL when called via .setData(index, None).

This surprises me, as I expected it to have the same QVariant conversion
issue over None as data(index) would.  Would you care to explain why this
does *not* appear to be the symmetrical problematic case?

Thank you in advance of your reply.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20180510/9a7f2810/attachment-0001.html>

More information about the PyQt mailing list