Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Set all QT4 SIP APIs #10101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed

Conversation

patricksnape
Copy link

After QT is imported the SIP API functions can no longer be
called to set the QT API. This change ensures that all of
the APIs are either set to 1 or 2 so that other packages
that may be imported after this function have a consistent
interface. This is consistent with other packages such as
pyside and is particularly relevant for IPython as the
%matplotlib magic means that one of the first set of imports
made in an IPython session is often from the %matplotlib
magic.

For example:

%matplotlib qt
from pyface.qt import QtGui, QtCore

fails without this change as only some of the required APIs have been set to version 2.

After QT is imported the SIP API functions can no longer be
called to set the QT API. This change ensures that all of
the APIs are either set to 1 or 2 so that other packages
that may be imported after this function have a consistent
interface. This is consistent with other packages such as
pyside and is particularly relevant for IPython as the
%matplotlib magic means that one of the first set of imports
made in an IPython session is often from the %matplotlib
magic.
@patricksnape patricksnape changed the title Set all SIP APIs Set all QT4 SIP APIs Dec 21, 2016
sip.setapi('QString', version)
sip.setapi('QVariant', version)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to QVariant? Is that no longer needed?

Also, you'll need to update the docstring of this function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

@tacaswell
Copy link
Contributor

What is the ordering on matplotlib doing the imports vs ipython doing the imports?

Should this actually be done in mpl not in IPython?

@patricksnape
Copy link
Author

Well as long as this method is called it's always a 'race' to whoever sets the state first. If we are going to set the APIs here at all then we should just ensure that we set them all. I can't believe that it is really even valid to just set one or two of the APIs to a different version but leave the rest as another.

I haven't looked at the matplotlib code but if they are using SIP to set the APIs as well then they also need to ensure they set all the APIs.

@tacaswell
Copy link
Contributor

