Qt for Python Release: 6.4 is finally here!

It is early fall in the northern hemisphere, and with that not only do the leaves drop, but also a new Qt for Python release! 🐍 

Perhaps you were wondering why the release was not on the same day as Qt?: It was a mixture of CI not liking our configurations, conferences happening during the release, and COVID affecting 50% of the team. Now, everything is working well, and most of us have recovered. 😊 

If you want to head to the changelog directly, you can find it here.

Catching up with Qt: new modules and functions 

A new Qt release brings new modules, and as usual, Qt for Python joins the ride. You can now use the QtPdf, QtPdfWidgets, QHttpServer, and QtSpatialAudio modules not just with Qt, but with Qt for Python as well. 

We have implemented Q_ARG/Q_RETURN_ARG for QMetaObject.invokeMethod() with arguments. Also, we included the QLoggingCategory class along with the qCDebug(), qCInfo(), qCWarning() and qCCritical() functions.  

In case you were missing the qHash() functions, we have exposed them to Python as well, along with many other functions: 

  • qt_set_sequence_auto_mnemonic() 
  • glGet(Boolean|Double|Float|Integer)v() and glGet(Boolean|Double|Float|Integer)i_v()  
  • QWebEngineCookieStore.setCookieFilter() and QtWebEngineProfile.setNotificationPresenter()  
  • QQmlContext.setContextProperties() 
  • QAudioBuffer.data() and QAudioBuffer.constData() 

PyPy and Python Compatibility 

After the initial release with the PyPy 3.8 compatibility, we solved some issues to make PySide compatible with PyPy 3.9. You can get these fixes from PyPi. 

As you might be aware, few years ago we introduced support for NumPy. We have now decided to include it by default, unlocking lots of specialized APIs, like a new function that we added: a NumPy overload for QSurfaceDataProxy.resetArray(). 

In case you are as excited as we are about Python 3.11 and the upcoming releases, we are happy to tell you that PySide 6.4.0 is already compatible with the last RC version from Python 3.11, so you can try it out and let us know of any corner case we forgot to fix. 

New examples 

The official Qt for Python examples provide valuable points of reference, demonstrating how to use PySide and the Qt APIs in practice, and with this release, we have added several examples. This includes:

In addition, we have added two new examples that demonstrate how use the Trio package for async support in Python in conjunction with Qt. This is only the beginning of a renewed effort to improve support for Python async features with Qt, so stay tuned for more examples demonstrating asyncio with Qt, support for awaiting Qt Signals, and more in the future! 

The new Enum system 

PySide is in the interesting position of being both Qt (with its C++ roots and all that entails) but also distinctly Python. Where possible, we strive to align PySide further with Python conventions and use as many Python features as we can, if they make sense. 

One such area that we tackled now affects enums, which was implemented as bound C++ classes, but now it is updated to leverage Python's own enum mechanism. 

Although the new Python enums and the old Shiboken-based ones are compatible with each other, but there are a few differences or restrictions: 

  • Python enums cannot be inherited from each other, whereas Shiboken enums can 
  • Python enums do not allow undefined values, Shiboken enums do 
  • Python enums always need exactly one argument, Shiboken enums have a default zero value 
  • Python enums rarely inherit from int, Shiboken enums always do 

You can see that  some of these differences are between flags. For example, until now, you could either write 

    flags = Qt.Alignment() 

    enum = Qt.AlignmentFlag 

or use the enum shortcuts like these:

    Qt.AlignLeft = Qt.AlignmentFlag.AlignLeft 

    Qt.AlignTop  = Qt.AlignmentFlag.AlignTop

These shortcuts, and flags no longer exist (officially) from 6.4.0 onwards. Instead, Python has an enum.Flags class, which is a subclass of the enum.Enum class. 

If the thought of updating all your code left and right makes you sweat more than an overheated pumpkin spice latte, do not fret, for salvation has a name, and it’s “forgiveness mode”. This transitory mode allows you to continue using the old constructs but translates them internally into the new ones. For example, if you write 

    flags = Qt.Alignment() 

    enum = Qt.AlignLeft 

    item.setForeground(QColor(Qt.green)) 

    flags_type = QPainter.RenderHints 

    flags = QPainter.RenderHints() 

    chart_view.setRenderHint(QPainter.Antialiasing) 

