Problems with new PyQt4 API

Hi list,

I'm using matplotlib as a library, in a program using the
new APIs of PyQt4, which will be the normal APIs for
Python 3. Unfortunately, the matplotlib Qt4 backend is
not compatible with this new API.

The problems are easy to fix: first QFileDialog.getSaveFileName
has changed, and is to be replaced with
QFileDialog.getSaveFileNameAndFilter, for example with the following
patch:

···

-----------------------------------------------------------------------------------------------
--- backend_qt4.py 2011-03-02 16:17:19.526831397 +0100
+++ backend_qt4_orig.py 2011-03-02 16:16:38.257797767 +0100
@@ -395,9 +395,8 @@
             filters.append(filter)
         filters = ';;'.join(filters)

- fname, _ = QtGui.QFileDialog.getSaveFileNameAndFilter(
- self, "Choose a filename to save to", start, filters,
- selectedFilter)
+ fname = QtGui.QFileDialog.getSaveFileName(
+ self, "Choose a filename to save to", start, filters,
selectedFilter)
         if fname:
             try:
                 self.canvas.print_figure( unicode(fname) )
-----------------------------------------------------------------------------------------------

secondly, QString is used in the new formlayout, wich can be avoided
using yet another patch, that I actually once filed as Path #3081405
in the matplotlib patch tracker.

-----------------------------------------------------------------------------------------------
--- formlayout.py 2010-10-05 11:45:01.000000000 +0200
+++ formlayout.py-orig 2010-10-01 12:28:34.000000000 +0200
@@ -56,7 +56,8 @@
                          QPixmap, QTabWidget, QApplication, QStackedWidget,
                          QDateEdit, QDateTimeEdit, QFont, QFontComboBox,
                          QFontDatabase, QGridLayout)
-from PyQt4.QtCore import Qt, SIGNAL, SLOT, QSize, pyqtSignature, pyqtProperty
+from PyQt4.QtCore import (Qt, SIGNAL, SLOT, QSize, QString,
+ pyqtSignature, pyqtProperty)
from datetime import date

