Search code examples
pythonmayaqt-signalspyside2

Why do my errors from pyqt signals freeze the ui until another python function gets called


In Maya 2016 everything is fine. But in Maya 2017 (after I did all the pyqt conversions), any Error happening in a function called from a qt signal doesn't get shown immediately. Then if I run another code in the script editor, such as "print 0", the error from the previous function comes up

To try it out, simply run the code, and click the button "error".

I tried it on Windows and Mac. Also asked a friend to try on his - and he had same issue. Again, on Maya 2016 it's all fine. The issue is only happening in Maya 2017

from PySide2 import QtWidgets, QtGui, QtCore
from shiboken2 import wrapInstance
import maya.OpenMayaUI as mui


mainWin = None

def showUI():
    global mainWin
    if mainWin != None:
        print "reloading UI..."
        mainWin.close()
    mainWin = myWindow()
    mainWin.show()


def getMayaWindow():
    ptr = mui.MQtUtil.mainWindow()
    return wrapInstance(long(ptr), QtWidgets.QWidget)


class myWindow(QtWidgets.QDialog):

    def __init__(self, parent=getMayaWindow()):

        super(myWindow, self).__init__(parent, QtCore.Qt.WindowStaysOnTopHint)

        def funcApply():
            oooo # this should error!

        self.layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.TopToBottom, self)
        self.testButton = QtWidgets.QPushButton('error')
        self.layout.addWidget(self.testButton)
        self.testButton.clicked.connect(funcApply)

showUI()

Solution

  • Like I said in the comments, I can replicate your bug in 2017 and 2017 update 2, but works perfectly fine in 2018.

    Luckily there's an easy enough solution where you just need to move your method out of the __init__ to make it a normal instance method. Doing this now errors as expected. (Honestly having a nested function inside __init__ is a bit weird anyhow, I'd move it regardless if it was buggy)

    Interesting enough, static methods have the same issue! If you try to call them from inside your class, they'll hang. But if you call it from outside the class it works ok, or if you wrap it all with a try except it will now work when being called from inside the class.

    Check out the following code. I included 3 cases, an instanced method, a static method, and a static method wrapped with a try except:

    from PySide2 import QtWidgets, QtGui, QtCore
    from shiboken2 import wrapInstance
    import maya.OpenMayaUI as mui
    
    
    mainWin = None
    
    
    def showUI():
        global mainWin
        if mainWin != None:
            print "reloading UI..."
            mainWin.close()
        mainWin = myWindow()
        mainWin.show()
    
    
    def getMayaWindow():
        ptr = mui.MQtUtil.mainWindow()
        return wrapInstance(long(ptr), QtWidgets.QWidget)
    
    
    class myWindow(QtWidgets.QDialog):
    
        def __init__(self, parent=getMayaWindow()):
    
            super(myWindow, self).__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
    
            # Works.
            self.testButton = QtWidgets.QPushButton('error')
            self.testButton.clicked.connect(self.funcApply)
    
            # Fails.
            self.testButton2 = QtWidgets.QPushButton('error static method')
            self.testButton2.clicked.connect(self.staticFuncApply)
    
            # Works.
            self.testButton3 = QtWidgets.QPushButton('error static method with try/except')
            self.testButton3.clicked.connect(self.staticTryExceptFuncApply)
    
            self.layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.TopToBottom, self)
            self.layout.addWidget(self.testButton)
            self.layout.addWidget(self.testButton2)
            self.layout.addWidget(self.testButton3)
            self.setLayout(self.layout)  # Normally need to specify what layout this widget needs to use.
    
        # Move this out and make it a normal instanced method.
        # This will work as expected.
        def funcApply(self):
            oooo # this should error!
    
        # Static methods still broken, but ok in Maya 2018.
        @staticmethod
        def staticFuncApply():
            oooo
    
        # Static methods wrapped with try except works.
        @staticmethod
        def staticTryExceptFuncApply():
            try:
                oooo
            except Exception as e:
                print e
    
    
    showUI()
    
    # myWindow.staticFuncApply()  # Calling static method outside of class works ok.
    

    All of these work in Maya 2018, but the static method will fail on 2017. Hopefully you can avoid using static methods, as wrapping it all in a try except is not a practical solution. You can also try to update your Maya to 2017 update 4 to see if it's patched up.

    Hope this helps!