you get a construct that mimics the following code, which is the recommended way of using flags and enums: 

    flags = Qt.AlignmentFlag(0

    enum = Qt.AlignmentFlag.AlignLeft 

    item.setForeground(QColor(Qt.GlobalColor.green)) 

    flags_type = QPainter.RenderHint 

    flags = QPainter.RenderHint(0

    chart_view.setRenderHint(QPainter.RenderHint.Antialiasing) 

With this you can at least initially ignore the difference between old and new enums, as long as the new enums are properties of classes. 

New tools 🧰

We have been been requested many times to offer more tooling, which could enable new and experienced developers to achieve more with PySide. So we decided to include a couple of extra tools to reduce some of the time-consuming steps while developing applications using Qt for Python: 

pyside6-qml

This tool mimics the capabilities of QML runtime utility for Python and enables quick prototyping with Python modules. It also makes it easy to integrate new QML types defined in Python files, thereby enabling creating pseudo Python QML plugins.   

 

 


pyside6-qtpy2cpp

This tool is a simple approach to convert your Python code into C++, enabling you to file issues on the Qt project when the problem is not found on the Python layer. We also thought about helping newcomers that want to convert their Python projects into C++. Please keep in mind this tool is experimental, and many issues will be found, so always double check the generated code.

pyside6-deploy

This tool is intended to help in-experienced developers with freezing and compiling tools to get an executable from their PySide project. We include a simple wrapper for Nuitka, so you can just run pyside6-deploy your_file.py to get it done. 

 

 

Other wrappers were added as well, such as pyside6-qmlformat and pyside6-qmlls to improve the QML workflow.

Many improvements to Shiboken 🥷

Considering that most of the changes related to the new Enum system happened at a CPython level, Shiboken was modified in favor of adjusting the generated code to the new implementation. But not only that, there are always new improvements that the team is rolling out, to improve the user experience for those who rely on Shiboken as a binding tool can take some benefit. 

For the people out there using modern C++, you might have noticed that so far we didn’t have support for the latest C++ operator, the spaceship comparison – starting from 6.4.0 it is possible to recognize it for binding generation purposes. 

Even though the typesystem looks like a simple XML file, it’s constantly evolving, adding new features, checks, etc., to extend the functionality when exposing complex structures or functions. For that a few things were added in this release: 

  • Meta type registration is now configurable in the typesystem, while using the ‘qt-register-metatype' on value-types. This can be used so the meta type registration is generated for the name option. 
  • You can use now use ‘handle’ and ‘value-handle’ as types for smart-pointer-type, to be able to use a basic handle type (operator->()) or a getter function returning a value T (like for std::optional). 
  • A function to get the type  name of a polymorphic class can now be specified for object-types. 
  • It is possible now to define parent ownership heuristics for a type, so we can avoid unintended ownership transfers 

A few other things are included as well, like the exception propagation through return value ownership modifications, a way of specifying free functions with complete custom implementations, extra command-line options for compiler, path, and platform, and it’s also possible to specify a list of functions to be generated, contrary to the old approach where functions had to be skipped. 

And finally, there is now support for std::unique_ptr :) 

Internal improvements and Documentation 📚

We have been working on how to improve the automatic transformation of C++ snippets into Python for our documentation, covering many corner cases that existed earlier. If you see a snippet that is not well-formed,  let us know via a bug report, otherwise, we cannot catch all the issues with the current snippets. 

Complementary, if for some reason you build the documentation locally, we decoupled the process a bit, so you no longer require a complete PySide build to get some API documentation properly built. 

If you are using VS Code, we have updated our debugging tutorial for Windows users. 

What else is cooking? 🧑‍🍳

We have been doing lots of research during the last months because we wanted to spend some time exploring ideas and areas where we could make Python shine. 

If you follow our development notes and are currently on one of our platforms, you might know what we have been playing with lately. In case you have not, the team has been working on: 

  • Asynchronous support, 
  • Embedded system compatibility and wheels automation, 
  • WebAssembly, and 
  • Android deployment 

Do you have any preference for those options? Let us know! 

Keep in mind that we are really open to new crazy ideas, where do you want to see PySide next? Are those topics enough? We would really appreciate your feedback. 


Blog Topics:

Comments