Skip to content
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

Add PySide6 support #367

Open
Martmists-GH opened this issue Dec 24, 2021 · 20 comments
Open

Add PySide6 support #367

Martmists-GH opened this issue Dec 24, 2021 · 20 comments
Labels

Comments

@Martmists-GH
Copy link

No description provided.

@mottosso
Copy link
Owner

I'd like for this to happen too. Pull-request welcome.

@asztalosdani
Copy link

What would it mean in theory?
Everything should align to the PySide6 interface?

@mottosso
Copy link
Owner

mottosso commented Feb 7, 2022

I'd imagine what would be the most common requirement is for all code written with Qt.py up to this point to still be working with PySide6. That means making PySide6 backwards compatible with PySide(1). Such that nothing breaks, but also no new features from PySide6 would make into Qt.py, similar to how nothing new from PySide2 made it in either.

Is that what you'd expect too?

@asztalosdani
Copy link

From the README.md:

Usage

Use Qt.py as you would use PySide2.

This can be interpreted in two ways.

  1. Use the PySide2 syntax, and you can run it on any Qt version.
    (I think you refer to this one). So this would mean, integrating PySide6 to follow PySide2 syntax. Benefit: Existing code using Qt.py is still usable.
  2. Use the latest syntax, and you can run it on any Qt version.
    This means integrating PySide6 so that everything follows its syntax. This would probably introduce backward incompatible changes, so a major version bump would be necessary. Benefits: you are using the latest syntax.

@mottosso
Copy link
Owner

mottosso commented Feb 8, 2022

Benefit: Existing code using Qt.py is still usable.

This would be my preference for sure. That said, there is a third alternative.

  1. Deprecate PySide(1), and make Qt.py bridge PySide2 and PySide6

That way, existing code would still run, but now you'd be able to also use features in PySide2 that wasn't in PySide(1). I personally don't develop for PySide(1) anymore so to me this would be fine. But I know a lot of people using Qt.py are still stuck with PySide(1) so it's not obvious which route is better.

@johnhaddon
Copy link

That said, there is a third alternative : Deprecate PySide(1), and make Qt.py bridge PySide2 and PySide6

I'm in the early stages of investigating a transition from PySide2 to PySide6, and from the little I've learned so far, this seems the only real option. Qt 4 only has QGLWidget, Qt 5 deprecated it and introduced a replacement in QOpenGLWidget, and finally Qt 6 has dropped QGLWidget entirely1. QGLWidget (and associated classes) seem different enough to the QOpenGLWidget equivalents that bridging them would be far from trivial, if possible even.

Qt.py was instrumental in allowing a smooth transition from Qt 4 to Qt 5, but - at least from my point of view - that transition is long over (2015 was the last VFX Platform to include Qt 4). I'm pretty convinced that a similarly smooth transition from Qt 5 to Qt 6 isn't possible without letting go of Qt 4.

Footnotes

  1. https://doc.qt.io/qt-6/opengl-changes-qt6.html

@dekekincaid
Copy link

I would love to see a major version 2 which is pyside2 & 6. If people still need pyside1 support they can keep using v1 of Qt.py.

@MHendricks
Copy link
Collaborator

I agree with using the major version to indicate a switch between supported qt versions. Given that it supports PyQt and PySide I would say we stick with Qt versions for this identifier, Ie Qt4, Qt5, Qt6.

I'm ok with going to v2.X.X for Qt5->6, but we could be more descriptive with the version number. I think PySide moving their naming convention from PySide2 to PySide6 for Qt6 is more consistent naming than if they would have called it PySide3. Given that Qt.py supports transitioning between 2 versions of Qt, perhaps we want to indicate the two supported versions in the major version number. Here are some ideas I've had.

  1. a>>b: Simply join the two Qt version numbers, possibly with number padding(to future proof against the distant Qt10+). 45.X.X or 405.X.X for Qt4->Qt5, and 56.X.X or 506.X.X for Qt5->Qt6.
  2. a*b: The six module used 6=2*3 for its name, so we could use 20.X.X for Qt4->Qt5, and 30.X.X for Qt5->Qt6.
  3. a.b: This would add an extra . separating the old and new qt versions. Qt4->5: 4.5.X.X.X. Qt5->6: 5.6.X.X.X.

These convey the specific Qt transition being supported simply by the version number, but lead to very large major version numbers with large gaps. If we did this I think we should migrate any future releases of the current Qt4->5 code from v1.X.X to the corresponding version names.

@dekekincaid
Copy link

