Skip to content

Support for Qt5#241

Closed
geggo wants to merge 6 commits into
enthought:masterfrom
geggo:traitsui/qt5
Closed

Support for Qt5#241
geggo wants to merge 6 commits into
enthought:masterfrom
geggo:traitsui/qt5

Conversation

@geggo
Copy link
Copy Markdown
Contributor

@geggo geggo commented Sep 28, 2015

Dear developers,

I had the feeling that the sands of Qt4 are running out, so I started adding support for PyQt5 to traitsui and pyface. This is not a serious pull request, yet unfinished, but I would like to get some feedback how to proceed. Some basic stuff such as text or range editors already work.

I started by copying the implementation from the qt4 backend, and then adding the necessary changes. Most of the changes are due to the splitting of the QtGui submodule of qt4 into QtGui and QtWidgets in qt5. These are mostly trivial and are performed by script. Then, where still in use, the old SIGNAL/SLOT connections need to be updated to the new style signals/slots.

Similar to what matplotlib did to support both qt4 and qt5, it is possible to use the same code, ported to qt5, for both qt4 and qt5, with a thin layer to make qt4 look like qt5. I think this would be the way to go also for traitsui/pyface. However, this implies that third party modules that rely on pyface.qt to import qt4 need to be modified to support the new module layout.

Any feedback, especially on the following issues is welcome:

  • Are you interested in this? How should I proceed? What do you think is the best way for adding support for qt5?
  • What about testing? Especially for pyface I did not find tests that cover most of the API?

Gregor

@corranwebster
Copy link
Copy Markdown
Contributor

This is awesome and very time-appropriate, as we were just discussing what might be needed for supporting Qt5 in TraitsUI. Thanks for kicking this off!

In terms of how to proceed, it'd be great if we can minimize the amount of duplicated code just from the point of view of reducing maintenance costs going forward (eg. avoid having to fix the same bug in multiple places, if possible). Our tentative plan had been to see if we could manage to have one common qt4/qt5 codebase which avoided using new features of Qt5 for the near future - I'm not sure if that's possible or practical, but it Matplotlib can manage it, or something close to it, then there is hope! In fact, once PySide has solid support for Qt5, I'd be reasonably comfortable about deprecating Qt4.

It's worth noting that this is similar to the plan for WxPython 3.0 support, which we recently merged experimental support for in PyFace and TraitsUI.

In terms of testing, tests are indeed a bit skimpier than we might like for TraitsUI and Pyface, but I'm happy to merge a PR that has "experimental" Qt5 support as long as all tests run and any examples which run under Qt4 also run under Qt5. In addition, for Pyface, although there is a lot that is not tested, we've put in a fair bit of effort in the last couple of months to make sure that the core components now at least have basic smoke tests.

The other obstacle to testing is that we recently switched to containerized Travis CI builds and Qt5 APT is not yet whitelisted (see travis-ci/apt-package-safelist#442), so Qt5 tests would need to build Qt5 and cache it in the container for the time being, which adds some complexity to the test infrastructure.

So does the following seem reasonable to you (since you've been looking at the issue more closely than I have yet):

  • get rid of all the old SIGNAL/SLOT code in the qt4 codebase (this seems like a good idea in and of itself, and I'd happily accept a PR that did just this!)
  • can we paper over the QtGui/QtWidget split in PyFace: we already abstract the PyQt/PySide split away in pyface.qt.* and it almost sounds as if we could handle a lot of the split by adding a pyface.qt.QtWidget module that imports from QtGui if it detects Qt4 is running. (Or do the reverse and make pyface.qt.QtGui import both QtGui and QtWidget of Qt5 is detected, but that seems less future-proof).
  • split pyface.qt.QtGui imports appropriately
  • we make ETS_TOOLKIT values of qt, qt4 and qt5 all be synonyms.
  • patch up any other issues as they appear.

Once again, thanks for doing this!

@corranwebster corranwebster mentioned this pull request Sep 28, 2015
@geggo
Copy link
Copy Markdown
Contributor Author

geggo commented Sep 29, 2015

Dear Corran,

good to hear you like that approach. Concerning your roadmap, I think that is feasible.

  • old style signal/slot: I already converted a bunch, about 70 occurrences remain, major part is trivial to change.
  • splitting of the imports is done
  • hiding away the differences in pyface.qt is already contained in the PR (but yet untested).

Frankly, I have difficulties understanding the toolkit selection process with all the automatic choices.

So I can offer to go ahead, finish the porting to a single code base for both qt4 and qt5, using the qt5 syntax, with a layer in pyface.qt so it continues to work with qt4. Don't know how long this will take, but I will cry for help if I get stuck, especially with testing and fixing remaining issues.

Gregor

@corranwebster
Copy link
Copy Markdown
Contributor

Hi, please go ahead, and please ask for any help you need.

To answer your question about toolkit selection:

  • the point of truth about what toolkit has been selected is traits.etsconfig.etsconfig.ETSConfig which has a toolkit attribute. This can be set either directly before any GUI code has been loaded, or via the ETS_TOOLKIT environment variable, or via a command-line argument.
  • if you try to load a GUI and ETSConfig.toolkit isn't set, then both Pyface and TraitsUI have code that goes about trying to determine what toolkits are available by importing the appropriate subpackages in order until something works, or you end up with the null backend. Unfortunately Pyface and TraitsUI have different code for doing this (TraitsUI should probably just call out to Pyface), so whichever of the two gets activated first via importing is the one which will trigger the selection.

For testing, the easiest is to set the ETS_TOOLKIT environment variable to your preferred value, if needed by prefixing to the command you are running, eg.

ETS_TOOLKIT=qt4 python sample_code.py

@geggo
Copy link
Copy Markdown
Contributor Author

geggo commented Sep 30, 2015

Dear Corran,

I went ahead and got rather far. I think most of the porting to Qt5 is done and got to the final point: cry for help. Code is living on the the qt5_V2 branch of geggo/traitsui and geggo/pyface. You can switch between using qt4 and qt5 by setting QT_API to pyqt or pyqt5.

Most tests passes, some traitsui demos fail, mostly due to the issues:

  • QFileDialog should have member setReadOnly(bool), but is missing in PyQt5
  • AttributeError: 'QHeaderView' object has no attribute 'setResizeMode'

Most annoying is an issue, with my anaconda python using

/Users/gregor/anaconda/envs/traitstest/bin/python

(this is used when I type in python) Qt5 fails with

This application failed to start because it could not find or load the Qt platform plugin "cocoa".

But with

/Users/gregor/anaconda/envs/traitstest/python.app/Contents/MacOS/python

(this is used when I type in ipython on the console) no failure. Possibly some issue with the qt5/pyqt5 conda package I have installed.

Gregor
(PS I'll be busy next days)

@corranwebster
Copy link
Copy Markdown
Contributor

Hi @geggo Thanks for this once again. Unfortunately, I don't know about that issue - I may try to install Qt5 on my mac, but more likely I'll just work in my linux VM, since it's easier to work with for this sort of stuff, but if I have any insight, I'll let you know.

Also, I see the pyface Qt5_v2 branch, but not the traitsui one. Did you push it to github, or am I missing something?

@geggo
Copy link
Copy Markdown
Contributor Author

geggo commented Oct 2, 2015

Am 01.10.2015 um 23:49 schrieb Corran Webster notifications@github.com:

Hi @geggo https://github.com/geggo Thanks for this once again. Unfortunately, I don't know about that issue - I may try to install Qt5 on my mac, but more likely I'll just work in my linux VM, since it's easier to work with for this sort of stuff, but if I have any insight, I'll let you know.

Also, I see the pyface Qt5_v2 branch, but not the traitsui one. Did you push it to github, or am I missing something?


Reply to this email directly or view it on GitHub #241 (comment).

Dear Corran,

forgot to push also to the geggo/traitsui repository, Qt5_v2 branch, now it’s there. Sorry for the confusion.

I think the failures with PyQt5 I have seen are not directly related to pyface/traitsui, but to the way how the Qt5 library is installed within the anaconda environment and where it searches for plugins. I assume if you rely on a system wide Qt5 install they would go away.

Gregor

@jf---
Copy link
Copy Markdown

jf--- commented Oct 6, 2015

Excited to see TraitsUI moving fwd, cool...

@geggo , have you tried setting $QT_PLUGIN_PATH=""? Or you could use the QtGui.QApplication.setLibraryPaths([]) before creating app.

A more detailed conversation on the conda list that touches upon this topic is found here

@geggo
Copy link
Copy Markdown
Contributor Author

geggo commented Oct 8, 2015

As a notice (@jf---), the failure I have seen when using Qt5 (on OS X with Anaconda Python, Qt5 installed via conda install --channel https://conda.anaconda.org/asmeurer pyqt5 ):

This application failed to start because it could not find or load the Qt platform plugin "cocoa".

can be resolved by deleting qt.conf, in my case located in

/Users/gregor/anaconda/envs/traitstest/bin/qt.conf

with contents

[Paths]
Prefix = /Users/gregor/anaconda/envs/traitstest

@jf---
Copy link
Copy Markdown

jf--- commented Oct 8, 2015

@geggo , I'm on conda as well, great to hear this is a way to sidestep the issue...

@PAleksandrov
Copy link
Copy Markdown

It seems that the 408 line at traitsui/qt5/ui_base.py:
QtCore.QObject.connect(control, QtCore.SIGNAL('finished(int)'),
self._on_finished)
must be changed to
control.finished['int'].connect(self._on_finished)

@geggo
Copy link
Copy Markdown
Contributor Author

geggo commented Oct 19, 2015

@PAleksandrov, the development now happens at the traitsui/qt5_V2 branch of geggo/traitsui, there this issues (should) have been fixed. Sorry for the confusion.

@corranwebster
Copy link
Copy Markdown
Contributor

Closing as we have support for Qt5 vias Pyface at a more basic level.

@larsoner
Copy link
Copy Markdown
Contributor

larsoner commented Sep 8, 2017

@corranwebster I'm looking into Qt5 support (or really take a stab at implementing it) for Mayavi and I'm a bit confused.

I noticed that there is still this line:

TraitUIToolkits = ['qt4', 'wx', 'null']

Even adding 'qt5' to this list, there is no traitsui/qt5 directory, so the _import_toolkit in toolkit.py can't succeed. So it seems like the changes like in this PR would be needed to get Qt5 working, no?

Or is "qt4" meant to be a misnomer, and Pyface is supposed to use PySide or PyQt5 to get Qt5 support, if available, even when "qt4" is supplied ...? (I have the latest pyface installed and this doesn't seem to work.)

This is mostly necessary because of recurring bugs we've had with using matplotlib and mayavi (which uses traitsui) concurrently (see many bug reports about "API QDate" and you'll see what I mean). I think qt5 would solve it, so it would be great to get it working.

@prabhuramachandran
Copy link
Copy Markdown
Member

@larsoner -- I think I have already added support for Qt5 in Mayavi master, see enthought/mayavi#528 .

@larsoner
Copy link
Copy Markdown
Contributor

larsoner commented Sep 8, 2017

Okay I'll try it and report there, thanks @prabhuramachandran

(I guess the end result is that qt4 will really use Qt4 or Qt5, depending on what's available, then?)

@prabhuramachandran
Copy link
Copy Markdown
Member

@larsoner -- IIRC, I think you need to set QT_API=pyqt5

@corranwebster
Copy link
Copy Markdown
Contributor

@larsoner Yes, for the time being ETS_TOOLKIT=qt4 means "use Qt", and then the QT_API environment variable allows you to select between PyQt4, PyQt5, or PySide. The way that qt5 support is implemented is by backporting the Qt5 classes into the appropriate Qt4 namespaces (eg. here https://github.com/enthought/pyface/blob/master/pyface/qt/QtGui.py#L7), so you will need to be aware of that if working on Qt5 support.

It would be nice to allow ETS_TOOLKIT=qt, but that will require lots of changes across ETS because of package names which involve "qt4" and/or changes in how the toolkits are resolved. Pyface at least is in a state where this can be done fairly easily for "pure" Pyface code, but that pattern needs to be propagated throughout the codebase for it to work everywhere.

@larsoner
Copy link
Copy Markdown
Contributor

larsoner commented Sep 8, 2017

Great, thanks for the info. Looks like it works when using PyQt5 + latest PyFace / Traits / TraitsUI. Now I'm having problems with segfaults but I think that's VTK's problem.

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.

6 participants