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

J Barchan jnbarchan at gmail.com
Wed May 9 08:04:27 BST 2018


​

On 8 May 2018 at 22:02, Phil Thompson <phil at riverbankcomputing.com> wrote:

>
> > On 8 May 2018, at 8:22 pm, J Barchan <jnbarchan at gmail.com> wrote:
> >
> > ​
> >
> > On 8 May 2018 at 18:14, Phil Thompson <phil at riverbankcomputing.com>
> wrote:
> > On 8 May 2018, at 9:04 am, J Barchan <jnbarchan at gmail.com> wrote:
> > >
> > > ​Now I'm finding that, with the fix discussed, while my overridden
> function definition correctly handles database NULLs, it "goes wrong" (as
> in, different behaviour from before) in certain other cases, returning a
> QVariant where it did not do so before (it returned the converted, native
> Python type).​
> > >
> > > 1. So long as I do not override QSqlQueryModel.data() at all, there is
> absolutely no problem --- both database NULL and auto-conversion of
> non-NULL to Python native type work fine, and are distinct.  This is the
> situation I need.
> > >
> > > 2. I need to override QSqlQueryModel.data() for my own purposes.  If I
> write just:
> > > def data(self, index: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole)
> -> typing.Any:
> > >     value = super().data(index, role)
> > >     return value
> > > Some data conversion happens, such that I no longer get NULL back
> where the value is NULL --- instead it is converted to '' if string or 0 if
> int.  This was my original problem and is not acceptable.
> > >
> > > 3. Following our discussion, I change that to:
> > > 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
> > > Now I correctly get whatever for database NULL, which works.  However,
> some other path of code, on some quite different non-NULL value, gets back
> a QVariant where it used to get a string.  I don't know what that path of
> code is, but I don't think I should care.
> > >
> > > So, what I need is: code which allows me to override
> ​​QSqlQueryModel.data() but returns the original data() value unchanged,
> just like it used when I did not put any override in (case #1).  It must do
> whatever to correctly deal with NULL & non-NULL, just like the
> non-overridden QSqlQueryModel.data() does.
> > >
> > > (In PyQt 5.7) What exact code can I put into the override to achieve
> just that, please?  Surely that can be done, no?
> >
> > You can't have it both ways. Either you let PyQt automatically convert
> to/from QVariant (and you lose the detection of nulls) or you do it
> yourself (converting to Python using the value() method).
> >
> > By the way, I've just noticed a bug in the docs which says (incorrectly)
> that null QVariants are converted to None and vice versa.
> >
> > Phil
> >
> > ​Hi Phil,
> >
> > Thanks for your reply.
> >
> > I think one of us must be getting something wrong here.  I wonder if
> you're still expecting me to understand something which is obvious to you
> but not to me.
> >
> > You can't have it both ways. Either you let PyQt automatically convert
> to/from QVariant (and you lose the detection of nulls) or you do it
> yourself (converting to Python using the value() method).
> >
> > I'm not asking to have anything both ways.​  I'm just asking how to
> write code so that the overridden method behaves absolutely identically to
> the base method it's overriding.  Surely that must be possible?
> >
> > I remind you: when I have no override for ​QSqlQueryModel.data()
> everything behaves perfectly.  I am saying: there is no problem, NULLs are
> handled as such and non-NULLs are correctly converted to their Python
> equivalent.  I do not know how NULLs work (what they are returned as), but
> everything just works.
> >
> > As soon as I write an override which just returns the base method, it
> goes wrong on NULL.  If I put it the sip.autoconversion(False), it works on
> NULL but now returns a QVariant where it used to return a Python native
> type, I think.
>
> ​​
> Correct - because data() returns a QVariant. With the auto-conversion the
> Python native type is automatically converted to a QVariant.
>
> > All I want to know is: how can I write an override of
> ​QSqlQueryModel.data() in Python/PyQt like:
> >
> > def data(self, index: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole) ->
> typing.Any:
> >      value = super().data(index, role)
> >      return value
> >
> > such that it returns just exactly the same as QSqlQueryModel.data()
> would have done, please, please, please?
>
> ​​
> You already have it - with the calls to autoenableconversion().
>
> Phil
>
>
​​Correct - because data() returns a QVariant. With the auto-conversion the
> Python native type is automatically converted to a QVariant.​


​Fine.  So are you saying I need to replicate the Python auto-conversion on
the result I get back because I had to suppress the autoconversion?, and
then return that?​  Is there a Pyton function, or what sort of code do I
need to write, to achieve the same result as whatever the autoconversion
would have done?  Because I have no idea...

​
> ​​
> You already have it - with the calls to autoenableconversion().


​Phil, no I do not.  I very carefully typed in that I had changed over to
precisely:

> > 3. Following our discussion, I change that to:

> > 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

> > Now I correctly get whatever for database NULL, which works.  However,
some other path of code, on some quite different non-NULL value, gets back
a QVariant where it used to get a string.  I don't know what that path of
code is, but I don't think I should care.

​

That's exactly what you are saying ​"​You already have it - with the calls
to autoenableconversion()." about, correct?  And I am saying: no, that code
returns whatever correct value in the NULL case which I was originally
complaining about, but now returns in other cases a QVariant back to my
code where it used to return, say, a string.  Which then makes the calling
code go wrong.  So with the calls to autoconversion it does *not* return
the same result as if I had never written the override, which is precisely
why I am stumped and asking the question....



-- 
Kindest,
Jonathan
​​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20180509/49135689/attachment-0001.html>


More information about the PyQt mailing list