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?
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