PyQt documentation where PyQt function is not same as Qt C++ function

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

PyQt documentation where PyQt function is not same as Qt C++ function

J Barchan
​​
Dear PyQt developers/maintainers/documenters,

[Also cc'ed to "Florian Bruhin", as I believe you have indicated that you are "The Man"!]

I'm getting a little peeved by the problems which arise when you seem to have chosen to make a PyQt function differ somewhat (in return result, so far) from the corresponding Qt C++ function, but no documentation to explain can be found.  (This may apply only to PyQt5, not PyQt4, I don't know.)

I was just trying to write an override in my own class for QRegularExpression.validate().  The Qt documentation (http://doc.qt.io/qt-5/qregularexpressionvalidator.html#validate) shows:

QValidator::State QRegularExpressionValidator::validate(QString &input, int &pos) const

So I expect it to return a QValidator.State.  However, QtGui.pyi shows:
def validate(self, input: str, pos: int) -> typing.Tuple[QValidator.State, str, int]: ...
So this is a tuple, with an extra str & int returned.

Apart from the fact that it's a tuple instead of a plain enum returned, I have no idea what the extra str & int might be, what to do with them, etc.


@return tuple of flag indicating validity (boolean), error string (string) and error offset (integer)

While not the same class, I hazard a guess that this tells me what the str & int are about(?)  But without that I would have been lost if they mattered.

Previously I have come across this issue with QFileDialog.getOpen/SaveFileName(), which returns a tuple of the filename plus some further information.  (Necessitating me to write an "intermediate" function which just returned the filename, as this is what the calling code expected).  This I had to track down via:
If you really need to return different information from the C++ function (why?  to do with overloading not working the same??), could this not be documented somewhere reliable?  I can't find the PyQt5 QRegularExpressionValidator.validate() anywhere.  Much better still would be if the function definition in the .pyi file could explain, but you'll probably say that's auto-generated....

PyQt is great, and thank you for your efforts!  Just can anything be done about this (I have no idea how many other cases might be like this)?




_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

Hans-Peter Jansen-2

On Montag, 27. November 2017 15:53:28 J Barchan wrote:

> ​​

> Dear PyQt developers/maintainers/documenters,

>

> [Also cc'ed to "Florian Bruhin", as I believe you have indicated that you

> are "The Man"!]

>

> I'm getting a little peeved by the problems which arise when you seem to

> have chosen to make a PyQt function differ somewhat (in return result, so

> far) from the corresponding Qt C++ function, but no documentation to

> explain can be found. (This may apply only to PyQt5, not PyQt4, I don't

> know.)

>

> I was just trying to write an override in my own class for

> QRegularExpression.validate(). The Qt documentation (

> http://doc.qt.io/qt-5/qregularexpressionvalidator.html#validate) shows:

>

> QValidator::State <http://doc.qt.io/qt-5/qvalidator.html#State-enum>

> QRegularExpressionValidator::validate(QString

> <http://doc.qt.io/qt-5/qstring.html> &*input*, int &*pos*) const

> So I expect it to return a QValidator.State. However, QtGui.pyi shows:

>

> def validate(self, input: str, pos: int) ->

> typing.Tuple[QValidator.State, str, int]: ...

>

> So this is a tuple, with an extra str & int returned.

>

> Apart from the fact that it's a tuple instead of a plain enum returned, I

> have *no idea* what the extra str & int might be, what to do with them, etc.

 

This is due to the poor C++ way of dealing with multiple return values, while avoiding to define yet another typedef... You supply references to parameter values by the ampersand (&). Expect these values modified in the method call.

 

In Python, that concept translates to a tuple return value rather naturally. PyQt follows the pattern "return value", "1st reference value", "2nd..." for the returned tuple order.

 

Cheers,

Pete

 


_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

Florian Bruhin
In reply to this post by J Barchan
Hi,

On Mon, Nov 27, 2017 at 03:53:28PM +0000, J Barchan wrote:
> [Also cc'ed to "Florian Bruhin", as I believe you have indicated that you
> are "The Man"!]

I'm just a "normal" user of PyQt ;-)

Phil Thompson is "the man", but as mentioned on [1], this mailing list is the
right place to ask :)

[1] https://www.riverbankcomputing.com/support/help

> I'm getting a little peeved by the problems which arise when you seem to
> have chosen to make a PyQt function differ somewhat (in return result, so
> far) from the corresponding Qt C++ function, but no documentation to
> explain can be found.  (This may apply only to PyQt5, not PyQt4, I don't
> know.)
>
> I was just trying to write an override in my own class for
> QRegularExpression.validate().  The Qt documentation (
> http://doc.qt.io/qt-5/qregularexpressionvalidator.html#validate) shows:
>
> QValidator::State <http://doc.qt.io/qt-5/qvalidator.html#State-enum>
> QRegularExpressionValidator::validate(QString
> <http://doc.qt.io/qt-5/qstring.html> &*input*, int &*pos*) const
> So I expect it to return a QValidator.State.  However, QtGui.pyi shows:
>
> def validate(self, input: str, pos: int) ->
> typing.Tuple[QValidator.State, str, int]: ...
>
> So this is a tuple, with an extra str & int returned.
>
> Apart from the fact that it's a tuple instead of a plain enum returned, I
> have *no idea* what the extra str & int might be, what to do with them, etc.
Probably the fixed input and new position.

> If you *really* need to return different information from the C++ function
> (why?  to do with overloading not working the same??)

Because C++ can write a new value back to input/pos (because they're passed as
reference), but Python can't.

Florian

--
https://www.qutebrowser.org  | [hidden email] (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072  | https://the-compiler.org/pubkey.asc
         I love long mails!  | https://email.is-not-s.ms/

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

Hans-Peter Jansen-2
In reply to this post by Hans-Peter Jansen-2
On Montag, 27. November 2017 17:38:43 Hans-Peter Jansen wrote:

> On Montag, 27. November 2017 15:53:28 J Barchan wrote:
> > ​​
> > Dear PyQt developers/maintainers/documenters,
> >
> > [Also cc'ed to "Florian Bruhin", as I believe you have indicated that you
> > are "The Man"!]
> >
> > I'm getting a little peeved by the problems which arise when you seem to
> > have chosen to make a PyQt function differ somewhat (in return result, so
> > far) from the corresponding Qt C++ function, but no documentation to
> > explain can be found.  (This may apply only to PyQt5, not PyQt4, I don't
> > know.)
> >
> > I was just trying to write an override in my own class for
> > QRegularExpression.validate().  The Qt documentation (
> > http://doc.qt.io/qt-5/qregularexpressionvalidator.html#validate) shows:
> >
> > QValidator::State <http://doc.qt.io/qt-5/qvalidator.html#State-enum>
> > QRegularExpressionValidator::validate(QString
> > <http://doc.qt.io/qt-5/qstring.html> &*input*, int &*pos*) const
> > So I expect it to return a QValidator.State.  However, QtGui.pyi shows:
> >
> > def validate(self, input: str, pos: int) ->
> > typing.Tuple[QValidator.State, str, int]: ...
> >
> > So this is a tuple, with an extra str & int returned.
> >
> > Apart from the fact that it's a tuple instead of a plain enum returned, I
> > have *no idea* what the extra str & int might be, what to do with them,
> > etc.
> This is due to the poor C++ way of dealing with multiple return values,
> while avoiding to define yet another typedef... You supply references to
> parameter values by the ampersand (&). Expect these values modified in the
> method call.
>
> In Python, that concept translates to a tuple return value rather naturally.
> PyQt follows the pattern "return value", "1st reference value", "2nd..."
> for the returned tuple order.

QRegularExpressionValidator.validate has the ability to modify the input in
order to make it fit.

If the regexp matches, force the input to uppercase:

class ShortcutValidator(QRegExpValidator):
    def __init__(self, parent = None):
        regExp = QRegExp("[A-Z0-9]{0,1}", Qt.CaseInsensitive)
        super().__init__(regExp, parent)

    def validate(self, input, pos):
        result, input, pos = super().validate(input, pos)
        if result == QValidator.Acceptable:
            input = input.upper()
        return result, input, pos

pos is/can be used for QValidator.Intermediate results..

Cheers,
Pete

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

J Barchan
In reply to this post by Florian Bruhin
Thank you H-P & Florian.

First, my apologies Florian, I got confused, I mistook your name for Phil Thompson's!  I have cc'ed this now to him too :)

Not only am I new to PyQt, but to Python too.  I had only just clicked that the reason for these extra return values is that they are Reference/VAR parameters in the C++ (which I hadn't particularly noticed).  Do you mean, Python does not have these, you have to return these Tuples in the return result as a way of achieving the same effect?  OMG, it's just horrible... :)

OK, at least I see the reason.  It's pretty hard to spot in the Qt documentation, you have to check out the presence of &s (but not with const, of which there are a lot) and read the small print in the docs to see what's likely to be going on...

@Phil
If you are the developer, documenter, may I ask you then:
1. Could this be noted against the declaration in the .pyi file?
2. If not, should a PyQt overall document explain about this C++ -> Python conversion behaviour?
3. OOI, why does PyQt5 QFileDialog.getOpen/SaveFileName() return that second parameter?  Lemme guess: it's the QString *selectedFilter parameter, isn't it?  The user can change that, and Qt returns it as well as the filename, I guess, though I can't even see that in the Qt documentation...  Grrrrr!!


On 27 November 2017 at 16:40, Florian Bruhin <[hidden email]> wrote:
Hi,

On Mon, Nov 27, 2017 at 03:53:28PM +0000, J Barchan wrote:
> [Also cc'ed to "Florian Bruhin", as I believe you have indicated that you
> are "The Man"!]

I'm just a "normal" user of PyQt ;-)

Phil Thompson is "the man", but as mentioned on [1], this mailing list is the
right place to ask :)

[1] https://www.riverbankcomputing.com/support/help

> I'm getting a little peeved by the problems which arise when you seem to
> have chosen to make a PyQt function differ somewhat (in return result, so
> far) from the corresponding Qt C++ function, but no documentation to
> explain can be found.  (This may apply only to PyQt5, not PyQt4, I don't
> know.)
>
> I was just trying to write an override in my own class for
> QRegularExpression.validate().  The Qt documentation (
> http://doc.qt.io/qt-5/qregularexpressionvalidator.html#validate) shows:
>
> QValidator::State <http://doc.qt.io/qt-5/qvalidator.html#State-enum>
> QRegularExpressionValidator::validate(QString
> <http://doc.qt.io/qt-5/qstring.html> &*input*, int &*pos*) const
> So I expect it to return a QValidator.State.  However, QtGui.pyi shows:
>
> def validate(self, input: str, pos: int) ->
> typing.Tuple[QValidator.State, str, int]: ...
>
> So this is a tuple, with an extra str & int returned.
>
> Apart from the fact that it's a tuple instead of a plain enum returned, I
> have *no idea* what the extra str & int might be, what to do with them, etc.

Probably the fixed input and new position.

> If you *really* need to return different information from the C++ function
> (why?  to do with overloading not working the same??)

Because C++ can write a new value back to input/pos (because they're passed as
reference), but Python can't.

Florian

--
https://www.qutebrowser.org  | [hidden email] (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072  | https://the-compiler.org/pubkey.asc
         I love long mails!  | https://email.is-not-s.ms/



--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

David Boddie
On Mon Nov 27 16:59:54 GMT 2017, J Barchan wrote:

> If you are the developer, documenter, may I ask you then:
> 1. Could this be noted against the declaration in the .pyi file?
> 2. If not, should a PyQt overall document explain about this C++ -> Python
> conversion behaviour?

There used to be something about this, I think. The page I mention below
shows places where you might want to be careful.

> 3. OOI, why does PyQt5 QFileDialog.getOpen/SaveFileName() return that
> second parameter?  Lemme guess: it's the QString *selectedFilter parameter,
> isn't it?  The user can change that, and Qt returns it as well as the
> filename, I guess, though I can't even see that in the Qt documentation...
> Grrrrr!!

It's mentioned in the PyQt4 documentation, which is still relevant to PyQt5
in places:

http://pyqt.sourceforge.net/Docs/PyQt4/python_v3.html#qfiledialog

You're looking for the "const QString &filter = QString()" part of the
C++ signature hints that the filter may change but the documentation doesn't
mention that:

https://doc.qt.io/qt-5/qfiledialog.html#getOpenFileName

David
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

Hans-Peter Jansen-2
In reply to this post by J Barchan
On Montag, 27. November 2017 16:59:54 J Barchan wrote:
 
> Not only am I new to PyQt, but to Python too.  I had only just clicked that
> the reason for these extra return values is that they are Reference/VAR
> parameters in the C++ (which I hadn't particularly noticed).  Do you mean,
> Python does not have these, you have to return these Tuples in the return
> result as a way of achieving the same effect?  OMG, it's just horrible... :)

That's a matter of taste, I guess.

Technically, these references are "address off" operators. Addresses of
variables just make no sense in dynamic languages.

I find it much more natural to *supply* and *return* multiple values then
playing games with references. But that's just my opinion.

Cheers,
Pete

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

Hans-Peter Jansen-2
On Montag, 27. November 2017 18:48:51 Hans-Peter Jansen wrote:
> Technically, these references are "address off" operators.

Technically, these references are "address of" operators.

Grmpf,
Pete
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

J Barchan
In reply to this post by Hans-Peter Jansen-2
Thank you all for your responses in this thread.

I now understand why PyQt has to use these "tuple" returns in places.  I may not be a fan of the way Python has to do this, but at least I now know what to look for in function declarations (non-const & references) which will make me need to check the signature, instead of it appearing simply "random" to me!


_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

David Boddie
On Tue Nov 28 09:01:30 GMT 2017, J Barchan wrote:

> I now understand why PyQt has to use these "tuple" returns in places.  I
> may not be a fan of the way Python has to do this, but at least I now know
> what to look for in function declarations (non-const & references) which
> will make me need to check the signature, instead of it appearing simply
> "random" to me!

Sorry, I misread what you wrote. The "const QString &filter" parameter isn't
something that will be modified, but I suppose that the argument to
the selectedFilter parameter could be modified - you do get the selected
filter back as the second item in the tuple in Python.

I should clarify that the "const QString &" pattern in signatures appears
all over the place in Qt and is used for reasons I can't remember, but
probably something to do with getting old C++ compilers to generate
efficient code.

I suppose that the hint that something could be modified is the use of a
pointer for something you would expect to be passed by value or const
reference. So, QString* instead of "const QString &".

For what it's worth, in the old days of KDE 3 I encountered a method of a
class that accepted a reference to a QImage that you were supposed to
modify. If you assigned a new QImage to the parameter holding the original
one, you didn't get the result you expected. This might have worked as
expected in C++, but not in Python.

https://api.kde.org/3.5-api/kdelibs-apidocs/kio/html/classThumbCreator.html

I don't know why the authors didn't just define a method that returned a
QImage.

Sorry for the confusion.

David
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Fwd: PyQt documentation where PyQt function is not same as Qt C++ function

J Barchan

On 28 November 2017 at 15:53, David Boddie <[hidden email]> wrote:
On Tue Nov 28 09:01:30 GMT 2017, J Barchan wrote:

> I now understand why PyQt has to use these "tuple" returns in places.  I
> may not be a fan of the way Python has to do this, but at least I now know
> what to look for in function declarations (non-const & references) which
> will make me need to check the signature, instead of it appearing simply
> "random" to me!

Sorry, I misread what you wrote. The "const QString &filter" parameter isn't
something that will be modified, but I suppose that the argument to
the selectedFilter parameter could be modified - you do get the selected
filter back as the second item in the tuple in Python.

I should clarify that the "const QString &" pattern in signatures appears
all over the place in Qt and is used for reasons I can't remember, but
probably something to do with getting old C++ compilers to generate
efficient code.

I suppose that the hint that something could be modified is the use of a
pointer for something you would expect to be passed by value or const
reference. So, QString* instead of "const QString &".

For what it's worth, in the old days of KDE 3 I encountered a method of a
class that accepted a reference to a QImage that you were supposed to
modify. If you assigned a new QImage to the parameter holding the original
one, you didn't get the result you expected. This might have worked as
expected in C++, but not in Python.

https://api.kde.org/3.5-api/kdelibs-apidocs/kio/html/classThumbCreator.html

I don't know why the authors didn't just define a method that returned a
QImage.

Sorry for the confusion.

David
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

​David, yes, I had already figured we were talking about the non-const *selectedFilter​ parameter, as I wrote, rather than the const &filter one, as the "reference" parameter PyQt is dealing with in the tuple return.  I hadn't even noticed the Qt docs for this saying it could be returned, hidden away on one line, as it didn't occur to me anyone would be interested in getting that back from the call!  Not PyQt's fault.

Purely OOI, do we know whether the automated "Qt C++ to PyQt Python converter" recognises this signature pattern (i.e. non-const * or &) and automatically generates a tuple-return for it?  Somehow I doubt it (too difficult, too reliant on C++ signature using const everywhere correctly), so I'm thinking these tuple-returns are handled by the author manually?





--
Kindest,
Jonathan

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: PyQt documentation where PyQt function is not same as Qt C++ function

Florian Bruhin
On Tue, Nov 28, 2017 at 04:53:18PM +0000, J Barchan wrote:
> Purely OOI, do we know whether the automated "Qt C++ to PyQt Python
> converter" recognises this signature pattern (i.e. non-const * or &) and
> automatically generates a tuple-return for it?  Somehow I doubt it (too
> difficult, too reliant on C++ signature using const everywhere correctly),
> so I'm thinking these tuple-returns are handled by the author manually?

PyQt has binding definition files (.sip files), which are basically C++ header
files (.h) with additional annotations. For those cases, there's an /Out/ or
/In,Out/ annotation in it.

Those are generated in a half-automated way as far as I'm aware, see
https://dot.kde.org/2006/08/09/phil-thompson-talks-about-pyqt

(Unless something changed about that in the meantime, which is something only
Phil can answer :D)

Florian

--
https://www.qutebrowser.org  | [hidden email] (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072  | https://the-compiler.org/pubkey.asc
         I love long mails!  | https://email.is-not-s.ms/

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

Barry Scott
In reply to this post by David Boddie

> On 28 Nov 2017, at 15:53, David Boddie <[hidden email]>
> I should clarify that the "const QString &" pattern in signatures appears
> all over the place in Qt and is used for reasons I can't remember, but
> probably something to do with getting old C++ compilers to generate
> efficient code.

The reason is that foo &x means that x is not optional.
Where as foo *x can optional by passing as null.

A const foo &x must be present and cannot be modified.
A foo &x can be modified and you should be assume it will be modified.

Barry

_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: PyQt documentation where PyQt function is not same as Qt C++ function

Kyle Altendorf
In reply to this post by J Barchan
On 2017-11-28 04:01, J Barchan wrote:
> I now understand why PyQt has to use these "tuple" returns in places.  
> I may not be a fan of the way Python has to do this, but at least I now
> know what to look for in function declarations (non-const & references)
> which will make me need to check the signature, instead of it appearing
> simply "random" to me!

Perhaps your distaste for Python's approach is mostly based on being
used to something else like C++?

Python passes everything by reference.  Further, every name is a
reference.  The difference is that some objects are immutable (strings,
tuples, ints, and more) and so even though the receiving function
references the original object it would be unable to change it in those
cases.

Perhaps if you explain why you prefer passing in variables to receive
the results of multiple return values (as C++ requires) we could help
you understand better.

   int cplusplusFunc(int anInput, int &secondOutput, int &thirdOutput);

   int first, second, third;
   first = cplusplusFUnc(second, third)

vs.

   def pythonFunc(anInput):
       return 1, anInput + 2, 3

   first, second, third = pythonFunc(42)

Looking at that, do you still feel that the C++ approach is more clear?  
Seems to me that Python nicely distinguishes inputs from output (and
yes, technically there is a single return value, a tuple, but it is so
easily packed and unpacked that that fact is not an issue).

This may also be relevant to understanding Python:
   https://nedbatchelder.com/text/names1.html

Cheers,
-kyle
_______________________________________________
PyQt mailing list    [hidden email]
https://www.riverbankcomputing.com/mailman/listinfo/pyqt