-1

There are multiple ways to access attributes of a PyNode such as Transform, which has the attributes translation, rotation and so on.

import pymel.core as pm

cube = pm.polyCube()[0]

cube.translationX.set(1)
cube.translation.translationX.set(2)
cube.tx.set(3)
cube.t.tx.set(4)

# and more

What I don't understand is how the attributes are found because I cannot find any documentation that lists the attributes? Does Transform have all those attributes where each points at the corresponding, underlying attribute of the DAG node? Where does the mapping happen so the right attribute is found?

akuzminykh
  • 4,522
  • 4
  • 15
  • 36

1 Answers1

2

You can just use :

cube.listAttr()

Im not sure they wrapped all attributes.

I have a simple cmds wrapper myself where Im just adding dynamicly any attributes of a node by overriding : getitem, getattr

here is the full code on git : https://github.com/DrWeeny/stackoverflow/blob/master/59185039.py it is just an example

class MAttr(object):
    """Represent a maya attribute

    Args:
        node (str): a string for the maya node affected
        attr (str): a string that represent the attribute
    Attributes:
        attr_bypass (str): regex to bypass the compound attributes, because i need to connect and getattr
    """
    attr_bypass = re.compile('\[(\d+)?:(\d+)?\]')

    def __init__(self, node, attr='result'):
        self.__dict__['node'] = node  #: str: current priority node evaluated
        self.__dict__['attribute'] = attr  #: str: current priority node evaluated
        self.__dict__['idx'] = 0  #: str: current priority node evaluated

    def __getitem__(self, item):
        """
        getitem has been overrided so you can select the compound attributes
        ``mn = MayaNode('cluster1')``
        ``mn.node.weightList[0]``
        ``mn.node.weightList[1].weights[0:100]``

        Notes:
            the notations with list[0:0:0] is class slice whereas list[0] is just and int

        Args:
            item (Any): should be slice class or an int

        Returns:
            cls : MAttr is updated with the chosen index/slice
        """
        if isinstance(item, int):
            self.__dict__['attribute'] = '{}[{}]'.format(self.attr, item)
        else:
            if not item.start and not item.stop and not item.step:
                item = ':'
            else:
                item = ':'.join([str(i) for i in [item.start, item.stop, item.step] if i != None])
            self.__dict__['attribute'] = '{}[{}]'.format(self.attr, item)
        return self

    def __getattr__(self, attr):
        """
        __getattr__ is overriden in order to select attributes
        Args:
            attr (str): name of the attribute, even if we loop throught,

        Returns:
            str: it join all the attributes that has been chained : weightList[0].weight

        """
        myattr = '{}.{}'.format(self.attr, attr)
        if myattr in self.listAttr(myattr):
            return MAttr(self._node, '{}.{}'.format(self.attr, attr))
        else:
            return self.__getattribute__(attr)

class MayaNode(object):
    """Represent a maya node as a class like pymel

    Only provide the name as a string, if you use preset, you can create a new node

    Note:
        Should use maya api for getting the node

    Args:
        name (str): a string for the maya node you want to encapsulate
        preset (:obj:`dict`, optional): Used for creating a new node from 'attrPreset'
            you can also just specify the nodeType with a string instead

    Attributes:
        maya_attr_name (maya_data): Any attribute from the name will look for actual maya attribute

    """

    def __init__(self, name, preset={}, blendValue=1):

        # this dict method is used to avoid calling __getattr__
        self.__dict__['node'] = name  #: str: current priority node evaluated
        self.__dict__['item'] = 1  #: int: can be either 0 or 1 and should be exented with Mesh or Cluster
        if preset:
            targ_ns = name.rsplit(':', 1)[0]
            self.loadNode(preset, blendValue, targ_ns)

    def __getitem__(self, item):
        """
        getitem has been overrided so you can select the main nodes sh or tr so when you do:
        ``mn = MayaNode('pCube1')``
        ``mn[0].node`` result as the transform
        ``mn[1].node`` result as the shape

        Note:
            By default ``mn.node`` is the transform
        """
        return self.setNode(item)

    def __getattr__(self, attr):
        """
        getattr has been overrided so you can select maya attributes and set them
        if you type an attribute, it will try to find if it exists in either shape or transform
        if it exists in both, it will always warn you that it returns shape in priority
        ``mn = MayaNode('pCube1')``
        ``mn.translateX = 10`` result in doing a cmds.setAttr
        ``mn.translateX.set(10)``
        ``mn.translateX.get()`` note that you to use get in order to do getAttr otherwise it __repr__ or __str__

        ``mn = MayaNode('cluster1')``
        ``mn.weightList[1].weights.get()`` is equivalent of cmds.getAttr('cluster1.weightList[1].weights[:]')

        Note:
            You cant have the value without .get()
        """
        if attr in self.listAttr(attr):
            return MAttr(self.node, attr)
        elif attr in self.__dict__:
            return self.__dict__[attr]
        else:
            try:
                return self.__getattribute__(attr)
            except AttributeError:
                cmds.warning('{} doesn\'t exists, return None instead')
                return None
DrWeeny
  • 2,487
  • 1
  • 14
  • 17