With Mari 8 going onto the latest VFX Ref Platform, its QT requirements change - namely an update from PySide2 to PySide6.
Unfortunately this update can have rather major implications to any code written for Mari.
With Extension Pack being one of the largest Mari Code bases in the world, below I will give some informal hints what to look out for.
The first relatively easy step is to change the actual module imports to use PySide6. So for example what was
from PySide2 import QtGuineeds to become
from PySide6 import QtGuiThere are some caveats as some modules have moved. Some examples:
| PySide 2 | PySide 6 |
| QtWidgets.QAction | QtGui.QAction |
| QtWidgets.QShortcut | QtGui.QShortcut |
| QtWidgets.QOpenGlWidget | QtOpenGLWidgets.QOpenGLWidget |
You can use a tool called pysideup to handle these changes
pip install pysideuppysideup your_project_folderAs any import error usually shows up right on Mari Launch, I ended up doing it manually instead, first doing a PySide2->PySide6 Search and Replace and then fixing any remaining Import Errors that got introduced by moved modules
Let's say you used a Qt Layout Alignment before
Qt.AlignCenter
that would be an enum (not a function() ) invoking a specific behavior. There are a lot of these in QT.
AlignCenter actually even in PySide2 never lived under Qt. It always lived under
Qt.AlignmentFlag.AlignCenter
but the way PySide2 inherited themto the top classes it was accessible from the base level ..
so you could write Qt.AlignCenter and it would correctly inherit from Qt.AlignmentFlag.AlignCenter.
This is now no longer the case. Enums will not be inherited by classes.
That means you will have to check every single Qt Enum that was accessed from the top class and set it correctly
Qt.AlignCenter -> Qt.AlignmentFlag.AlignCenter
There is a tool
pip install pyside-migrate
pyside-migrate [your_project_folder]
it does an ok job at converting many occurrences, but equally misses as many, so code will still need to be thoroughly checked.
Often times in your IDE you can see the typing throwing warnings about non-existent enums anymore.
So make sure to have a Python Interpreter with PySide6 active in your Code Editor so you can more easily spot the warnings.
While pyside-migrate catches some obvious occurrences, there are sometimes "hidden" uses of enums that aren't quite as obvious.
Let's say you subclassed a widget
class MyGraphicsItem(QtWidgets.QGraphicsItem)
Inside you then call the enum of QGraphicsItem, but since you instanced it you call it as "self".
self.setFlags(self.flags() & ~self.ItemIsFocusable)
This is now no longer possible in PySide 6. Instead you need to call the original Class Enum
self.setFlags(self.flags() & ~QGraphicsItem.GraphicsItemFlag.ItemIsFocusable)
As cases of these are not always immediately obvious, this is unfortunately a very tedious job (yes, I tried multiple AI analysis - it tends to miss a bunch still)
Some enums also have flat-out moved into subclasses. For example I was reasonably sure that for message boxes there previously wasn't a icon class. But now there is ..
PySide2
QtWidgets.QMessageBox.Critical
PySdie6
QtWidgets.QMessageBox.Icon.Critical
Mari Enums are equally affected by the class inheritance changes - and there's no tool to auto fix it.
So for example
mari.Image.DEFAULT_OPTIONS
needs to become
mari.Image.SaveOptions.DEFAULT_OPTIONS
To help with identifying the Mari enums, I generated a full list of Python Stubs for Mari 8. This way you can at least see the warnings about non-existent enums. You can find them here on GitHub
As with QT Enums, the trouble starts in cases like this where you reassigned the original class to a variable and access the enums from there
PySide2
channel = mari.current.channel()
ocio_config = channel.colorSpaceConfig()
ocio_config.setColorspace(ocio_config.COLORSPACE_STAGE_NATIVE,'raw')
in the above case the code needs to change to
PySide6
channel = mari.current.channel()
ocio_config = channel.colorSpaceConfig()
ocio_config.setColorspace(mari.ColorspaceConfig.ColorspaceStage.COLORSPACE_STAGE_NATIVE,'raw')
Due to the sometimes very hidden nature of these assignments, I found it best to identify ALL fully uppercase words inside the codebase and go through them one by one
to fix them.
A small complication of this, is when the same Enum Name exists in multiple places e.g. the enum
DEPTH_FLOAT
can exist as
mari.Image.Depth.DEPTH_FLOAT
mari.PaintBuffer.BufferDepth.DEPTH_FLOAT
mari.Projector.BitDepth.DEPTH_FLOAT
in these cases you will have to be mindful of the context the enum is used (Image, Buffer, Projector) and set the correct one
There are a few edge cases where literal Mari enums have completely disappeared. Nearrly 100% of all cases I've seen so far involve the use of mari.resources. E.g. before in order to access the
Mari Icon Path you would do
mari.resources.path(mari.resources.ICONS)
the literal "ICONS" no longer exists. Instead you need to call the function returning the string:
mari.ResourceInfo.iconPathKey()
Especially for the Enum Changes for Mari and PySide 6 using Linters in your Code Editor will help you spot issues.
For Mari API you can use the dedicated Python
Stubs (ensure you are using Mari 8+ stubs !).
You still have to check every file but at least this way you can actually find them relatively easy

Mouse events like "event.pos()" previously returned a integer but now return a float. This is an easy fix usually as you can go back to the original via
event.pos().toPoint()
Some functions like "globalPos()" also are affected by this change and return a float by default now (and can be converted back to point using toPoint()).
Speaking of Mouse things, wheel evaluation has also changed. Mouse Wheel
event.delta()
no longer exists and needs to be replaced with
event.angleDelta().y()
The module QRegExp has been replaced by QRegularExpression.
The new module has a different set of functions so in general you won't be able to simply convert QRegExp to the new ones, requiring quite some rewrites to get the same result
QtWidgets.qApp()
has been removed. You can usually use QtWidgets. QApplication instead
In PySide2 you could set font weights via integers
font.setWeight(75)
this is no longer supported. Instead PySide6 exposes different enums for different weights. The above weight 75 corresponds to
font.setWeight(QFont.Weight.Bold)
There are multiple behavior changes to QImages and their Alphas.
There is no direct function anymore to retrieve an alpha channel so
image.alphaChannel()
..simply doesn't exist anymore
In addition QImage Alpha Channels are handling image processing operations very differently now when working with image formats like PNG where you can save transparency without an explicit Alpha
channel
While QPixmaps seem to stick to their old PySide 2 behavior, doing pixel processing on a PNG with transparency breaks the transparency and instead shows the native color (black/white) in those
areas.
An example of this is the following in my code base:
The fix for me was to go through a pixmap first which seemed to maintain it
original_pixmap = QPixmap(path)
original_image = original_pixmap.toImage().convertToFormat(QImage.Format.Format_ARGB32)
as there's no more easy way to "store" the original alpha channel (no more image.alphaChannel() ) this approach seemed the least work