om2-BeginnersGuide 01 - connectAttr / getAttr / setAttr
Disclaimer:
All code here is provided as is without support.
Use at your own risk! These posts assume you have some knowledge of import/running python script in maya

So now we have a handle of getting a selection, or building an MSelectionList() to get MObjects to manipulate in scene.

Now another big part of our day is creating nodes / adding or removing attributes / querying attributes values / connecting or disconnecting attributes.

Below might look familiar those of you using cmds a lot;

from maya import cmds
curSel = cmds.ls(sl=True)
srcNode = curSel[0]
destNode = curSel[1]

# connect
cmds.connect("{}.translate".format(srcNode),
             "{}.translate".format(destNode),
             force=True)
# getAttr
transX = cmds.getAttr("{}.translate".format(srcNode))

# setAttr
cmds.setAttr("{}.translateX".format(srcNode), 10)

# createNode
newNode = cmds.createNode("transform", name="Fart")

Yes it is true that we’re about to convert this into more lines using om2. And yes I still do a lot of prototyping in cmds when mashing stuff together in the script editor, but for reuse tools, I will most likely convert those scripts to om2, even the ones that might not see a lot of benefit speed wise, as it’s just good practise and I find it fun to do shrug.

from maya.api import OpenMaya as om2
from maya import cmds
# mDagMod for creating / handling DGNodes
mdgmod = om2.MDGModifier()

# mDagMod for creating / handling DagNodes
mDagMod = om2.MDagModifier()

curSel = om2.MGlobal.getActiveSelectionList()
srcNode = curSel.getDependNode(0)
destNode = curSel.getDependNode(1)

# connect
# Find first source plug, find dest plug, use the modifier to connect them
mFn = om2.MFnDependencyNode(srcNode)
srcPlug = mFn.findPlug("translate", False)
mFn.setObject(destNode)
destPlug = mFn.findPlug("translate", False)
if destPlug.isConnected:
    # Find what it is connected to and disconnect it first!
    # Since this is a destination only one thing can be connected to it.
    # Else if we're looking for all connected to a source we can use connectedTo()
    src = destPlug.source()
    mDagMod.disconnect(srcPlug, destPlug)

mDagMod.connect(srcPlug, destPlug)
mDagMod.doIt()

# getAttr
# some plugs are compounds, some are arrays, some are floats / bool / shorts / double etc
srcTrans = [srcPlug.child(x).asFloat() for x in range(srcPlug.numChildren())]
print(srcTrans)

# setAttr
srcPlug.child(0).setFloat(10)

# createNode
# Depending on if you are making a DAGNode or DGNode you'll need to use either a
# MDagModifier or a MDGModifier() eg: you can't make a joint with a MDGModifier()
nodeName = "Fart"
# We can use cmds here to check for the node as the queries in cmds are pretty
# fast.
if not cmds.objExists(nodeName):
    newNode = mDagMod.createNode("transform")
    mDagMod.renameNode(newNode, nodeName)
    mDagMod.doIt()
# Note you might want to use the MFnDependencyNode.create() method, but this will
# create the node in scene as soon as you call this. Using the MDG or MDag modifiers
# lets you queue up xNum of operations and using the doIt() to perform them in one
# go. Which can be a HUGE time saver when building complex scenes.

So what about this:

”# some plugs are compounds, some are arrays, some are floats / bool / shorts / double etc”

If you’re confused what kind you’re dealing with you can use Maya’s nodeEditor to try to figure it out.

An MPlug has a couple methods to help out.

MPlug.isArray()
MPlug.isCompound()
MPlug.isElement()
MPlug.isChild()

The main difference between an Array and a Compound being;

Lets look at this in code:

from maya.api import OpenMaya as om2
# mDagMod for creating / handling DAGNodes
mDagMod = om2.MDagModifier()
mDGMod = om2.MDGModifier()

curSel = om2.MGlobal.getActiveSelectionList()
srcNode = curSel.getDependNode(0)
destNode = curSel.getDependNode(1)

# Connect the CHILDREN of attributes "translate", "rotate", "scale" to
# another transform's "translate", "rotate", "scale"
mFn = om2.MFnDependencyNode()
for x in range(3):
    mFn.setObject(srcNode)
    for plugName in ("translate", "rotate", "scale"):
        mFn.setObject(srcNode)
        srcPlug = mFn.findPlug(plugName, False)
        srcMPlug = srcPlug.child(x)

        mFn.setObject(destNode)
        destPlug = mFn.findPlug(plugName, False)
        destMPlug = destPlug.child(x)
    
        mDagMod.connect(srcMPlug, destMPlug)

# Note how we've stacked all these connections BEFORE calling the doIt()
mDagMod.doIt()

# Now the worldMatrix (which is an Array)

mFn.setObject(srcNode)
srcPlug = mFn.findPlug("worldMatrix", False)
srcWorldMatrix0 = srcPlug.elementByLogicalIndex(0)
mFn.setObject(destNode)

decomposeMatrix = mDGMod.createNode("decomposeMatrix")
# This node NEEDS TO EXIST to connect to! So we have to create it now!
mDGMod.doIt()

mFn.setObject(decomposeMatrix)
destPlug = mFn.findPlug("inputMatrix", False)

mDagMod.connect(srcWorldMatrix0, destPlug)
mDagMod.doIt()

Finally it’s probably important to know the difference between a logical index and a physical one… from the docs… yes the info is all there :P

Logical Index:

“This method will find and return a plug with the given logical index.

The logical index is the sparse array index used in MEL scripts. If a plug does not exist at the given Index, Maya will create a plug at that index. This is not the case with elementByPhysicalIndex(). If needed, elementByLogicalIndex can be used to expand an array plug on a node.
It is important to note that Maya assumes that all such plugs serve a purpose and it will not free non-networked plugs that result from such an array expansion.”

Physical Index:

“This method will find and return a plug with the given physical index.

The index can range from 0 to numElements() - 1. This function is particularly useful for iteration through the element plugs of an array plug. It is equivalent to operator [] (int) This method is only valid for array plugs.

If the returned plug is networked, the networked plug will be returned. Otherwise, a non-networked plug will be returned.”

.. onwards… MObject