Search code examples
pythonmaya

Access and modify Maya undo queues


are there any ways in which I could access/ edit the undo queue?

The reason I asked is because, in my current tooling, I created the following in one of my renaming function (where you double click on the QListWidgetItem, input in a new name and cmds.rename will be using the new input name):

cmds.undoInfo(chunkName='renameChunk', openChunk=True)
# do cmds.rename operations
cmds.undoInfo(chunkName='renameChunk', closeChunk=True)

However, if I am trying to do an undo function (ctrl+z) to revert back the naming, I need to hit the key combination a couple of times instead of the expected 1 time. And while printing out the undo queue, I noticed that there are a lot of 'blank' entries which could be the cause of the multiple undos.

...
# 39:  # 
# 40:  # 
# 41:  # 
# 42:  # 
# 43: renameChunk # 
# 44:  # 
# 45:  # 
# 46:  # 
# 47:  # 
# 48:  # 
# 49:  #

Solution

  • I'm going to supply an answer since what you're doing is a bit risky. Right now you're assuming cmds.undoInfo(chunkName='renameChunk', closeChunk=True) WILL run, though if an error occurs in-between the line will never be executed and you will be left with an open undo chunk.

    A safer approach would be to open an undo chunk, then wrap your code in a try finally. This way no matter what happens you can be assured that the chunk will close in the finally block:

    cmds.undoInfo(chunkName='renameChunk', openChunk=True)
    try:
        raise RuntimeError("Oops!")
    finally:
        cmds.undoInfo(closeChunk=True)  # This will still execute.
    

    Alternatively you can be a bit more fancier and create your own undo class and utilize its __enter__ and __exit__ special methods:

    class UndoStack(object):
    
        def __init__(self, name="actionName"):
            self.name = name
    
        def __enter__(self):
            cmds.undoInfo(openChunk=True, chunkName=self.name, infinity=True)
    
        def __exit__(self, typ, val, tb):
            cmds.undoInfo(closeChunk=True)
    
    with UndoStack("renameChunk"):  # Opens undo chunk.
        raise RunTimeError("Oops!")  # Fails
    # At this point 'with' ends and will auto-close the undo chunk.
    

    As long as you do it this way you shouldn't have all these blank undo calls (at least I don't!). Though do try to keep it compact, so open up an undo chunk, do the work, then immediately close it. Avoid straying off to do other stuff like managing your gui or something.