Quantcast
Channel: mel wiki
Viewing all articles
Browse latest Browse all 610

Batching Maya Files via Python

$
0
0
This subject is about batching Maya files in a session of Maya other than the one that is currently open, via Python. It's one thing to (via the currently opened Maya) loop over a list of files opening them in succession and executing code. But if you want to launch external Maya's in batch mode (so as to not disturb your current Maya session), open a file, and execute code on that file (all in Python), it's a different story.

To batch file via Maya with mel, it's pretty straightforward via maya.exe:
> maya -batch -file someMayaFile.ma -command someMelProc
There is mayapy.exe as well, but this doesn't launch Maya: It launches Maya's version of Python. It is a Maya mirror of python.exe. However, once it has been launched, Maya itself can be imported in as a Python module, and then batching can take place. Method A explains this below.


Different methods below. I came up with Method C first, got suggested Method B, then sort of combined the two to come up with Method A.

Method A

The example below will batch over all the passed in Maya files, and saves a new group node in them as proof it worked. Some of the magic is using subprocess.call to call to mayapy.exe, and passing in an additional argument that is the name of the current file to work on. Another bit of trickery is having the module do double-duty: When executed in GUI Maya the user runs its main() function to start it up, but when it is called to via mayapy.exe putting it in 'batch mode', the top & bottom section 'if __name__ == "__main__":' are executed as well which both imports maya.standalone (thus now physically has Maya running inside of mayapy.exe) and calls to the batchOperation() function, which can then query, via sys.argv the command-line arguments passed in (which are the names of the files to batch over). I have a feeling that's not terribly clear. I hope the code makes more sense ;)

I'll label each thing has it's executed so you can see the data flow.
GUI mode starts with GUI A and ends with GUI D, which then starts BATCH A and ends with BATCH E.
# batchTest.py
import subprocess

if __name__ == "__main__":
    # If we're in 'batch' mode, it means that mayapy.exe is running,
    # so load maya.standalone into it:
    import maya.standalone
    maya.standalone.initialize(name='python')
    # If you have a userSetup.py that is needed for happy Maya execution, call
    # to it here:
    import userSetup
    userSetup.main()

import maya.cmds as mc

def main(paths):
    """
    Launched in the gui version of Maya, manually, or via some other script.

    Parameters :
    paths : string\list : Path(s) to Maya files to batch over.
    """
    if not isinstance(paths, list):
        paths = [paths]
    args = ['mayapy', __file__, '-']
    args.extend(paths)
    # This fires off another version of Maya in 'batch' mode, calling back to
    # this code, executing the 'batch only' parts.  Luckily, the current version
    # of Maya calling it waits for the other version to complete doing it's thing
    # before continuing on in this code...
    subprocess.call(args)

def batchOperation():
    """
    The work done by the batch:  This has been called to while Maya is in batch
    mode, via the subprocess.call() func in the main() function:  Because of this,
    we capture the incoming args via sys.argv.
    A single instance of Maya is launched, and then all the files are batched over
    in that instance, and processed
    """
    # The sys.argv vals match the subprocess call above
    # sys.argv[0] : The path to this module ( __file__ )
    # sys.argv[1] : '-'
    # sys.argv[2] + : Path(s) to the files to batch over
    paths = sys.argv[2:]

    # If there is an error, the shell will just disappear.  So we wrap it in a
    # try\except, allowing it to stay open to help track down bugs.
    try:
        mc.file(prompt=False)
        for fil in paths:
            mc.file(fil, force=True, open=True)
            mc.group(empty=True, name='I_was_made_in_batch_mode', world=True)
            mc.file(force=True, save=True)
    except Exception, e:
        print "Exception:", e
        raw_input("Encountered an exception, see above.  Press Enter to exit...")
    finally:
        mc.file(prompt=True)

# When called to via batch mode, run this code.  This line must come after the
# function it's calling.
if __name__ == "__main__":
    batchOperation()
To run in Maya:
import batchTest
batchTest.main(['c:/temp/myFileA.ma', 'c:/temp/myFileB.ma'])
You should see a shell pop up for the new instance of Maya that is launched (via mayapy.exe), and then each path is opened and batch processed in that shell. The gui version of Maya will wait until completion of the batch to continue on with its code.

Method B:

This (modified) example was given to me by Keir Rice. Thanks Keir!

Make a batch script: batchTest.bat . It runs mayapy.exe, which is Maya's version of Python.
REM Launcher batch file: batchTest.bat
"%ProgramFiles%\Autodesk\Maya2010\bin\mayapy.exe""c:\temp\test.py"
pause
  • Add pause to the end of the batch script if you want the shell to stay open upon completion.
Note that if mayapy is part of your Windows path, you can leave off the directory before it, and the .exe on the end of it.

Then make the python module it calls to:
# python script to run: c:\temp\test.py
import maya.cmds

def TestFunction():
    print maya.cmds.about(version=True)

if __name__ == "__main__":
    # Init Maya:
    import maya.standalone
    maya.standalone.initialize(name='python')
    # If you have one:
    import userSetup
    userSetup.main()

    # Run your code:
    TestFunction()
Finally, run the bat script. Results should be printed in the shell.

Method C:

This is one I came up with before I knew about Method A or B, above.
Key Components: (the file-names aren't important, just illustrating the example)
  • mainModule.py : This is the Python module that orchestrates the whole thing. It can be executed from Maya, or the command line.
  • melScript.mel : This is a 'wrapper' script that our batch operation will call to. It in turn, via the mel python command, will execute the Python code we want to have effect the scene files.
  • pythonModule.py : This is the Python module that our mel script calls to. In this example, it executes the main() function inside.

Here is a bit of code from mainModule.py. By calling to subprocess.call(), we're able to launch Maya in batch mode on a specific file, executing our wrapper mel command on it:
http://docs.python.org/library/subprocess.html
# mainModule.py
import subprocess
subprocess.call(['maya', '-batch', '-file', 'c:\\myFile.ma', '-command', 'melScript'])

This is the guts of our wrapper mel script. All it does is call to the Python code we care about:
// melScript.mel

global proc melScript(){
    python("import pythonModule");
    python("pythonModule.main()");
}

pythonModule.py and its main() function can prettymuch do whatever you'd like to that scene file:
# pythonModule.py
import maya.cmds as mc

def main():
    # do stuff!

Viewing all articles
Browse latest Browse all 610

Trending Articles