Foundry’s release of Nuke 16 comes with a significant but under-publicized change: PySide6 replaces PySide2. This update is briefly mentioned in the official release notes, but long-time Nuke scripters relying on Nukepedia or GitHub tools may run into issues if they aren’t prepared.

What’s Changed?

The shift from PySide2 to PySide6 follows Qt’s own evolution, bringing with it several breaking changes in the PySide API. If you’ve written Python tools for Nuke 15 or earlier, you might need to update them for compatibility.

You may be wondering how come we’re updating straight from 2 to 6, and what happened to PySide 3 though 5.  Worry not, no version was skipped. The Original PySide was released alongside Qt4. PySide2 was targeting Qt5. With the release of Qt6, PySide adjusted their version number to match the version number of Qt, so that it’s clearer that PySide6 works with Qt6.

There is an official guide to porting PySide2 code to PySide6, but I thought this article deserved to exist to list a few Nuke specific differences.

Here are the key differences you should be aware of:

PySide6 Module Renaming

PySide6 modules have a slightly different structure from PySide2. This means imports like:

from PySide2.QtWidgets import QPushButton

Need to be updated to:

from PySide6.QtWidgets import QPushButton

A simple find-and-replace may work for basic cases, but more complex scripts will require deeper modifications.

This update would also make the code now incompatible with older versions. You could use a few ways to preserve compatibility:

Use Qt.py

Qt.py (https://github.com/mottosso/Qt.py) is a shim that bridges Qt versions. Originally it was used to make code compatible between Qt4 and Qt5, with any code written with Qt.py compatible with both PySide and PySide2 (and PyQt4 and PyQt5), but since recently also PySide6!

While Qt.py is my favored approach to writing Qt code that is compatible with all versions of Nuke, it is worth noting a big limitation:
Qt.py only exposes the parts of Qt that are common in all 3 versions (4, 5, 6), and certain new features or removed features from older versions may not be available, or only available via QtCompat.

To use Qt.py, the above imports would become:

from Qt.QtWidgets import QPushButton

Use the Nuke version to drive the imports

Since we know that Nuke moved to PySide2 with Nuke 11, and PySide6 with Nuke 16, we can explicitly check the version and do the correct import.

The above import would become:

import nuke

if nuke.NUKE_VERSION_MAJOR < 11:
    # PySide for Nuke up to 10
    from PySide.QtGui import QPushButton
elif nuke.NUKE_VERSION_MAJOR < 16:
    # PySide2 for default Nuke 11
    from PySide2.QtWidgets import QPushButton
else:
    # PySide6 for Nuke 16+
    from PySide6.QtWidgets import QPushButton

Note that we need to be aware of certain changes, like the fact that in PySide QPushbutton used to be part of QtGui but moved to QtWidgets in PySide2.

Use try/excepts

Another alternative is to try/except your code. It’s a little bit uglier, but if your code is not exclusive to Nuke you may not be able to even import the nuke module, so this may be a necessary pattern:

try:
    # Try PySide6 first
    from PySide6.QtWidgets import QPushButton
except ImportError:
    try:
        # PySide2 as a fallback
        from PySide2.QtWidgets import QPushButton
    except ImportError:
        # Optional: PySide as a second fallback if we want to support even older versions.
        from PySide.QtGui import QPushButton

Shiboken Updates

If you’re using shiboken2 (I rarely see it in Nuke scripts, but just in case), you’ll need to also migrate to shiboken6.

Old:

from shiboken2 import wrapInstance

New:

from shiboken6 import wrapInstance

Widget Instances do not expose their class’s enum values anymore

In Qt, there are many enums/flags/constants that are exposed on classes.
As of PySide6, those are not available from instances of the class anymore.
This change is particularly painful to me, as I used instance values extensively.
Old:

form_layout = QtWidgets.QFormLayout()
form_layout.setFieldGrowthPolicy(form_layout.AllNonFixedFieldsGrow)  # Notice how it accessed AllNonFixedFieldGrow from the instance defined on the previous line.

New:

form_layout = QtWidgets.QFormLayout()
form_layout.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)

