This chapter will cover everything you need to get the most out of the rest of the book, as well as give you a feel for the differences between MEL and Python, as follows:
Using the script editor to investigate functionality
Running code from the script editor
Importing Maya's built-in Python functionality
Accessing documentation for a specific command
Understanding Create, Query, and Edit flags
Adding custom folders to your script path
Writing and running an external script
Calling a MEL script with Python
In this chapter, we'll cover the basics of scripting with Maya and Python. If you've been scripting for Maya for a while, a lot of what's covered will likely be familiar. If you're new to Maya scripting, this chapter will get you set up with everything you'll need to know to get the most out of the rest of the book.
The script editor is your primary tool in order to learn about Maya's script-based functionality, as well as a great place to test small snippets of code outside a full script. One of the most useful aspects of the script editor is that it will show you the commands that correspond to the actions that you take within Maya's interface.
This is one of the best ways to learn about the commands involved in your day-to-day Maya tasks. For example, let's use it to find out how to make a polygonal cube with Maya Embedded Language (MEL):
Open the script editor by going to Windows | General Editors | Script Editor.
You'll likely note that there is a lot of text already displayed, even if you've only recently opened Maya. To make things easier to see, go to Edit | Clear History from within the Script Editor window's menu.
Now try making a polygon cube by holding down space to bring up the hotbox and going to Create | Polygon Primitives | Cube.
Use the interactive creation tool to specify the poly cube's dimensions.
Observe the output in the top half of the script editor. You should see something like the following:
setToolTo CreatePolyCubeCtx; polyCube -ch on -o on -w 5.502056 -h 3.41434 -d 7.451427 -sw 5 -sd 5 -cuv 4 ; // Result: pCube1 polyCube1 //
The output that Maya provides is presented as the MEL commands that correspond to the action that you've just taken. That can be a great way to find out which commands you'll need to use in your own scripts. In this case, it's the polyCube
command, which will create a polygonal cube. Every command in Maya comes in two flavors—the MEL version and the corresponding Python command.
The script editor shows you commands in MEL syntax, which tends to take the form of:
commandName -option1Name option1Value -option2Name option2Value;
The MEL syntax borrows a lot from batch scripting wherein it relies on strings of option names (generally referred to as "flags") and corresponding values. The corresponding Python command generally has the following syntax:
commandName(option1Name=option1Value, option1Name=option1Value)
As you can see, the MEL and Python versions are fairly similar, but with some key differences:
In the MEL version, flag names are indicated with a dash, and their values follow directly after, whereas in Python, options are given with the "optionName=value" syntax
Python encloses all the flags in parentheses, whereas MEL does not
MEL requires a semicolon (;) at the end of each line, whereas Python does not
Another big difference between MEL and Python is how they treat whitespace characters (spaces, tabs, and newlines). MEL, like most languages, doesn't care about whitespace; statements are terminated with semicolons, and blocks of code are defined with matched sets of curly brackets.
Python, however, uses whitespace characters to control program flow. This is often one of the strangest things about Python to people who are new to the language, but not to programming. In Python, blocks of code are defined by indentation. You can use either tabs or spaces, but the key thing is that you're consistent. In Python, every time you increase the number of tabs (or spaces) at the start of a line, it's equivalent to adding an opening curly bracket, and every time you decrease that number, it's equivalent to a closing curly bracket. This can often be confusing, as the structure of your program is defined by characters that may not actually be visible. If you're new to Python and having trouble keeping track of your whitespace, you might want to change your editor settings to display whitespace characters. Most programmer-friendly text editors include such an option, and it can be a big help.
The specific list of options for each command can be found in the built-in Python documentation, accessible from within Maya by going to Help | Python Command Reference. For most commands, you'll find a long list of options.
To make things even more complicated, every option has both a short name and a long name. For example, the polyCube allows you to specify the number of subdivisions along the X axis. You can use either the long name, "subdivisionsX" or the short name, "sx" to set it.
For example, all of the following will result in the creation of a 1x1x1 polygonal cube with five subdivisions along the X-axis.
The MEL versions are:
polyCube -sx 5; polyCube -subdivisionsX 5;
The Python versions are:
maya.cmds.polyCube(sx=5) maya.cmds.polyCube(subdivsionsX=5)
Feel free to use either the short or long version for your arguments. You can also mix and match, using short names for some arguments and long names for others.
In practice, it's generally best to use short names for common arguments (ones that you're likely to remember) and long names for more obscure / more rarely used arguments. Remember that just because your code seems completely sensible to you right now, it may look confusing when you revisit it 6 months (or 6 years!) from now. Make it easy for your future self by using long names (and including comments) when necessary.
You may be wondering why Maya offers two different methods for scripting, MEL and Python. That's a simple case of backwards compatibility. MEL came first and was available in Maya long before Python support was added. Back then, you had to use MEL for day-to-day tasks, and if that couldn't provide you with what you needed, you had to dive into the C++ API (which was quite involved and hard to work with on non-Windows systems). Python unites both approaches, but MEL is still supported to allow older scripts to work. It's also possible that you might get better performance with MEL than with Python, as the Python functionality is a wrapper around MEL. Python is a much nicer language to work with though, so it's generally a worthwhile trade-off.
Note that the script editor doesn't (by default) show you everything that you do. Under normal circumstances, Maya shows you a slightly filtered output based on what you are most likely to be interested in. This is usually a good thing, but there are times when you'll want to disable it. To show all the output, go to the script editor and select History | Echo all Commands. This will cause Maya to output everything to the script editor. This generally means much, much more output than you want, but can sometimes be helpful. In practice, you'll generally want to leave that option off except when you're trying to replicate a given piece of functionality in a script, and the default output isn't giving you any insight into what Maya is doing.
If you have Maya setup to use interactive mode for the creation of primitive shapes, you must have seen the following in the output presented in the Script Editor:
setToolTo CreatePolyCubeCtx;
Contexts are an alternative way of getting input from the user, and we'll have more to say about them in Chapter 10, Advanced Topics.
Not only is the Script Editor a great way to see which commands correspond to the actions you take in Maya's UI, but it is also a convenient way to write small bits of code. While you will certainly want to use a text editor to write your scripts, it is still important to be comfortable using the script editor to run small sections of code, either to test it out before inclusion in a larger script or to get more information about the current scene.
Make sure that you have the script editor open and that you've switched to the Python tab in the input (bottom) section.
Type the following into the input section:
import maya.cmds maya.cmds.polyCube()
Once you've done that, execute it by either pressing the Execute button at the top of the Script Editor or just by pressing Control + Enter.
Your code will disappear from the input section, a new polygon cube will be created, and the results will be pasted into the output ("History") section of the script editor.
To keep your code from disappearing automatically, highlight it first with Command-A (to select everything), then press Command + Enter. This will cause Maya to run just the selected code without clearing out the input section.
Although the polyCube
command does the actual work, we have to first import the Maya library for Python before we can use it. To do this, we have to first use import maya.cmds
.
The script editor is a great way to try out small snippets of code, but the fact that successful code is deleted can get rather frustrating. For any real script development, you'll want to use a programmer-friendly text editor.
One handy thing about the script editor is that you can save code from the editor to the shelf. To do this, enter some code into the input section, then go to File | Save Script to Shelf... from the Script Editor menu. Maya will ask you to provide a name for the script and then (after a bit of time), a new button will appear in the "Custom" shelf. Pressing that button will execute the corresponding code.
Although most of your scripting work will involve writing separate scripts, it can sometimes be useful to copy-paste commands from the history (top) section of the Script Editor to the input (bottom) section and save it all to the shelf. This is a bit like recording an action in Photoshop and can be a quick and dirty way to create a new shortcut for commonly used functionality.
Python is a really useful language, but it doesn't actually offer that much out of the box other than some basic commands for manipulating simple data. In order to do truly interesting things, you'll generally need to extend Python's built-in functionality with one or more libraries, including the one that provides access to Maya's functionality.
First, let's import the main Maya scripting library for Python, maya.cmds
:
import maya.cmds as cmds
Once we've done that, we can use cmds
instead of maya.cmds
. For example, if we have this code:
maya.cmds.polyCube()
We can instead use the following:
cmds.polyCube()
That might seem like a minor change, but in the course of a full script, it can save you a great deal of typing. Less typing means fewer typos, so it's well worth doing.
Now that we've done this, let's see what cmds has to offer by listing its contents. Python offers a handy way to display the contents of any object via the dir()
command. Let's use that to get a list of all the commands in maya.cmds
:
commandList = dir(cmds) for command in commandList: print(command)
Run the preceding code, and you'll see a long list of everything defined in the maya.cmds library. This will be an extensive list, indeed. Most of the commands you'll see are covered in the official docs, but it's good to know how to use dir to investigate a given library.
You can also use dir to investigate a specific command. For example, try the following code:
props = dir(cmds.polyCube) for prop in props: print(prop)
Run the preceding code, and you'll see all of the properties for the polyCube command itself. However, the results will likely look a bit odd in that none of them have anything to do with generating a polygonal cube. That's because maya.cmds.[commandName]
is a built-in function. So, if you use dir()
to investigate it further, you'll just see the capabilities that are common to Python functions. For details on the specifics of a command, consult the built-in documentation for Maya's commands, which can be accessed by going to Help | Maya Scripting Reference | Python Command Reference.
Like any other specific subdomain of Python functionality, the commands that expose Maya's toolset to Python are part of a library. In order to make use of them, you have to first import the library. Virtually, every script you write will require the "maya.cmds" library, and you will likely need to include additional libraries occasionally for additional capabilities, such as communicating with a webserver or reading in a particular file format.
Although you could just leave it at import maya.cmds
, that would require a lot of additional typing. By using the import [library] as [shortName]
syntax, you can tell Python to use a custom name as an alias for maya.cmds
. You could use almost any name you want (import maya.cmds as MyUncleFred
would work just fine), but in practice, you want to use something both short and descriptive. You'll also want to make sure that you don't overwrite any of Python's built-in libraries. For example, you could do the following:
import maya.cmds as math
This would rename maya.cmds
as math and cause trouble if you wanted to use any of the functions defined in the math library. Don't do that.
For the sake of this book and consistency with Maya's documentation, we will be using "cmds" as the shorthand for "maya.cmds".
The maya.cmds library is only one of several libraries that can be used to interface Maya with Python. One of the great things about Python support in Maya is that the old way of doing things, where there was both MEL (for day-to-day tasks) and the C++ API (for larger scale plugins), is unified under the banner of Python. The maya.cmds
library handles the MEL component, but for functions previously accessed through the C++ API, you'll want to use maya.OpenMaya instead.
It (maya.cmds) is a lightweight wrapper around the MEL commands that many Maya users have grown accustomed to, and it has the benefit of being officially supported by Autodesk. However, it is not the only way to access MEL commands. There is also a third-party library, PyMEL (accessed by importing pymel.core
). PyMEL has the benefit of being more "Pythonic" and offering nicer syntax, but is not directly supported by Autodesk. It also introduces additional layers of abstraction on top of the built-in functionality, which can lead to poorer performance.
Maya is a complex tool, and it offers a wide range of functionality, all of it with corresponding commands that can be invoked via scripts. Each command has its own set of arguments, ranging from easily understood to quite cryptic.
When writing scripts for Maya (and as with any other kind of programming), it is vital to be able to find the appropriate documentation and to understand how to make sense of it.
Let's say that we want more information on a specific command, say the command to create a polygonal cube.
One way to view the help for the command is to use Maya's web-based command help, available by going to Help | Python Command Reference from within Maya. From there, you can either click on the "Polygons" subsection or use the search box.
There are a couple of other ways to get to the documentation for a command, though. You can also go directly to the documentation for a command from the Script Editor window. First, execute the corresponding action using Maya's interface, such as invoking the hotbox and choosing Create | Polygon Primitives | Cube.
That will cause the corresponding MEL command to be displayed in the output section of the Script Editor, in this case, "polyCube". From within the script editor, highlight the relevant line, and go to Help | Help on Selected Command. This will bring up a browser window with the documentation for that command. Note that it will default to the MEL version of the command; for the Python version, click on the "Python" link in the top-right corner of the window.
Finally, you can retrieve information about a command via Python directly using the help command. Try running the following:
print(cmds.help('polyCube'))
This will result in a list of the flags available for the given command, as well as the type of value that Maya expects for each, such as:
-sx -subdivisionsX Int
This means that there is a flag named "sx" or "subdivisionsX" that expects an integer value.
For the most part, you'll want just the Python command reference open in a browser window while you work on developing your scripts. Good reference documents are key to writing good software, and you should get used to just keeping the references close at hand.
You can also use the help command to invoke the web-based documentation for a given command directly, such as:
cmds.help('polyCube', doc=True, language='python')
This would bring up the web page containing the documentation for the Python version of the polyCube command. That's definitely a clunky way to access the help, but might be useful if you wanted to give the users of your script an easy way to refer to relevant documentation directly from your script's user interface.
One thing that is a bit strange about Maya scripting is that the same command can be used in up to three different ways—create, query, and edit modes—with the specifics varying for each of the command flags. This is a byproduct of the fact that the Python functionality is a wrapper around the older MEL-based scripting system, and it can seem a bit confusing when you're getting started. Nevertheless, it is important to understand the differences between the three modes and how to use them.
Open up the Python command reference by going to Help | Python Command Reference and navigate to the documentation for the polyCube command.
Also, be sure to have the script editor open in Maya and be in the Python tab. Alternatively, you can run the example commands Maya's command line; just make sure that you're running in Python mode rather than MEL (click on MEL to switch to Python and Python to switch back to MEL).
First off, take a look at the Properties column. You'll see that every flag has some combination of "C", "E", "Q", and "M" listed. Those refer to the different ways in which a command can be run and have the following meanings:
C: "Create" flag is only relevant when first running the command, such as when you initially create a polygonal primitive
Q: "Query" flag can be queried after the command has been run and can be used to retrieve information about something in the scene
E: "Edit" flag can be edited after the fact
M: "Multiple" flag can be used more than once in a single instance of the command (to create specify multiple points when creating a curve, for example)
For many flags, you'll see a full complement of create, query, and edit, but there are generally at least a few flags that aren't accessible for one or more of the modes.
Let's see how create, edit, and query play out in the case of the polyCube command.
First off, let's make a new cube and store the result in a variable, so we can make use of it later:
myCube = cmds.polyCube()
Now, let's change something about the cube, post-creation by using the edit mode:
cmds.polyCube(myCube, edit=True, subdivisionsX=5)
This will cause the cube that we created with the first command to be altered from the default (no subdivisions in the x axis) to having five.
Now, let's use the query mode to store the new number of divisions to a variable:
numberDivisions = cmds.polyCube(myCube, query=True, subdivisionsX=True) print(numberDivisions)
You should see "5.0" as the output. Note that even though the number of divisions of a polygonal cube must be an integer value, Maya is displaying it as "5.0".
The important thing to note for the query and edit modes is that you run the command as you normally would (cmds.polyCube
, for example), but with the following three key differences:
The inclusion of the name of the object as the first argument. This can either be the name directly as a string
("pCube1"
, for example), or a variable.The inclusion of either
edit=True
orquery=True
as an argument.Additional arguments, with the specifics based on whether you're running the command in the query or edit mode.
For the edit mode, you'll want to specify the name of the property you want to change, along with the new value. For the query mode, you'll want to just include the name of the property and "=True". Think of this as saying that it is True
that you want to know the value of the property. Note that you can only query a single flag at a time. If you need to query multiple values, run the command multiple times, changing the flag you pass in.
Although many of the most-used properties can be used in all three modes, there are numerous examples of ones that cannot be, mainly because it wouldn't make sense to do so. For example, it's perfectly reasonable to set construction history on or off when creating a new object, and it's certainly reasonable to query that after the fact, but what would it mean to use the edit mode to enable construction history on an object that didn't already have it? That would require rebuilding the history of the object, which may have been manipulated in various ways since it was created. As a result, the "constructionHistory" (or "ch") flag only offers the Create and Query options.
You might think that this is all a bit clunky, and if all we wanted to do was set the number of subdivisions for a newly created cube, you would be correct. However, it's important to understand the different command modes, both to get information after the fact and because it's an important part of building user interface elements and getting information from them.
We'll be making the extensive use of the Query mode to retrieve information from user interface elements throughout the rest of the book, starting in Chapter 2, Creating User Interfaces.
In order to write reusable scripts, you'll want to save your scripts to external files, and in order to do that, you'll need to make sure that Maya knows where they are.
Maya maintains a list of locations to search for scripts, used when you use the import (Python) or source (MEL) commands. If you want to see the full list, you can do so with the following code:
import sys pathList = sys.path for path in pathList: print(path)
This will provide you with a list of paths, including the following:
/Users/[username]/Library/Preferences/Autodesk/maya/[maya version]/prefs/scripts /Users/[username]/Library/Preferences/Autodesk/maya/[maya version]/scripts /Users/[username]/Library/Preferences/Autodesk/maya/scripts
Saving your scripts to any of those folders will allow Maya to find them. If you're fine with saving all of your scripts to one of those folders, that's totally fine.
However, you might want to add additional folders to the list. For example, you might want to save your scripts in a folder within the my Documents
directory, maybe something like:
/Users/adrian/Documents/MayaScripting/examples/
Note that this is a typical example on Macintosh. On a Windows machine, it would look more like:
\Documents and Settings\[username]\MyDocuments\MayaScripting\examples
Either way, we'll need to tell Maya to look there to find scripts to execute. There are a few ways we could do it, but in keeping with the theme of the book, we'll do it using Python.
Run the following code in the script editor:
import sys sys.path.append('/Users/adrian/Documents/MayaScripting/examples')
This is done by replacing /Users/adrian/Documents/MayaScripting/examples
with whatever folder you want to use.
Once you've done this, you'll be able to import scripts stored in that directory as well. However, having to enter the preceding code every time you launch Maya would be quite frustrating. Luckily, Maya provides a way for us to execute custom Python code on a startup.
To make the code execute every time Maya opens, save it to a file named userSetup.py
and save it to the following location for a Mac:
~/Library/Preferences/Autodesk/maya/<version>/scripts
Or for Windows, you can save it to:
<drive>:\Documents and Settings\<username>\My Documents\maya\<version>\scripts
All of the code contained in userSetup.py
will be run every time Maya starts up.
While the base list of paths that Maya will search for scripts is not altered by the above, it will cause Maya to add your custom folder to the list every time it starts up, which in practice amounts to the same thing.
You can also add to your paths by creating the Maya.env file and saving it to the following location (on a Mac machine):
/Users/<username>/Library/Preferences/Autodesk/maya/version
or
/Users/<username>/Library/Preferences/Autodesk/maya
On a Windows machine, save it to:
drive:\Documents and Settings\username\My Documents\maya\version
or
drive:\Documents and Settings\username\My Documents\maya
For the specifics of the Maya.env
file syntax, consult Maya's documentation. However, editing Maya.env
can lead to crashes and system instability if you're not careful, so I recommend relying on userSetup.py
instead.
In this recipe, we'll be writing and running our first actual script as an external Python file.
The Script Editor window is a bit of a misnomer. Although it's a great way to test out short snippets of code, it's awkward to use for any kind of real script development. For this, you'll want to have a programmer-friendly text editor setup. There are a ton of options out there, and if you're reading this book, you likely already have one that you like to use. Whatever it is, make sure that it's geared towards writing code, and it saves files in plain text.
First off, we'll need a script. Create a new file in your editor and add the following code:
import maya.cmds as cmds print("Imported the script!") def makeObject(): cmds.polyCube() print("Made a cube!")
Now save the script as myScript.py
. Once you've done that, switch back to Maya and run the following from either the script editor or the command line:
import myScript
This will cause Maya to read in the file, and you'll see the following in the script editor output:
Imported the script!
What you will not see, however, is a new cube. That's because the real functionality of our (simple) script is defined within a function named "makeObject".
Maya treats each Python file that you import as its own module, with the name of the file providing the name of the module. Once we've imported a file, we can invoke functions within it by calling [moduleName].[function name]. For the earlier-mentioned example, this would mean:
myScript.makeObject()
Run it, and you should see a newly minted cube show up, and "Made a cube!" in the output of the Script Editor.
Now, let's try changing our script. First, delete the cube we just made, then switch over to your text editor, and change the script to the following:
import maya.cmds as cmds def makeObject(): cmds.polySphere() print("Made a sphere!")
Switch back to Maya and run the script again with:
myScript.makeObject()
You'll see that rather than having a nice sphere, we still ended up with a cube. That's because when you ask Maya to execute a script that it has already executed, it will default to rerunning the same code that it ran previously. In order to ensure that we get the latest, greatest version of our script, we'll need to first run the following:
reload(myScript)
This will force Maya to reload the file. Note that the argument to reload isn't the file name itself (myScript.py
in this case), but rather the name of the module that the file defines ("myScript").
Once you've done this, you can once again try:
myScript.makeObject()
This time, you'll see a proper polygonal sphere, just as we intended.
It may seem like an unnecessary extra step to both import the script and call one of its functions, and you can indeed have the script automatically execute code (as demonstrated by the call to print("Imported Script!"). However, it's much better practice to wrap all of your functionality in functions, as it makes large scripts much easier to work with.
If you have functionality that you want to execute every time the script is run, it is best to define a function with a name like "main" and have the last line of your script invoke it. Take a look at the following example:
import maya.cmds as cmds def makeObject(): cmds.polyCube() print("Made a cube!") makeObject()
This would define the makeObject()
function, then (on the last line of the script) cause it to be executed.
When working on a script, it can get really tedious to reload, import, and run the script each time. An easy way to get around that is to enter the following into the script editor:
import myScript reload(myScript) myScript.myCommand()
Once you've done that, use File | Save Script to Shelf... to give yourself a button to easily rerun the latest version of your script. Note that the preceding code contains both import and reload. That's to make sure that the code will work both the first time you run it as well as successive times. The "import" command is there to ensure the module has been loaded at least once (necessary for a new script, or upon restarting Maya), and the "reload" command is there to ensure that what we're running is the latest version (necessary if we've made changes to the script with Maya still up).
If you have a script that defines a lot of functionality, and you don't want to constantly type out the module name, you can use the same trick we used with maya.cmds
to shorten things a bit. Namely, you can use the "as" syntax to provide a shorter name. For example, I could have done the following:
import myScript as ms ms.makeObject()
This would have exactly the same effect.
Maya offers two different languages with which to create custom functionality via scripting—both Maya Embedded Language (MEL) scripts and Python. In practice, you'll only want to use one, and of the two, Python offers a much better and more flexible experience.
However, it is not uncommon to have legacy scripts that were written back before Maya added Python functionality. While the "right" solution would be to rewrite the scripts using Python, there's not always enough time to do so. In those cases, it can sometimes be helpful to be able to call out to legacy, MEL-based functionality from within your Python scripts.
Although Python is definitely the better way to create new functionality, it may sometimes be the case that you have older scripts that were written in MEL that you would like to incorporate.
The best option is to rewrite the script in Python, but if the script is complex or you don't have time, it may be easier to just invoke the MEL functionality from within a Python script. This way, you can incorporate legacy functionality without completely reinventing the wheel.
For this recipe, you'll need the MEL script. If you don't have one handy, open up a new file and enter the following:
global proc myMELScript() { polyCube; print("Hello from MEL!"); }
Save this as myMELScript.mel
in your maya/scripts
directory. Although we won't be going into the details of MEL, do note that the file has the same name as the function that we're defining. Most MEL scripts will follow that convention. Also note the inclusion of semicolons after the end of each line. Although Python doesn't require them, MEL (and many other languages) does.
Once you have that, create a new file and name it runMEL.py
. Enter the following:
import maya.cmds as cmds import maya.mel as mel def runMEL(): print("Running MEL from Python") mel.eval("source myMELScript;") mel.eval("myMELScript;") runMEL()
Save the script and run it with:
import runMEL
Because the last line of our script invokes the runMEL command, it will automatically take effect. You should see a new cube, as well as the following output in the Script Editor:
Running MEL from Python Hello from MEL!
In this example, we imported both maya.cmds and maya.mel. The maya.mel library provides support to interface Python with MEL, with one of its most useful commands being the eval function, which takes an arbitrary string and attempts to run it as an MEL command. In the earlier example, we do that twice, with the first command being:
source myMEL;
The source command does the same thing as reload, in that it ensures that Maya will reread the entire source file, rather than rerunning a potentially outdated version. This shouldn't matter because it's only necessary if you're making changes to the MEL script (and hopefully you're not doing that, use Python instead!) but it's a good thing to include just in case.
Once we've done this, we actually run the MEL script with:
myMEL;