Putting Maya back to it’s start up state, for Python’s sake

The node editor project is beginning to become bigger and bigger. Where I was first just handling basically everything in a giant nv_Node.py file, I realized that this was becoming a major ball ache while working. So I started to split everything up in their own nice little modules, which introduced me to the error message of hell:

super(type, obj): obj must be an instance or subtype of type

Which I got basically every time I needed to reload part of the project, but never when it was launched for the first time. I’m not going to pretend to fully understand how Python’s module importing works exactly and I’m also sure I have some bad programming designs in my code as well. But since I wanted to continue with this project over the holidays without a complete re-write, I went looking for another solution.

Luckily I happened upon this post by Nick Rodgers: https://medium.com/@nicholasRodgers/sidestepping-pythons-reload-function-without-restarting-maya-2448bab9476e His solution is pretty smart and saves so much time when you’re editing files all over the place. It deletes the previous imports so they’ll get imported freshly every time. Just posting it here in case I’ll need it again and can’t find the post anymore.

import inspect
from os.path import dirname
import sys

# I'm going to define this little function to make this cleaner
# It's going to have a flag to let you specify the userPath you want to clear out
# But otherwise I'd going to assume that it's the userPath you're running the script from (__file__)
def resetSessionForScript(userPath=None):
    if userPath is None:
        userPath = dirname(__file__)
    # Convert this to lower just for a clean comparison later
    userPath = userPath.lower()

    print userPath

    toDelete = []
    # Iterate over all the modules that are currently loaded
    for key, module in sys.modules.iteritems():
        # There's a few modules that are going to complain if you try to query them
        # so I've popped this into a try/except to keep it safe
            # Use the "inspect" library to get the moduleFilePath that the current module was loaded from
            moduleFilePath = inspect.getfile(module).lower()

            # Don't try and remove the startup script, that will break everything
            if moduleFilePath == __file__.lower():

            # If the module's filepath contains the userPath, add it to the list of modules to delete
            if moduleFilePath.startswith(userPath):
                print "Removing %s" % key

    # If we'd deleted the module in the loop above, it would have changed the size of the dictionary and
    # broken the loop. So now we go over the list we made and delete all the modules
    for module in toDelete:
        del (sys.modules[module])

Node Editor Part 2

Some updates on the ol’ node editor here:

  •  Added some nicer looking connections between the nodes
  • You can see the connection when you start dragging off a socket
  • Connections can be made from output to input and vice versa. The editor will always know the correct direction of the connection
  • Nodes can be destroyed properly
  • Destroying nodes also correctly destroys all the connections
  • Cool looking mouse-over events!

Node Editor part 1

A long time ago I started working on a QT node editor but got stuck fairly quickly. I found myself with some free time again today after not having to work on a game in the weekends anymore 🙂 So I went back to my old code and started tinkering a little bit. Got a bit more of the visual stuff working today. It doesn’t do anything yet, but I’m able to add nodes with inputs and outputs and connect everything together. Gotta start somewhere, right?


Somewhat “safer” way of making a PyNode

I always kept running into problems when making PyNodes in my script and the error messages Maya gives you aren’t always the best.  So I wrote a little helper function, especially useful when you have more than one object with the same name in your scene.

def pynode(object_name, specific_on_multiple=False, pick_most_root=False, pick_most_leaf=False, pick_index=None):
    Returns a PyNode of the given object name with better error messages and additional options

    :param object_name: name of the object you want to make a PyNode
    :param specific_on_multiple: <bool> When set to True, allows you set the next flags to return a specific object when there are multiple objects with the same name
    :param pick_most_root: <bool> returns the most root object if there are multiple objects with the same name
    :param pick_most_leaf: <bool> returns the most leaf object if there are multiple objects with the same name
    :param pick_index: <int> returns this index of object if there are multiple objects with the same name
    :return: a PyNode
    if object_name is None:
        raise RuntimeError("Can't make a PyNode when object_name type is None")
    if pm.objExists(object_name):
            return pm.PyNode(object_name)
            if not type(object_name) == str:
                node_name = object_name.nodeName()
                node_name = object_name
            multiple_nodes = sorted([str(node) for node in pm.ls(node_name)], key=len)

            if len(multiple_nodes) > 1:
                if specific_on_multiple is False:
                    error_message = "There are multiple nodes with this name:"
                    for node in multiple_nodes:
                        error_message += "\n%s" % node
                    raise RuntimeError(error_message)
                    if pick_most_root is True:
                        return pm.PyNode(multiple_nodes[0])
                    elif pick_most_leaf is True:
                        return pm.PyNode(multiple_nodes[-1])
                    elif pick_index is not None:
                            selected_node = multiple_nodes[pick_index]
                        except IndexError:
                            raise IndexError("%s is not a valid index, valid indices are 0 to %s"
                                             % (pick_index, len(multiple_nodes) - 1))
                        return pm.PyNode(selected_node)

                    raise ValueError("When custom_on_multiple is set to True, either pick_most_root or pick_most_leaf "
                                     "should be set to True as well")
        raise ValueError("Object (%s) doesn't exist" % object)

Skin Saver tool

I finally found the time to update my old skin saver tool. I’ve cleaned up the code a bit, added some extra functionality and just made it work a bit smoother than before. You can find it on my Gumroad page: https://gumroad.com/l/GskhZ