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()
andglGet(Boolean|Double|Float|Integer)i_v()
QWebEngineCookieStore.setCookieFilter()
andQtWebEngineProfile.setNotificationPresenter()
QQmlContext.setContextProperties()
QAudioBuffer.data()
andQAudioBuffer.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:
- surface_numpy and minimalsurface demonstrating 3D surface visualization,
- dropsite, dirview, googlesuggest, license wizard, heart rate server/client (QtBluetooth),
- QML Window, QML Plugins,
- analog clock (QtGUI) and digital clock (QtWidgets),
- spreadsheet, terminal (QtSerialPort),
- and character map.
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 forstd::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.