Why get all fancy which will ultimately just be confusing? Just use basic semantic versioning.

@mottosso
Copy link
Owner

I'm pretty convinced that a similarly smooth transition from Qt 5 to Qt 6 isn't possible without letting go of Qt 4.

This is a good point. It's also worth re-iterating the advantage of keeping compatibility with Qt 4, which would be that everything written with Qt.py so far would keep working without modifications in newer software with access to PySide6. That fills me with relief, as I wouldn't have to port anything, it would just keep working. 😊 Except, as you pointed out, certain modules simply aren't available anymore and cannot be ported.

I think the question then is; is there enough modules missing from PySide6 to justify letting go of Qt 4? I'd imagine users of a Qt 4-5-6 wrapper could choose to from PySide6.QtWidgets import QOpenGLWidget for their PySide6-specific projects, whilst benefiting from a wide compatibility in other projects.

What other un-portable modules or features are we considering?

@mottosso
Copy link
Owner

Why get all fancy which will ultimately just be confusing? Just use basic semantic versioning.

If we do choose to break backwards compatibility, we need to consider what should happen if you e.g. launch Maya and have 5 UIs written with Qt.py 1.0 and 2 new UIs written with Qt.py 2.0. You couldn't run these together in the same Maya session, but would need to update all UIs at once. And once updated you could no longer use them with Qt.py 1.0.

With this in mind, it could make sense to change the package name altogether, such that you can have both Qt.py 1.0 and e.g. Qt6.py on your PYTHONPATH at once.

@johnhaddon
Copy link

johnhaddon commented Feb 28, 2023

It's also worth re-iterating the advantage of keeping compatibility with Qt 4, which would be that everything written with Qt.py so far would keep working without modifications in newer software with access to PySide6.

Correct me if I'm wrong here, but my understanding is that the current Qt.py mantra is "Use Qt.py as you would use PySide2", but with a caveat : "without access to features not available in PySide1". One possibility is to just drop that caveat. I'd hope that would mean that everything written so far would continue to work without change in PySide1 and PySide2, but in addition I'd get my hands on QOpenGLWidget. The downside would be that folks writing new software that had to target PySide1 would have to be careful not to use features not available there. But I really really hope nobody is writing new software targeting PySide1. Either way, it seems reasonable to say that the balance has tipped such that the greater good is support for PySide6.

I'd imagine users of a Qt 4-5-6 wrapper could choose to from PySide6.QtWidgets import QOpenGLWidget for their PySide6-specific projects

At least for my specific use case (Gaffer), I'd be questioning the value of Qt.py at that point, particularly since I no longer have a need to support PyQt as well as PySide. Qt.py's beauty was that it had clearly defined principles that gave confidence you could write once without worrying about testing elsewhere, and any direct imports defeat that.

it could make sense to change the package name altogether, such that you can have both Qt.py 1.0 and e.g. Qt6.py on your PYTHONPATH at once.

If absolute clarity and sticking to the original principles of the project are paramount, this does seem the best option. I'd already be frustrated that a 4-5-6 wrapper would be hobbling usage of features in 5, and I can't imagine it being workable to extend that to a 4-5-6-7 wrapper and beyond. The more I think about it, the more a new module seems the best option. Qt.py's primary strength is in its principles, and a new module keeps those principles but allows a bump to the targeted minimum Qt version.

@mottosso
Copy link
Owner

Very good points.

clearly defined principles that gave confidence you could write once without worrying about testing elsewhere

At the moment, Qt.py is a lowest common denominator of Qt 4 and 5. It exposes everything in 5, except what isn't also in 4. So if we do retire Qt 4, every application will continue to work except not in an environment with only Qt 4 available, and except applications that use the completely removed QtGLWidget. That seems fair and safe. There are a handful of issues appearing here and via direct email for users of Qt 4 (primarily the scientific community who are even better at clinging on to old libraries than VFX), but they would also not benefit from Qt 6 and could stick with the current stable version of Qt.py.

So an argument could be made to stick with exposing the PySide2 interface through Qt.py, and "unlock" the parts that were excluded due to Qt 4, such as QOpenGLWidget. It wouldn't expose things that are exclusive to Qt 6, in the same way that Qt.py currently only exposes things that exist across 2 versions of Qt.

If we go this route, it would also make sense to stick with the same package name and semantic versioning (e.g. 2.0), whilst also benefiting from not having to refactor any software (since nothing (very little) was removed, only added).

The only question mark then is whether anyone is still using Qt 4? If not, then I think we've got a winner. Let's use this issue as a voice for anyone using it, link your colleagues to it and spread the word. This will their chance to keep compatibility with Qt 4.

