[PyMEL] How to undo an entire function call?

With PyMEL, how does one undo the execution of a single function call?

Say I have a function that creates a bunch of nodes, manipulates them, then returns some data. I want to undo the call, and undo all the stuff that happened inside that call. In a MEL proc, this is handled for you. In PyMEL, it appears that every aspect of the function call is undone step by step.

Looking for advice on how you guys handle that sort of thing. Sorry if this seems remedial - I haven’t found much info on the matter using my searching foo.

-csa

MEL, python, and PyMEL all undo only a single command at a time, I think. If any commands are wrapped into a function which contains many commands, pressing or calling undo after the function has been called probably won’t undo anything. Or are you saying that if you define a proc in MEL and call the proc and then press CTRL-Z that the entire proc gets undone?

Take a look at the openChunk and closeChunk options. They let you set a point at which all operations inside the “chunk” can be undone at once.

http://download.autodesk.com/us/maya/2010help/CommandsPython/undoInfo.html

some more advice on undoChunks, like wrapping things in a try:except:

The good news is that I whipped up a simple test case, and the undo works as expected. IE:

MEL


global proc doStuff()
{
    string $loc[] = `spaceLocator -n "myLocator1"`;
    xform -ws -t 0 0 1 $loc[0];
    
    string $loc[] = `spaceLocator -n "myLocator2"`;
    xform -ws -t 0 0 2 $loc[0];    

    string $loc[] = `spaceLocator -n "myLocator3"`;
    xform -ws -t 0 0 3 $loc[0];    
}

doStuff();

PyMEL



import pymel.core as pm

def doStuffInPyMEL():
    loc = pm.spaceLocator(name='myLocator1')
    pm.xform(loc, ws=True, t=(0,0,1))
    
    loc = pm.spaceLocator(name='myLocator2')
    pm.xform(loc, ws=True, t=(0,0,2))
    
    loc = pm.spaceLocator(name='myLocator3')
    pm.xform(loc, ws=True, t=(0,0,3))
    
doStuffInPyMEL()

That being said… I invested my code even further, and discovered that I cannot seem to be able to undo the following code, executed in a brand new file:


import pymel.core as pm

pm.system.newFile( force=True )
pm.surface( du=1, dv=1, ku=(0, 1), kv=(0, 1), p=( (-1, 1, 0), (-1, -1, 0), (1, 1, 0), (1, -1, 0)))

Any ideas here? Even the example code in the pymel.core.surface documentation seem to fail undo. My expectation is to undo the creation of the nurbs plane back to a blank file.

-csa

Here’s the same problem wrapped in a try/except. I still get the same problems…

PyMEL:


import pymel.core as pm
import maya.cmds as cmds

pm.system.newFile( force=True )

pm.flushUndo()
try:
    pm.undo()
except:
    print "
Move along, there is nothing to undo here!"
    
pm.undoInfo(openChunk=True)
try:
    pm.surface( du=1,
                dv=1,
                ku=(0, 1),
                kv=(0, 1),
                p=( (-1, 1, 0),
                    (-1, -1, 0),
                    (1, 1, 0),
                    (1, -1, 0))
                  )
    pm.spaceLocator( name='whatever' )
finally:
    pm.undoInfo(closeChunk=True)

pm.undo()

Looks like a potential bug… I cannot undo the creation of a nurbsPlane created via MEL nor maya.cmds either:

MEL:


file -f -new;
flushUndo;
surface -du 1 -dv 1 -ku 0 -ku 1 -kv 0 -kv 1 -p -1 1 0 -p -1 -1 0 -p 1 1 0 -p 1 -1 0;
undo;

maya.cmds:


import maya.cmds as cmds
cmds.file( force=True, new=True )
cmds.flushUndo()
try:
    cmds.undo()
except:
    print "
Move along, there is nothing to undo here!"
    
cmds.surface( du=1, dv=1, ku=(0, 1), kv=(0, 1), p=((-1, 1, 0), (-1, -1, 0), (1, 1, 0), (1, -1, 0)))
cmds.undo()

yup same here(maya 2012, win64), surface can’t be undone. How odd.

FYI

On the 14/02/2012 a UndoChunk context manager was added to PyMel by Paul Molodowitch.

docstring here

class UndoChunk(object):
‘’'Context manager for encapsulating code in a single undo.

Use in a with statement
Wrapper for cmds.undoInfo(openChunk=1)/cmds.undoInfo(closeChunk=1)

>>> import pymel.core as pm
>>> pm.ls("MyNode*", type='transform')
[]
>>> with pm.UndoChunk():
...     res = pm.createNode('transform', name="MyNode1")
...     res = pm.createNode('transform', name="MyNode2")
...     res = pm.createNode('transform', name="MyNode3")
>>> pm.ls("MyNode*", type='transform')
[nt.Transform(u'MyNode1'), nt.Transform(u'MyNode2'), nt.Transform(u'MyNode3')]
>>> pm.undo() # Due to the undo chunk, all three are undone at once
>>> pm.ls("MyNode*", type='transform')
[]
'''

-Dave