Maya Python API 2.0
What is the Python API?
Maya's core architecture is built using a combination of "Maya Commands" and the "Maya API". The API is low level, whereas the Commands are more easily accessible. MEL can only talk to Maya Commands, and C++ can only talk to Maya API (you can hack around this but it's dirty). But, Python can talk to both, giving you a combination of the power and speed of the API, and functionality of existing commands.
This is helpfully depicted in a diagram from Autodesk's Maya API Documentation
Why the Python API?
When using the API, the learning curve is steeper. You need to write a lot more code to achieve the same result. Reference is much harder to come by. If creating a command, you must implement your own undo commands. So what are the benefits?
The Python API allows a much more palatable platform from which to author fast-running code within Maya. The C++ API still rules the roost when it comes to speed, but this requires not only knowledge of C++, but also the use of Visual Studio. To top that, each time you change a C++ plugin, it needs to be unloaded, the code needs to be recompiled (for the correct version of Maya AND the target platform) and the plug-in then reloaded. This can hinder iteration times massively, especially if you're tinkering to experiment with an algorithm.
In the tests below, we implement a simple algorithm in both PyMEL and the Python API; calculate the area of a sphere with 90,000 faces, by iterating over each face and tallying as we go.
- PyMel: 16.61 seconds
- Python API: 0.15 seconds
In this test, the API is 110x faster than PyMel!
import pymel.core as pm start_time = pm.timerX() sphere = pm.polySphere(sx=300, sy=300) # Create a really dense sphere BEFORE we start the timer area = 0 for face in sphere.faces: area += face.getArea() print 'Area = %.2f' %area print 'Duration = %f seconds' %cmds.timerX(st=start_time) # Results: # Area = 12.57 # Duration = 21.250000 seconds
import maya.cmds as cmds cmds.polySphere(sx=300, sy=300) # Create a really dense sphere BEFORE we start the timer start_time = cmds.timerX() import maya.OpenMaya as om selection_list = om.MSelectionList() dag_path = om.MDagPath() om.MGlobal.getActiveSelectionList(selection_list) selection_iterator = om.MItSelectionList(selection_list) selection_list.getDagPath(0, dag_path) area = 0 # Iterate through the selection (in this case it's only the sphere we just created) while not selection_iterator.isDone(): mesh = om.MDagPath() component = om.MObject() selection_iterator.getDagPath(mesh, component) face_iterator = om.MItMeshPolygon(mesh, component) face_area = om.MScriptUtil() face_area_double = face_area.asDoublePtr() # Iterate over each face while not face_iterator.isDone(): face_iterator.getArea(face_area_double) area += face_area.getDouble(face_area_double) face_iterator.next() selection_iterator.next() print 'Area = %.2f' %area print 'Duration = %f seconds' %cmds.timerX(st=start_time) # Results: # Area = 12.57 # Duration = 0.160000 seconds
API v1 vs v2
At the time of writing (Maya 2018), v2.0 is not fully fleshed out, and you may find yourself having to use both in your script. This is totally valid, BUT you will be unable to pass data back and forth between objects of different versions.
Importing version 1.0
import maya.OpenMaya as om
Importing version 2.0
import maya.api.OpenMaya as om2 # Note the api namespace here!
import maya.api.OpenMaya as om2 om2.MGlobal.displayError('Error Output')
You must ensure that any commands you create, have the associated
Creating a Plug-In
Plugins must be saved to the MAYA_PLUGIN_PATH directory e.g C:/Users/USERNAME/Documents/maya/VERSION/plug-ins
Load the plugin
In the "Plug-In Manager", click the "i" icon to see the commands registers with your plugin.