@dekekincaid
Copy link

We have Qt4 code but it is only C++ and nothing else. Pyside v1 was missing way too many features and we only used pyqt4 at the time.

We used Qt.py to transition between qt4 to qt5 and once we moved away from all dcc's that supported qt4, we have been pyside2 ever since which is over 5 years now.

If there were a 2.0 we would just upgrade our code to support it. We wouldn't worry about code being mixed Qt.py v1 and v2. It is no different then moving between major versions of any software.

@hughetop
Copy link

While full backwards-compatibility would be nice, I don't know if it's feasible to keep PySide(1) compatibility. I agree with the VFX platform argument, PySide1 is so old it shouldn't be supported anymore. Yes it will be a pain to update PySide (and even PySide2/PyQt4) code, but so is updating to Python 3. We might as well update both since DCCs will stop supporting those old versions anyway.

@MHendricks
Copy link
Collaborator

We are no longer using Qt4(PySide,PyQt4), still using PyQt5/PySide2 though. I haven't looked into Qt6.

If you just need access to the extra QOpenGLWidget class, you could as a short term workaround, create a file called QtSiteConfig.py file that is importable when Qt.py is imported. It just needs the update_members function added.

QtSiteConfig.py

def update_members(members):
    members['QtWidgets'].append("QOpenGLWidget")

I don't have access to Qt6 so haven't tried this but based on the from PySide6.QtWidgets import QOpenGLWidget mentioned above, this should work if it exists. We have used this function to add Qsci, QtWebKit, QtSvg modules to Qt.py for internal tools.

This is not a long term solution, just a possible short term workaround.

@johnhaddon
Copy link

If you just need access to the extra QOpenGLWidget class, you could as a short term workaround, create a file called QtSiteConfig.py file

Thanks Mike - I didn't know about that mechanism. I'm not sure it's appropriate in this case though, since it's in Gaffer, which is basically a DCC. I assume we should avoid the QtSiteConfig.py mechanism so that it remains available for users to use at their site? I can just import direct from PySide2 for now, but wanted to raise the whole 4-5-6 thing in the hope of creating a path forward for when the time comes to support PySide6 too.

@MHendricks
Copy link
Collaborator

I assume we should avoid the QtSiteConfig.py mechanism so that it remains available for users to use at their site?

Yeah, it's best left for the end user as there is only one resolved import of that module name.

@AWhetter
Copy link
Contributor

If we do choose to break backwards compatibility, we need to consider what should happen if you e.g. launch Maya and have 5 UIs written with Qt.py 1.0 and 2 new UIs written with Qt.py 2.0. You couldn't run these together in the same Maya session, but would need to update all UIs at once. And once updated you could no longer use them with Qt.py 1.0.

This is a big concern for us too.

With this in mind, it could make sense to change the package name altogether, such that you can have both Qt.py 1.0 and e.g. Qt6.py on your PYTHONPATH at once.

I like this idea. We take a similar approach for other core libraries in our DCCs, and it's the approach we took with our in-house Qt shims before we adopted Qt.py. It makes it easier to figure out which of our libraries need to be updated when support for a Qt version is being dropped, because we can simply search code for "Qt6" when it comes time to drop support for Qt6.
It also means that you can expose the Qt bindings with the current Qt version that they support, and users can make use of the newer Qt version now but still get the benefit of shimming when the next Qt version comes along. For example, if I'm writing a Qt6 only library/application, I can make use of "import Qt6" now and be safe in the knowledge that it will continue working even when Qt7 comes along.

It would allow for Qt.py to define a matrix of Qt bindings to Qt API versions. Currently this would be:

PySide PySide2 PySide6
PyQt4 X
PySide X
PyQt5 X
PySide2 X
PySide6 X

But it could become:

PySide PySide2 PySide6
PyQt4 X
PySide X
PyQt5 X X
PySide2 X X
PySide6 X X X

Major version bumps in Qt.py would happen only when an Qt interface version is dropped, which is probably also when support for versions of Qt bindings would be dropped. For example you would drop support for PySide2 and PyQt5 when dropping the "Qt5" package.

@mottosso
Copy link
Owner

Given the initiation of #394 that seems to work well, and given the lack of change to QtWidgets in Qt 6, it seems safe to continue supporting Qt 4 and 5 alongside the introduction of Qt 6. Making Qt.py unchanged from the perspective of any existing applications, and seamlessly enable these same apps to continue running in Qt 6 enabled DCC's.

Any objections?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants