pythonmayamelpymelmaya-api

Get the parameter flags and default values for a Maya command


I am trying to get the flags and default values for any given maya command. In python I would generally use the inspect module, but as pymel is only a wrapper I don't see that as an option here. I was hoping the api would have something that could accomplish this, but haven't run across anything. Below is a ghetto approach, works in this use-case, but it's hacky and would have to be modified considerably to actually work for all commands (not a road I want to travel):

def getMayaCmdFlagDefaults(cmd):
    '''Get the flags and corresponding default values of a given MEL command.

    :Parameters:
        cmd (str) = A MEL command name.

    :Return:
        (dict) {'flag':<value>}
    '''
    obj_types = ['polyPlane', 'nurbsPlane'] #etc..

    for obj in obj_types:
        try:
            temp = getattr(pm, obj)(ch=0)
            node = getattr(pm, cmd)(temp)
            if node:
                result = Init.getAttributesMEL(node[0])
                pm.delete(temp)
                return result

        except Exception as error:
            print ('# Error: {}: {} #'.format(cmd, error))
            pm.delete(temp)


print (getMayaCmdFlagDefaults('polyReduce'))
# returns: {u'keepQuadsWeight': 0.0, u'symmetryPlaneW': 0.0, u'symmetryPlaneZ': 0.0, u'symmetryPlaneX': 0.0, u'symmetryPlaneY': 0.0, u'sharpness': 0.0, u'keepBorderWeight': 0.5, u'vertexMapName': None, u'vertexWeights': None, u'border': 0.5, u'keepBorder': True, u'triangleCount': 0, u'keepHardEdgeWeight': 0.5, u'keepCreaseEdge': True, u'percentageAchieved': 0.0, u'keepColorBorder': True, u'version': 0, u'triangleCountIn': 200, u'percentage': 0.0, u'keepMapBorderWeight': 0.5, u'useVirtualSymmetry': 0, u'keepColorBorderWeight': 0.5, u'symmetryTolerance': 0.0, u'geomWeights': 1.0, u'detail': 0.5, u'invertVertexWeights': True, u'keepHardEdge': True, u'keepCreaseEdgeWeight': 0.5, u'uvWeights': 0.0, u'vertexCount': 0, u'termination': 0, u'line': 0.5, u'weightCoefficient': 10000.0, u'vertexCountIn': 121, u'keepFaceGroupBorderWeight': 0.5, u'keepMapBorder': True, u'vertexCountAchieved': 0, u'keepFaceGroupBorder': True, u'triangulate': True, u'cachingReduce': False, u'weights': [], u'compactness': 0.0, u'vertexWeightCoefficient': 1.0, u'triangleCountAchieved': 0, u'keepOriginalVertices': False, u'symmetryPlane': (0.0, 0.0, 0.0, 0.0), u'colorWeights': 0.0, u'preserveTopology': True}

Using Inspect (by far the preferred method):

print (inspect.getargspec(pm.polyReduce))
# returns: ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)

print (inspect.getargspec(cmds.polyReduce))
# returns: TypeError: <built-in method polyReduce of module object at 0x000002B30DDE3078> is not a Python function

# Additional things of interest that I have tried:
# backport of inspect.signature for python 2.6+:
import funcsigs
bound_args = funcsigs.signature(pm.polyReduce)

# unwrap a decorated method:
def extract_wrapped(decorated):
    closure = (c.cell_contents for c in decorated.__closure__)
    return next((c for c in closure if isinstance(c, FunctionType)), None)

Solution

  • The issue is that a command doesn't provide that information. You need to understand that the cmds module is exactly what it's called; a series of commands to populate/manipulate the scene. The actual defaults are embedded in the actual node class through its attributes.

    The command is really a "function" that calls a special class (MPxCommand), and its job is to parse arguments you pass in mel/python and do something with those arguments.

    cmds.polyPlane for instance, takes a series of parameters passed to it, and either creates/modifies the node and essentially wraps that so it's undoable. Without any parameters, typically it'll create an instance of that object in your scene. The defaults come from the class of the polyPlane itself, not the cmd.polyPlane function used to create it. When you pass arguments to cmds.polyPlane to change its properties, the command simply creates the polyPlane and then modifies its attributes... explicitly!

    I think what you need is cmds.attrInfo. Check its documentation. They outline an example there that might help you get started. You were on the right track...

    The good news is that this data needs to be parsed once (the attribute defaults of an object won't change unless the application changes to a new version). Once you have a script that creates then checks the node using cmds.attrInfo, you can dump that info to a file and subsequently read the file whenever you need that info.

    For instance you might want to start a simple text or json file with a list of the nodes you want to prioritize, and run a script that reads the list of nodes, creates each node, parses its attribute info, and dumps those details to a separate text or json file which you can read later. If you require info about additional nodes, simply update the former file with the new node names, run your script which updates the latter file. Start small, and modify as required.