@@ -101,7 +102,10 @@
     Avoid warning from Qt when an invalid QColor is instantiated
     """
     color = QColor()
- text = unicode(text)
+ if isinstance(text, QString):
+ text = str(text)
+ if not isinstance(text, (unicode, str)):
+ return color
     if text.startswith('#') and len(text)==7:
         correct = '#0123456789abcdef'
         for char in text:
-----------------------------------------------------------------------------------------------------------

Greetings

Martin

--
Max-Born-Institut
Max-Born-Straße 2a
12489 Berlin
+49 30 6392 1234

Martin,

Thank you for letting us know about continuing issues with PyQT4. First, I think your patches are “backwards”, per se. Can you double-check that they are what you mean? Also, which version of matplotlib did you patch against? I know that we recently made a fix involving QString:

https://github.com/matplotlib/matplotlib/commit/fa82c5adcc1493ec705728e4beb806cb4c84579f

I see we probably still need to fix the backend, but is everything else in order?

Ben Root

···

On Wed, Mar 2, 2011 at 9:26 AM, Martin Teichmann <lkb.teichmann@…149…> wrote:

Hi list,

I’m using matplotlib as a library, in a program using the

new APIs of PyQt4, which will be the normal APIs for

Python 3. Unfortunately, the matplotlib Qt4 backend is

not compatible with this new API.

The problems are easy to fix: first QFileDialog.getSaveFileName

has changed, and is to be replaced with

QFileDialog.getSaveFileNameAndFilter, for example with the following

patch:


— backend_qt4.py 2011-03-02 16:17:19.526831397 +0100

+++ backend_qt4_orig.py 2011-03-02 16:16:38.257797767 +0100

@@ -395,9 +395,8 @@

         filters.append(filter)

     filters = ';;'.join(filters)
  •    fname, _ = QtGui.QFileDialog.getSaveFileNameAndFilter(
    
  •        self, "Choose a filename to save to", start, filters,
    
  •        selectedFilter)
    
  •    fname = QtGui.QFileDialog.getSaveFileName(
    
  •        self, "Choose a filename to save to", start, filters,
    

selectedFilter)

     if fname:

         try:

             self.canvas.print_figure( unicode(fname) )

secondly, QString is used in the new formlayout, wich can be avoided

using yet another patch, that I actually once filed as Path #3081405

in the matplotlib patch tracker.


— formlayout.py 2010-10-05 11:45:01.000000000 +0200

+++ formlayout.py-orig 2010-10-01 12:28:34.000000000 +0200

@@ -56,7 +56,8 @@

                      QPixmap, QTabWidget, QApplication, QStackedWidget,

                      QDateEdit, QDateTimeEdit, QFont, QFontComboBox,

                      QFontDatabase, QGridLayout)

-from PyQt4.QtCore import Qt, SIGNAL, SLOT, QSize, pyqtSignature, pyqtProperty

+from PyQt4.QtCore import (Qt, SIGNAL, SLOT, QSize, QString,

  •                      pyqtSignature, pyqtProperty)
    

from datetime import date

@@ -101,7 +102,10 @@

 Avoid warning from Qt when an invalid QColor is instantiated

 """

 color = QColor()
  • text = unicode(text)
  • if isinstance(text, QString):

  •    text = str(text)
    
  • if not isinstance(text, (unicode, str)):

  •    return color
    

    if text.startswith(‘#’) and len(text)==7:

       correct = '#0123456789abcdef'
    
       for char in text:
    

Greetings

Martin

This really doesn't belong on the PyQt4 mailing list. Please post to
the matplotlib user or developer list.

···

On Wed, Mar 2, 2011 at 10:26 AM, Martin Teichmann <lkb.teichmann@...149...> wrote:

Hi list,

I'm using matplotlib as a library, in a program using the
new APIs of PyQt4, which will be the normal APIs for
Python 3. Unfortunately, the matplotlib Qt4 backend is
not compatible with this new API.

My apologies. I thought I saw this posted to the pyqt4 mailing list.
Trying to do too many things at once.

···

On Wed, Mar 2, 2011 at 4:26 PM, Darren Dale <dsdale24@...149...> wrote:

On Wed, Mar 2, 2011 at 10:26 AM, Martin Teichmann > <lkb.teichmann@...149...> wrote:

Hi list,

I'm using matplotlib as a library, in a program using the
new APIs of PyQt4, which will be the normal APIs for
Python 3. Unfortunately, the matplotlib Qt4 backend is
not compatible with this new API.

This really doesn't belong on the PyQt4 mailing list. Please post to
the matplotlib user or developer list.

Hi Benjamin, Hi List,

sorry for the backwards patch, here the forward one:

···

------------------------------------------------------------------------
--- backend_qt4_orig.py 2011-03-02 16:16:38.257797767 +0100
+++ backend_qt4.py 2011-03-02 16:17:19.526831397 +0100
@@ -395,8 +395,9 @@
             filters.append(filter)
         filters = ';;'.join(filters)

- fname = QtGui.QFileDialog.getSaveFileName(
- self, "Choose a filename to save to", start, filters,
selectedFilter)
+ fname, _ = QtGui.QFileDialog.getSaveFileNameAndFilter(
+ self, "Choose a filename to save to", start, filters,
+ selectedFilter)
         if fname:
             try:
                 self.canvas.print_figure( unicode(fname) )
----------------------------------------------------------------------------

It is done against a rather old version of matplotlib (the 0.99.3, the
newest in kubuntu...) but the code hasn't changed since then,
acording to github, so only the line numbers are wrong.

The second patch I sent is now obsolete, as you hinted to the
patch on github. I had followed the link on the matplotlib
web site (http://matplotlib.sourceforge.net/) which links still to
some subversion repository once you click onto "source code"
Could please someone update that link to github? Or is there
a new matplotlib website as well (google didn't find one).

Greetings

Martin

--
Max-Born-Institut
Max-Born-Straße 2a
12489 Berlin
+49 30 6392 1234

Martin,

Thank you for double-checking your patches. I will see about getting it added into mpl today.

As for the sourceforge/github confusion, we are currently in a transition phase. Our repository is now hosted on github, but the official website and trackers are still sourceforge. Sorry for any confusion there. The (un)official new website will be http://matplotlib.github.com.

Thank you for helping to make matplotlib better!

Ben Root

···

On Thu, Mar 3, 2011 at 3:15 AM, Martin Teichmann <lkb.teichmann@…149…> wrote:

Hi Benjamin, Hi List,

sorry for the backwards patch, here the forward one:


— backend_qt4_orig.py 2011-03-02 16:16:38.257797767 +0100

+++ backend_qt4.py 2011-03-02 16:17:19.526831397 +0100

@@ -395,8 +395,9 @@
filters.append(filter)

     filters = ';;'.join(filters)
  •    fname = QtGui.QFileDialog.getSaveFileName(
    
  •        self, "Choose a filename to save to", start, filters,
    

selectedFilter)

  •    fname, _ = QtGui.QFileDialog.getSaveFileNameAndFilter(
    
  •        self, "Choose a filename to save to", start, filters,
    
  •        selectedFilter)
    
       if fname:
    
           try:
    
               self.canvas.print_figure( unicode(fname) )
    

It is done against a rather old version of matplotlib (the 0.99.3, the

newest in kubuntu…) but the code hasn’t changed since then,

acording to github, so only the line numbers are wrong.

The second patch I sent is now obsolete, as you hinted to the

patch on github. I had followed the link on the matplotlib

web site (http://matplotlib.sourceforge.net/) which links still to

some subversion repository once you click onto “source code”

Could please someone update that link to github? Or is there

a new matplotlib website as well (google didn’t find one).

Greetings

Martin

Max-Born-Institut

Max-Born-Straße 2a

12489 Berlin

+49 30 6392 1234

With particular emphasis on UNofficial. I put that site up to make the
git/github developer docs available right away, and to investigate
whether we might want to host the homepage at github. There has been
no discussion of switching, let alone a decision to do so.

···

On Thu, Mar 3, 2011 at 9:36 AM, Benjamin Root <ben.root@...553...> wrote:

As for the sourceforge/github confusion, we are currently in a transition
phase. Our repository is now hosted on github, but the official website and
trackers are still sourceforge. Sorry for any confusion there. The
(un)official new website will be http://matplotlib.github.com.

Martin,

Just for completeness, I wanted to include a link to some sort of reference indicating a need to change the function. I can not find any documentation that says that we need to change from getSaveFileName() to getSaveFileNameAndFilter(). Can you please provide a source explaining the need for this change?

Thanks,
Ben Root

···

On Thu, Mar 3, 2011 at 3:15 AM, Martin Teichmann <lkb.teichmann@…149…> wrote:

Hi Benjamin, Hi List,

sorry for the backwards patch, here the forward one:


— backend_qt4_orig.py 2011-03-02 16:16:38.257797767 +0100

+++ backend_qt4.py 2011-03-02 16:17:19.526831397 +0100

@@ -395,8 +395,9 @@
filters.append(filter)

     filters = ';;'.join(filters)
  •    fname = QtGui.QFileDialog.getSaveFileName(
    
  •        self, "Choose a filename to save to", start, filters,
    

selectedFilter)

  •    fname, _ = QtGui.QFileDialog.getSaveFileNameAndFilter(
    
  •        self, "Choose a filename to save to", start, filters,
    
  •        selectedFilter)
    
       if fname:
    
           try:
    
               self.canvas.print_figure( unicode(fname) )
    

It is done against a rather old version of matplotlib (the 0.99.3, the

newest in kubuntu…) but the code hasn’t changed since then,

acording to github, so only the line numbers are wrong.

The second patch I sent is now obsolete, as you hinted to the

patch on github. I had followed the link on the matplotlib

web site (http://matplotlib.sourceforge.net/) which links still to

some subversion repository once you click onto “source code”

Could please someone update that link to github? Or is there

a new matplotlib website as well (google didn’t find one).

Greetings

Martin

Max-Born-Institut

Max-Born-Straße 2a

12489 Berlin

+49 30 6392 1234

Try here: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/python_v3.html#qfiledialog

···

On Thu, Mar 3, 2011 at 10:22 AM, Benjamin Root <ben.root@...553...> wrote:

Just for completeness, I wanted to include a link to some sort of reference
indicating a need to change the function. I can not find any documentation
that says that we need to change from getSaveFileName() to
getSaveFileNameAndFilter(). Can you please provide a source explaining the
need for this change?

Exactly. That's all I found too. Nothing indicates that we need to
change anything. We are throwing away the second part of the tuple
which has the returned filter. The only reason I see for the new
function is so the coder can get back the filter string, which we
don't seem to use.

Am I missing something?

Ben Root

···

On Thursday, March 3, 2011, Darren Dale <dsdale24@...149...> wrote:

On Thu, Mar 3, 2011 at 10:22 AM, Benjamin Root <ben.root@...553...> wrote:

Just for completeness, I wanted to include a link to some sort of reference
indicating a need to change the function. I can not find any documentation
that says that we need to change from getSaveFileName() to
getSaveFileNameAndFilter(). Can you please provide a source explaining the
need for this change?

Try here: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/python_v3.html#qfiledialog

Hi Ben, Hi list,

Exactly. That's all I found too. Nothing indicates that we need to
change anything. We are throwing away the second part of the tuple
which has the returned filter. The only reason I see for the new
function is so the coder can get back the filter string, which we
don't seem to use.

It took me a while to see the problem, too. The point is: there is one parameter
missing in the new API of getSaveFileName, called selectedFilter,
which we use, and
given that it is missing, python takes it to be the next parameter, which
must be an int, and you get a TypeError. I discussed this with
Phil Thompson (the author of PyQt4) over at the PyQt4 mailing list
(see [PyQt] Bug in QFileDialog.getSaveFileName)
and he told me to use getSaveFileNameAndFilter.

The other option would be to change PyQt4, dunno which is best.

Greetings

Martin

···

--
Max-Born-Institut
Max-Born-Straße 2a
12489 Berlin
+49 30 6392 1234

Martin, thanks for the explanation. That made a lot more sense. I will go ahead with the patch.

Ben Root

···

On Fri, Mar 4, 2011 at 4:23 AM, Martin Teichmann <lkb.teichmann@…149…> wrote:

Hi Ben, Hi list,

Exactly. That’s all I found too. Nothing indicates that we need to

change anything. We are throwing away the second part of the tuple

which has the returned filter. The only reason I see for the new

function is so the coder can get back the filter string, which we

don’t seem to use.

It took me a while to see the problem, too. The point is: there is one parameter

missing in the new API of getSaveFileName, called selectedFilter,

which we use, and

given that it is missing, python takes it to be the next parameter, which

must be an int, and you get a TypeError. I discussed this with

Phil Thompson (the author of PyQt4) over at the PyQt4 mailing list

(see http://www.mail-archive.com/pyqt%40riverbankcomputing.com/msg23733.html)

and he told me to use getSaveFileNameAndFilter.

The other option would be to change PyQt4, dunno which is best.

Greetings

Martin

getSaveFileNameAndFilter was only added in pyqt-4.6.

···

On Mon, Mar 7, 2011 at 11:04 AM, Benjamin Root <ben.root@...553...> wrote:

On Fri, Mar 4, 2011 at 4:23 AM, Martin Teichmann <lkb.teichmann@...149...> > wrote:

Hi Ben, Hi list,

> Exactly. That's all I found too. Nothing indicates that we need to
> change anything. We are throwing away the second part of the tuple
> which has the returned filter. The only reason I see for the new
> function is so the coder can get back the filter string, which we
> don't seem to use.

It took me a while to see the problem, too. The point is: there is one
parameter
missing in the new API of getSaveFileName, called selectedFilter,
which we use, and
given that it is missing, python takes it to be the next parameter, which
must be an int, and you get a TypeError. I discussed this with
Phil Thompson (the author of PyQt4) over at the PyQt4 mailing list
(see
[PyQt] Bug in QFileDialog.getSaveFileName)
and he told me to use getSaveFileNameAndFilter.

The other option would be to change PyQt4, dunno which is best.

Greetings

Martin

Martin, thanks for the explanation. That made a lot more sense. I will go
ahead with the patch.

oy! Why the heck did qt4 change their API like this? What should we do? I also assume that some sort of fix should be applied to the v1.0.x?

Ben Root

···

On Mon, Mar 7, 2011 at 10:20 AM, Darren Dale <dsdale24@…55…149…> wrote:

On Mon, Mar 7, 2011 at 11:04 AM, Benjamin Root <ben.root@…553…> wrote:

On Fri, Mar 4, 2011 at 4:23 AM, Martin Teichmann <lkb.teichmann@…149…> > > > wrote:

Hi Ben, Hi list,

Exactly. That’s all I found too. Nothing indicates that we need to

change anything. We are throwing away the second part of the tuple

which has the returned filter. The only reason I see for the new

function is so the coder can get back the filter string, which we

don’t seem to use.

It took me a while to see the problem, too. The point is: there is one

parameter

missing in the new API of getSaveFileName, called selectedFilter,

which we use, and

given that it is missing, python takes it to be the next parameter, which

must be an int, and you get a TypeError. I discussed this with

Phil Thompson (the author of PyQt4) over at the PyQt4 mailing list

(see

http://www.mail-archive.com/pyqt%40riverbankcomputing.com/msg23733.html)

and he told me to use getSaveFileNameAndFilter.

The other option would be to change PyQt4, dunno which is best.

Greetings

Martin

Martin, thanks for the explanation. That made a lot more sense. I will go

ahead with the patch.

getSaveFileNameAndFilter was only added in pyqt-4.6.

>
>
>>
>> Hi Ben, Hi list,
>>
>> > Exactly. That's all I found too. Nothing indicates that we need to
>> > change anything. We are throwing away the second part of the tuple
>> > which has the returned filter. The only reason I see for the new
>> > function is so the coder can get back the filter string, which we
>> > don't seem to use.
>>
>> It took me a while to see the problem, too. The point is: there is one
>> parameter
>> missing in the new API of getSaveFileName, called selectedFilter,
>> which we use, and
>> given that it is missing, python takes it to be the next parameter,
>> which
>> must be an int, and you get a TypeError. I discussed this with
>> Phil Thompson (the author of PyQt4) over at the PyQt4 mailing list
>> (see
>>
>> [PyQt] Bug in QFileDialog.getSaveFileName)
>> and he told me to use getSaveFileNameAndFilter.
>>
>> The other option would be to change PyQt4, dunno which is best.
>>
>> Greetings
>>
>> Martin
>>
>
> Martin, thanks for the explanation. That made a lot more sense. I will
> go
> ahead with the patch.

getSaveFileNameAndFilter was only added in pyqt-4.6.

oy! Why the heck did qt4 change their API like this?

To make it more pythonic for python-3. You can set the api to v2 with
python-2, but it is not the default.

What should we do?

I think the change being discussed is only necessary when the QString
api is set to v2. So, we should be able to do something along the
lines of:

import sip

try:
   if sip.getapi("QString") > 1:
       # support the new api
   else:
       # support the old api
except (AttributeError, KeyError): # call to getapi may fail with
older versions of sip
   # support the old api

I also assume that some sort of fix should be applied to the v1.0.x?

I think it should be, if the fix does not break backward compatibility
with <PyQt4-4.6.

Darren

···

On Mon, Mar 7, 2011 at 11:24 AM, Benjamin Root <ben.root@...553...> wrote:

On Mon, Mar 7, 2011 at 10:20 AM, Darren Dale <dsdale24@...149...> wrote:

On Mon, Mar 7, 2011 at 11:04 AM, Benjamin Root <ben.root@...553...> wrote:
> On Fri, Mar 4, 2011 at 4:23 AM, Martin Teichmann >> > <lkb.teichmann@...149...> >> > wrote:

My attempt at this can be found in pull request 33:

https://github.com/matplotlib/matplotlib/pull/33

Ben Root

···

On Mon, Mar 7, 2011 at 10:39 AM, Darren Dale <dsdale24@…55…149…> wrote:

On Mon, Mar 7, 2011 at 11:24 AM, Benjamin Root <ben.root@…553…> wrote:

On Mon, Mar 7, 2011 at 10:20 AM, Darren Dale <dsdale24@…149…> wrote:

On Mon, Mar 7, 2011 at 11:04 AM, Benjamin Root <ben.root@…553…> wrote:

On Fri, Mar 4, 2011 at 4:23 AM, Martin Teichmann > > >> > <lkb.teichmann@…149…> > > >> > wrote:

Hi Ben, Hi list,

Exactly. That’s all I found too. Nothing indicates that we need to

change anything. We are throwing away the second part of the tuple

which has the returned filter. The only reason I see for the new

function is so the coder can get back the filter string, which we

don’t seem to use.

It took me a while to see the problem, too. The point is: there is one

parameter

missing in the new API of getSaveFileName, called selectedFilter,

which we use, and

given that it is missing, python takes it to be the next parameter,

which

must be an int, and you get a TypeError. I discussed this with

Phil Thompson (the author of PyQt4) over at the PyQt4 mailing list

(see

http://www.mail-archive.com/pyqt%40riverbankcomputing.com/msg23733.html)

and he told me to use getSaveFileNameAndFilter.

The other option would be to change PyQt4, dunno which is best.

Greetings

Martin

Martin, thanks for the explanation. That made a lot more sense. I will

go

ahead with the patch.

getSaveFileNameAndFilter was only added in pyqt-4.6.

oy! Why the heck did qt4 change their API like this?

To make it more pythonic for python-3. You can set the api to v2 with

python-2, but it is not the default.

What should we do?

I think the change being discussed is only necessary when the QString

api is set to v2. So, we should be able to do something along the

lines of:

import sip

try:

if sip.getapi(“QString”) > 1:

   # support the new api

else:

   # support the old api

except (AttributeError, KeyError): # call to getapi may fail with

older versions of sip

support the old api

I also assume that some sort of fix should be applied to the v1.0.x?

I think it should be, if the fix does not break backward compatibility

with <PyQt4-4.6.

Darren