The new pattern will still function with PySide2 (where both patterns worked).

Nuke Specific: DAG Widget Changes

One of the more notable UI changes in Nuke 16 is the DAG widget update.

Previously, Nuke’s DAG (Node Graph) was an OpenGL-based widget, but with OpenGL deprecation in Qt6, Nuke has replaced it with a standard QWidget.

In the past, I and some other devs have found the DAG widget by checking the widget’s class. This will not work anymore as the widget seems to now be a regular QWidget.
Thankfully, Foundry has now named the widget, so we can find it by object name:

from PySide6.QtWidgets import QApplication, QWidget

def find_dag_widget():
    for widget in QApplication.instance().allWidgets():
        if widget.objectName() == "DAG":
            return widget
    return None

dag = find_dag_widget()

If your tools rely on accessing the DAG widget, be prepared for potential behavioral differences between the old OpenGL-based implementation and the new QWidget.

Dag widgets for secondary DAGs are also now named, for example if you had a Group1’s DAG open, it would be named “DAG.Group1”. This is a welcome change, as it has been historically difficult to find other DAGs for a specific Group.

The bad news, however, is that the GL Widget itself does not seem accessible anymore, so for functions that relied on grabbing the buffer from it, so far I’ve had no luck finding an alternative. I’ll be reaching to support to see if any is available.

Extra tips from Simon Jokuschies

Simon Jokuschies, maker of Cragl tools for Nuke, has commented these tips on LinkedIn:

1) To make the maintenance simpler I would suggest putting all PySide imports into one module and reference these just from that module. With that middle man you reduce coupling to one binding.

2) Funny thing: QAction was originally in PySide. located in QtGui. In PySide2 it was moved to QtWidgets. And now in PySide6 it’s back in QtGui. What the heck 😀

3) QtGui.QPixmap.fromImage does no longer accept an image path as string but only a QtGui.QImage

4) Getting the screen size changed because QDesktopWidget is no longer available:

# PySide2
from PySide2 import QtWidgets
resolution = QtWidgets.QDesktopWidget().screenGeometry()

# PySide6
from PySide6.QtGui import QGuiApplication
resolution = QGuiApplication.instance().primaryScreen().size()

5) Moving windows to the center of the screen does only seem to work sufficiently when showing it and then moving it with a small delay. e.g. using QtCore.QTimer.singleShot.

6) Playing sounds changed also a little. QtMultimedia has no QSound anymore. You will need QMediaPlayer and QAudioOutput

Updating Your Tools

Many popular Nukepedia and GitHub scripts will need updating to work with Nuke 16. If you maintain a tool, it’s a good idea to check for compatibility now.

Updated Tools

I’ll maintain a list of tools I (and others) have updated for Nuke 16 here:

  • shortcuteditor-nuke – Ben Dickson’s Shortcut Editor for Nuke.
  • nuke_nodegraph_utils – My Node Graph utils, using Qt.py for cross-version compatibility.
  • tabtabtab-nuke – Another one of Ben Dickson’s tools. The most up to date fork is maintained by Charles Taylor, and has Nuke 16 support.
  • nuke_dag_capture – A tool I made in the past to allow doing a screenshot of your entire node graph and export it as a PNG. Nuke 16 support is a bit dodgy for now, but it works. Hoping to improve the implementation once I hear from Foundry about the OpenGl implementation.

(If you’ve updated a Nuke tool for PySide6 and want it listed here, let me know!)

Conclusion

While PySide6 brings improvements like better performance and modern Qt support, the transition isn’t seamless for existing Nuke scripts. If your tools rely on PySide2, shiboken2, or the DAG widget, now is the time to update them.

If you run into issues or find new quirks, share them in the comments! I’m planning to update this page with other quirks I find as I convert more tool in the upcoming months.