QtPy

QtPy in Nuke: What It Is and How to Install It

One Python interface for PySide6, PySide2, PyQt6 and PyQt5, and why QtPy is not Qt.py

QtPy lets you write a Python interface once and run it with any of the Qt libraries for Python: PySide6, PySide2, PyQt6 or PyQt5. In VFX that matters, because every version of Nuke, Maya and Houdini ships a different one, and Nuke 16 moved from PySide2 to PySide6. This page explains what QtPy is, how it differs from Qt.py (a different library with almost the same name), whether you need it in Nuke, and how to install it.



Index



01. What is QtPy

Qt is the C++ toolkit used to build the interface of Nuke, Maya, Houdini and many other programs. To use it from Python you need a binding, and there are four: PySide6 and PySide2 (made by the Qt company) and PyQt6 and PyQt5 (made by Riverbank). They do almost the same things, but the names of some modules and functions differ.

QtPy is a small layer on top of them: you write from qtpy import QtWidgets, and QtPy loads whichever binding is installed. Your tool doesn't need to know if it runs on PySide6 or PySide2. It's an open-source project of the Spyder team (MIT licence); the current version on PyPI is 2.4.3, and it supports PyQt5, PyQt6, PySide2 and PySide6.



02. QtPy or Qt.py? Two different libraries

This confuses almost everyone, me included the first time. They have the same goal and almost the same name, but they are two separate projects:

QtPyQt.py
install withpip install QtPypip install Qt.py, or copy one file
importfrom qtpy import QtWidgetsfrom Qt import QtWidgets
made bythe Spyder projectMarcus Ottosson and the VFX community
forma package (a folder)a single file, Qt.py
bindingsPySide6, PySide2, PyQt6, PyQt5PySide6, PySide2, PyQt6, PyQt5
where you meet itscientific and general Python toolsVFX pipelines and tools for Nuke, Maya, Houdini

Both work in Nuke. If you start from scratch for VFX tools, Qt.py is the one you'll see most in studio code; my older page Custom Panel in QtPy uses Qt.py. If a tool asks for qtpy (lowercase), it means QtPy, the package of this page.



03. Do you need it in Nuke?

Not always. Nuke ships its own binding: PySide2 up to Nuke 15 and PySide6 from Nuke 16 (Nuke 17, which I used for this page, has PySide6 with Qt 6.5).

  • Your tool runs only in Nuke 16 or later? Import PySide6 directly, no wrapper needed.
  • It must run in Nuke 15 and 16, or also in Maya and Houdini? Use QtPy or Qt.py, or the small try/except below.
  • You use a tool that needs it? Install it once, as in the next section.
try:
    from PySide6 import QtWidgets, QtCore, QtGui
except ImportError:
    from PySide2 import QtWidgets, QtCore, QtGui

I ran this in Nuke 17: it loads PySide6. If an old tool stops with No module named 'PySide2' in Nuke 16, read my page No module named 'PySide2' in Nuke 16+.



04. How to install QtPy for Nuke

Nuke has its own Python, and it doesn't see the packages of the Python installed on your system. The cleanest way is to install QtPy in a folder inside your .nuke folder and tell Nuke to look there. QtPy is pure Python, so it works on Windows, macOS and Linux.

1. Install it into a folder of your .nuke

Nuke comes with its own python.exe, with pip included (Nuke 17 has pip 24). Open a terminal and run, changing the version of Nuke and your user name:

"C:\Program Files\Nuke17.0v1\python.exe" -m pip install QtPy --target "C:\Users\you\.nuke\python"

pip also installs packaging, a small library QtPy needs: Nuke 17 doesn't include it, and without it you get No module named 'packaging'. I installed QtPy 2.4.3 exactly like this with the pip of Nuke 17, and in Nuke 17 qtpy.API_NAME is PySide6, with Qt 6.5.3. On macOS and Linux use the same command with the Python inside your Nuke installation, or any Python 3 you have: QtPy and packaging have no compiled parts, so the folder works in every version of Nuke 13 or later. If you copy the files by hand, copy both folders, qtpy and packaging.

2. Tell Nuke where to find it

Add one line to the init.py in your .nuke folder (create the file if it doesn't exist):

nuke.pluginAddPath('./python')

The path is relative to the .nuke folder. nuke.pluginAddPath() adds the folder to the places where Python looks for modules: I checked in Nuke 17 that a package in that folder imports correctly. Restart Nuke.

Qt.py instead?

The same two steps: pip install Qt.py --target ..., or simply copy the single file Qt.py into .nuke/python: it has no dependencies. I tested Qt.py 2.0.7 in Nuke 17 too: Qt.__binding__ is PySide6. pip also adds some type-hint folders (Qt-stubs, PySide6-stubs): they are only for code editors and you can ignore them.



05. First test and a small window

In the Script Editor, check which binding QtPy found:

import qtpy
print(qtpy.API_NAME, qtpy.QT_VERSION)

A small window that lists the selected nodes, written once for every version of Nuke:

import nuke
from qtpy import QtWidgets

class NodeList(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle('Selected nodes')
        layout = QtWidgets.QVBoxLayout(self)
        self.list = QtWidgets.QListWidget()
        button = QtWidgets.QPushButton('Refresh')
        button.clicked.connect(self.refresh)
        layout.addWidget(self.list)
        layout.addWidget(button)
        self.refresh()

    def refresh(self):
        self.list.clear()
        for node in nuke.selectedNodes():
            self.list.addItem(node.name() + '  (' + node.Class() + ')')

window = NodeList(QtWidgets.QApplication.activeWindow())
window.show()

I ran this window with QtPy and PySide6 6.5.3, the version inside Nuke 17: it opens with the title "Selected nodes" and lists the selected nodes. Passing Nuke's window as parent keeps your window on top of Nuke and closes it with Nuke. For panels that dock in Nuke's interface, see Custom Panel in QtPy.



06. Common errors

  • ModuleNotFoundError: No module named 'qtpy': Nuke doesn't see the folder. Check the line in init.py, the folder name and that you restarted Nuke.
  • No module named 'packaging': you copied the qtpy folder without the packaging folder. Install with pip, or copy both.
  • QtBindingsNotFoundError: No Qt bindings could be found: QtPy found no binding. I got it running the same code with the python.exe of Nuke outside Nuke: PySide6 is only visible from inside Nuke.
  • No module named 'PySide2' in Nuke 16 or 17: the tool imports PySide2 directly. Change the import to qtpy, or to the try/except above.
  • The tool works in one version of Nuke and not in another: probably a function that changed between Qt5 and Qt6 (for example exec_() became exec()). QtPy and Qt.py fix many of these differences, not all.


Questions about this tutorial?

Write me directly: I read every message. You can also find me on LinkedIn.