[PyQt] PyQt 5.7, QSqlQueryModel.data() sub-classed override bug?
J Barchan
jnbarchan at gmail.com
Thu May 3 14:54:52 BST 2018
Ah ha! I read in
https://www.riverbankcomputing.com/pipermail/pyqt/2016-April/037326.html:
>>>>
* I am currently updating QGIS to PyQt5 (and Qt5 and Python3)>>>>
Since this update, NULL QVariant strings are converted to empty
strings '' and all numbers to 0 when converted from C++ to python
objects.*
And that is exactly what I am experiencing: the string-NULL is giving me
empty string and the int-NULL is giving me 0. So isn't this a PyQt issue I
am seeing after all??
On 3 May 2018 at 14:50, J Barchan <jnbarchan at gmail.com> wrote:
> Hang on. This is an area I do not understand, doubtless you do.
>
> The C++ QSqlQueryModel::data() method is supposed to return a QVariant.
> Am I maybe losing the QVariant-ness when I write my own PyQt overload
> which returns the base method's result, because Python-esque conversion is
> going on?
>
> I'm trying to understand http://pyqt.sourceforge.net/
> Docs/PyQt5/pyqt_qvariant.html, but I don't really. I do note:
> > There is no obvious way to represent a null QVariant
> <http://pyqt.sourceforge.net/Docs/PyQt5/api/QtCore/qvariant.html#PyQt5-QtCore-QVariant>
> as a standard Python object.
>
> Is there a connection between this and the fact that it goes wrong when
> the value it should be returning is the NULL returned from the SQL query?
>
> On 3 May 2018 at 13:55, J Barchan <jnbarchan at gmail.com> wrote:
>
>>
>>
>> On 3 May 2018 at 13:05, Phil Thompson <phil at riverbankcomputing.com>
>> wrote:
>>
>>> On 3 May 2018, at 12:25 pm, J Barchan <jnbarchan at gmail.com> wrote:
>>> >
>>> >
>>> > I am finding (in PyQt 5.7 at least) that sub-classing QSqlQueryModel
>>> and overriding its data() method produces an incorrect result when the
>>> value retrieved from a MySQL database is NULL.
>>> >
>>> > Full details are in https://forum.qt.io/topic/9036
>>> 3/inexplicable-qsqlquerymodel-handling-of-null-value, and particularly
>>> post # https://forum.qt.io/topic/90363/inexplicable-qsqlquerymodel-
>>> handling-of-null-value. Nobody has tried it in C++ for me to date to
>>> verify, but I'm suspecting this might be a PyQt bug?
>>> >
>>> > Briefly:
>>> > My SELECT query returns a column which is NULLable, and has NULL as
>>> its value. Where I expect "blank" as the end value, I actually get, for
>>> example, 0 if the column type is int or '' if the type is string, etc.
>>> >
>>> > This is when I sub-class QSqlQueryModel. If all I have is:
>>> > class DBQueryModel(QtSql.QSqlQueryModel):
>>> > def __init__(self, parent=None):
>>> > super().__init__(parent)
>>> > I get the "NULL"/"blank". However, as soon as I add just:
>>> > def data(self, index: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole)
>>> -> typing.Any:
>>> > return super().data(index, role)
>>> > I get those values instead of NULL.
>>> >
>>> > Note that my override is based on the Qt definition of the method at
>>> http://doc.qt.io/qt-5/qsqlquerymodel.html#data:
>>> > QVariant QSqlQueryModel::data(const QModelIndex &item, int role =
>>> Qt::DisplayRole) const
>>> >
>>> > Note that the default for role is Qt::DisplayRole. However, in
>>> QtSql.py I see:
>>> > def data(self, QModelIndex, role=None): # real signature unknown;
>>> restored from __doc__
>>> > """ data(self, QModelIndex, role: int = Qt.DisplayRole) -> Any """
>>> > pass
>>> > You will notice that the comment shows the default should be
>>> Qt.DisplayRole, but the declaration defaults it to None instead.
>>>
>>> What is QtSql.py?
>>>
>>> If you want to know the signature of a method pss it to help().
>>>
>>> > I don't know enough to be sure, but would that be the underlying cause
>>> of the unexpected behaviour?
>>> >
>>> > FWIW, I have tried making my override be:
>>> > def data(self, index: QtCore.QModelIndex, role=None)
>>> > instead, but same bad behaviour.
>>> >
>>> > 1. Is this indeed a bug in PyQt, and the cause of my issue?
>>>
>>> No and no.
>>>
>>> > 2. If so, I presume you (Phil!) will be kind enough to fix. However,
>>> for my part I am stuck with PyQt 5.7 for the foreseeable future. If the
>>> fix is indeed to change code in the latest/next release, is there anything
>>> I can do in existing code (my override) to make it work in 5.7, as a
>>> workaround? (in real code I need the override, as I do other processing)
>>> >
>>> > My coding has come to halt as I cannot proceed without a fix. So I
>>> should be obliged for any early response as to whether this is the cause of
>>> my woes. I do realise PyQt support/fixes are quite voluntary, and so thank
>>> whoever in advance!
>>>
>>> Phil
>>
>>
>> For QtSql.py:
>>
>> Hmm, I had not realised. I use PyCharm as my IDE. From there, while I
>> am coding, I can click on anything PyQt and ask for "Go to
>> definition/declaration". The editor then 9in this case) opens me up into a
>> file named QtSql.py, showing me in this case [extract]:
>>
>> class QSqlQueryModel(__PyQt5_QtCore.QAbstractTableModel):
>>>
>>> ...
>>>
>>> def columnCount(self, parent=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
>>> """ columnCount(self, parent: QModelIndex = QModelIndex()) -> int """
>>> pass
>>>
>>> def data(self, QModelIndex, role=None): # real signature unknown; restored from __doc__
>>> """ data(self, QModelIndex, role: int = Qt.DisplayRole) -> Any """
>>> pass
>>>
>>> def endInsertColumns(self): # real signature unknown; restored from __doc__
>>> """ endInsertColumns(self) """
>>> pass
>>>
>>>
>> etc. I had *assumed* this was a file supplied with PyQt. I guess now
>> it's "generated on the fly" by PyCharm (I see its path is in a PyCharm
>> temporary directory). At other times, it might open, say,
>> /usr/lib/python3/dist-packages/PyQt5/QtCore.pyi, which I think is a file
>> you supply. Oh, at the head of this QtSql.py I see:
>>
>> # encoding: utf-8
>> # module PyQt5.QtSql
>> # from /usr/lib/python3/dist-packages/PyQt5/QtSql.cpython-35m-x86_64-linux-gnu.so
>> # by generator 1.145
>> # no doc
>>
>>
>> You'll probably understand all this better than I!
>>
>>
>>
>> For my problem:
>>
>> I think I now understand better why it's not a PyQt method definition
>> issue.
>>
>> However, from the linked Qt forum discussion, I'm stuck between a rock &
>> a hard place, because the only help I'm getting is that it might be a PyQt
>> issue. I do not have C++ to try that out. So, I wonder if I might ask you
>> if you can make any suggestion as to the cause, even if it is not a PyQt
>> issue, given that you are familiar with Qt at least?
>>
>> To summarise my problem as briefly as possible:
>>
>> 1.
>> I start with:
>>
>> model = QtSql.QSqlQueryModel(self)
>> model.setQuery("SELECT LandlordNo, SMTPAccountId FROM landlords WHERE SMTPAccountId IS NULL")
>>
>> # or plain "SELECT NULL AS SMTPAccountId", to eliminate anything about the column definition being an issue
>>
>> rowCount = model.rowCount()
>> if rowCount > 0:
>> rec = model.record(0)
>> field = rec.field("SMTPAccountId")
>> isn = field.isNull()
>>
>> SMTPAccointId returns NULL from MySQL. *At this point field.isNull()
>> correctly returns True.*
>>
>> 2.
>> I sub-class QSqlQueryModel, and use that, with quite simply, exactly:
>>
>> class DBQueryModel(QtSql.QSqlQueryModel):
>> def __init__(self, parent=None):
>> super().__init__(parent)
>>
>> and use that sub-class in place of QSqlQueryModel: model =
>> DBQueryModel(self)
>> *And it this point point field.isNull() *still* correctly returns
>> True.*
>>
>> 3.
>> Then I add *just exactly this* to my sub-class:
>>
>> def data(self, index: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole) -> typing.Any:
>> return super().data(index, role)
>>
>> (I've also tried role=None) You can see that simply calls the base class
>> method. *But now field.isNull() returns False!!* The application sees 0
>> instead of NULL for the value (SMTPAccountId is declared INT NULL), or ''
>> if I use SELECT NULL AS SMTPAccountId so it counts as string.
>>
>>
>> This leaves me completely stumped. I have no idea where the problem is
>> (there shouldn't be a problem!). I have to sub-class the data() method
>> for other purposes, but then it handles NULL (only) incorrectly.
>>
>> Would you have any idea what is going on here? My thanks in advance.
>>
>>
>> --
>> Kindest,
>> Jonathan
>>
>
>
>
> --
> Kindest,
> Jonathan
>
--
Kindest,
Jonathan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20180503/68cabfe0/attachment-0001.html>
More information about the PyQt
mailing list