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 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"
- Add
pause
to the end of the batch script if you want the shell to stay open upon completion.
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__":
import maya.standalone
maya.standalone.initialize(name='python')
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!