Visual Python Error Reporting

3d pipeline application development for a studio seems very much like developing and maintaining web services for a website. You have a large user base and you do not expect those users to be very technically inclined. Animators are, after all, necessarily more interested in creating interesting performances than the somewhat obscure minutiae of node graphs and connection types. This is not to say there are not technical animators out there – there are many very good ones, to be sure. A large studio, tho, invests some time and money in providing more technical support to maximize animator performance time and minimize cursing time. We have, as yet, no solution to minimize animator drinking time, however.

The tricky part is that modern 3d application software provides almost too many options for the non or semi technical to cause mischief. The design and implementation of animation tools is a constant battle to anticipate an infinite number of states an artist’s animation scene can be in.

So when, in the course of human events, it becomes necessary for animation tools to fail, it would be optimal if they were to fail in a useful way. Many artistic types pay no attention to the red-flash of the status bar familiar to many TDs (if they even have it displayed), and the Script Editor is as foreign as Chrome’s developer console.

Fortunately, if you’re using Python, you have some tools available to help with better error reporting. A clear winner in this area is the decorator. Python decorators wrap functions and re-bind them in the Python interpreter, allowing the re-use of code with minimal intrusion. One practical application of this is a decorator that can provide useful information about an Exception.


from functools import wraps

def displayException(f):
    # copy function info to decorator
    @wraps(f)
    def _wrapped(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception,e:
            # try to import PySide - if you can't, bail            
            try:
                from PySide import QtGui
                # check to see if the application is running - if not,
                # don't launch ui
                if QtGui.QApplication.instance():
                    tmp = QtGui.QMessageBox.critical(None, 'Python Exception', str(e))
            except ImportError,e:
                pass
                
            # allow the exception to propogate up
            raise
    return _wrapped

Now you can use this to wrap any function you have and, if it fails, it will at least it will present a error dialog to the user. I recommend using it at only at your higher-level entry point functions. If you use this in lower-level loops, you run the risk of popping up hundreds of these.


@displayException
def myMainFunction():
    """This does some big operation - like building a rig or publishing a
    file
    """
    pass

This code uses functools.wraps to update the returned decorator with the function’s doc string and other attributes. Also, I check to see if PySide can even be imported – my use case for this would be Maya, but this will work in any Python code where PySide may or may not be available. Also, the code checks to see if the QApplication is running – this is good practice, as launching a UI when Maya is running in batch mode could be a bad idea.

Advertisements
Visual Python Error Reporting