Why would it not be valid to only set some of the APIs to v2? mpl has been doing this for as long I have been working on the project (and if it wasn't valid why would river bank have put in that fine of control?)

See https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/qt_compat.py for where mpl takes care of this.

@patricksnape
Copy link
Author

patricksnape commented Jan 2, 2017

Fair enough, I revoke that, I'm not an expert in QT so I likely misunderstood. It's just frustrating that once you import QT the APIs are fixed and so if a project is opinionated about which API it wants then obviously they conflict. I guess the real question here is whether or not many projects use API v1 and so what the 'default' should be. Clearly this is more complicated than I thought which is a shame. Perhaps the best course of action is to check pyface and see if it really needs all those APIs set to v2.

@takluyver
Copy link
Member

My reading of the discussion is that we shouldn't actually do this; while it may be frustrating to use a mixture of packages which load PyQt, anything we do with selecting Qt APIs is probably fixing some cases at the cost of others, rather than improving the overall situation. If that is the case, then I'd rather leave things as they are so that at least the problems are consistent, rather than trying to work out which use cases are commonest.

Any objections?

@takluyver takluyver added this to the no action milestone Jan 12, 2017
@patricksnape
Copy link
Author

It's just frustrating that these magics tend to be at the top of the notebook and so are often the first thing loaded - which then hoses interaction with other QT packages. But I understand that this isn't a pressing change (as nothing is actively broken within IPython so I understand closing this issue from your perspective).

@takluyver
Copy link
Member

Right, but that goes both ways: if you set all those APIs to version 2, then any code which was expecting to use e.g. QDate v1 is broken. The first thing to load Qt has to decide all the API versions, but there's no correct set of values that will avoid problems in general.

One possible answer is for you to use an IPython startup file, which will run whenever you load a notebook, so you can pick all the APIs and load Qt before the notebook code runs. The downside of that is that you could create notebooks that only work on your machine.

Closing for now, but feel free to continue this discussion here.

@takluyver takluyver closed this Jan 13, 2017
@tacaswell
Copy link
Contributor

This problem is particular to pyqt4, pyside, pyqt5, and pyside2 are always v2. This particular set of pain will fade away if we just wait long enough 😉 .

@Carreau
Copy link
Member

Carreau commented Mar 14, 2017

We've got some discussion on today's dev meeting. We'll be reopening this and try it. We can revert if we have more complaints from the other side (if any).

@takluyver
Copy link
Member

I'm still -0.5 on this - I don't think there's a right thing to do, and in the absence of one, I'd rather at least be consistent in what we do. Yes, we can revert it, but it's not necessarily true that the bugs it causes will be clearly related to this.

Maybe an alternative would be to add a new QT_API option like pyqt_allv2?

@Carreau
Copy link
Member

Carreau commented Mar 14, 2017

The problem IIUC is that if sip is used, you anyway can't use different versions across APIs. So no setting uniform API will not work anyway. Seeing that this is mostly to keep potential compatibility with pyqt4 which is now quite old (and not even on PyPI ?)

We're also pushing forward on Python versions, and dropping support for 2.x, so I think that pushing also on Qt5 is reasonable.

Happy to get a pyqt_allv2, but I believe it might be good to have it on by default.

@ccordoba12
Copy link
Member

I'd rather at least be consistent in what we do

Given that Mayavi now requires other APIs to be set (besides QString and QVariant), I think consistency demands to set them to v2 too.

@tacaswell
Copy link
Contributor

I would lean towards bumping all imports to v2 in both ipython an mpl.

On the mpl side we have the 'backend.qt4' rcparam which can take the values PyQt4 (all v1) and PyQt4v2 (some v2). I think adding a 'PyQt4v2all' path would be reasonable and would solve this problem. I am 👍 on that going for for 2.0.1.

@fperez
Copy link
Member

fperez commented Mar 21, 2017

Forgive me for being dense, I'm lost in a maze of Qt API versions, all alike...

Why would the following not work?

  • By default, we explicitly set all API versions to v2 in Qt4 when loading via %gui qt4.
  • We offer a new %gui qt4v1 call that instead sets all versions to v1.
  • The version setting code is modified from its form in this PR to something like:
for QAPI in ['QDate', 'QDateTime', 'QString', 'QTextStream', 
                    'QTime', 'QUrl', 'QVariant']:
    try:
        sip.setapi(QAPI, version)
    except ValueError:
        pass

That would make it possible for people who need some odd mix of v1 and v2 to still get what they want, simply by doing something like:

for QAPI in ['QDate', 'QString', 'QUrl']:
    sip.setapi(QAPI, 1)
%gui qt4

Those (I imagine quite rare) cases would still be able to mix and match as desired, while the majority of users of Qt4 would either get v2 by default, or could get v1 with a simple %gui qt4v1 call.

Does this sound OK? It would require an update to this PR, but a fairly simple one, I think, and it seems to cover all the cases to me. Am I missing something?

@ccordoba12
Copy link
Member

+1 to @fperez proposal. I find it cleaner and simpler than adding yet another QT_API value

@Carreau
Copy link
Member

Carreau commented Mar 21, 2017

+1 to @fperez proposal. I find it cleaner and simpler than adding yet another QT_API value

I'm unsure that's easy (well the for loop part is, the adding qt4v1 magic option not that much. The API version is set as a side effect of importing the modules that lookup which api versions are available (kinda silly). Without large API breakage and major refactoring I don't see any clean and easy way to do it.

It's anyway already wrong on 5.x:

In [1]: %gui qt4
In [2]: from IPython.external.qt_for_kernel import QT_API
In [3]: QT_API
Out[3]: 'pyqt5'

And the names of the %gui options are largely tied to names of modules. So I'm unsure what to do.

@Carreau Carreau modified the milestones: 6.1, no action Mar 21, 2017
@ccordoba12
Copy link
Member

The API version is set as a side effect of importing the modules

You can set it before importing PyQt4. That's what we do in qtpy:

https://github.com/spyder-ide/qtpy/blob/master/qtpy/__init__.py#L96-L102

@Carreau
Copy link
Member

Carreau commented Mar 22, 2017

You can set it before importing PyQt4. That's what we do in qtpy:

https://github.com/spyder-ide/qtpy/blob/master/qtpy/__init__.py#L96-L102

Yes, but from IPython.external.qt_for_kernel import QT_API would still return the wrong things in IPython. I would like to understand why, and actually fix it. Also in terminal IPython, it's not sufficient (AFAICT) you need to setup eventloop integration between prompt-toolkit and QT, and "just" setting the API to v1 (or v2) before setting integration does not seem like the right things as it will still go through the autodetection mechanism, and may try to setup a different a different integration than the one that was forced before.

@ccordoba12
Copy link
Member

I would like to understand why, and actually fix it

Sure, that's the right thing to do because it seems things are broken now.

@patricksnape
Copy link
Author

I'm +1 on @fperez suggestion. Though I'm not 100% clear I understand enough about QT to know what could be causing the issue @Carreau is talking about. Should I update this PR to be as described by @fperez and then someone can give some guidance on how we might solve the other issue? Or we break that into a separate PR/issue perhaps?

@Carreau Carreau modified the milestones: 6.1, 6.2 May 24, 2017
@Carreau Carreau modified the milestones: 6.2, 6.3 Sep 11, 2017
@takluyver
Copy link
Member

What's the status of this? Since IPython itself never uses Qt, I'm happy to do whatever the matplotlib devs reckon is a good idea, as mpl uses Qt and is probably the main reason to load it inside IPython.

@tacaswell
Copy link
Contributor

Nothing has happened on the mpl side, but it is still probably a good idea.

I am happy with @fperez 's suggestion for matplotlib and ipython to both try to set them all.

OTOH Maybe if we procrastinate long enough qt4 will just fade away....

@Carreau
Copy link
Member

Carreau commented Oct 15, 2017

Yes, the status is "Someone need to do it", or as @tacaswell pointed if we wait enough maybe nobody will care anymore.

@takluyver takluyver modified the milestones: 6.3, wishlist Mar 29, 2018
@ivanov
Copy link
Member

ivanov commented Apr 17, 2020

Good news, everyone! As of a month ago - thanks to @anntzer's work on matplotlib/matplotlib#16840 - qt4 is being deprecated in matplotlib 3.3.

So it seems like procrastinating long enough paid off :)

Not sure what that means for this open PR, but I figured the interested parties will enlighten the rest of us.

@patricksnape
Copy link
Author

Happy to close this as things have changed a lot since I made this post and projects like pyface now support QT5:

enthought/pyface#293

@patricksnape patricksnape deleted the set_all_sip_apis branch June 11, 2020 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants