__getitem__ and maya.cmds weird behavior

Hi all. I’m experiencing weird behavior of Python “magic” methods and maya.cmds. Below you can see 2 versions of the code. In both versions I use string representation of the class object as first argument in cmds.connectAttr() but in second version where I have implemented __getitem__ method maya throws out # TypeError: Invalid argument 1, 'transform1.translateX'. Expected arguments of type ( , ) #
Here si the code:

import maya.cmds as mc

tr1 = mc.createNode("transform", name="transform1")
tr2 = mc.createNode("transform", name="transform2")

Version 1:

class AttrClass:
    
    def __repr__(self):
        return "transform1.translateX"
    
obj = AttrClass()

mc.connectAttr(obj, "transform2.scaleX")

Version 2:

class AttrClass:
    
    def __repr__(self):
        return "transform1.translateX"
    
    def __getitem__(self, item):
        print(item)
        
obj = AttrClass()

mc.connectAttr(obj, "transform2.scaleX")

In version 2 if you try explicitly call __repr__() it works fine :

mc.connectAttr(obj.__repr__(), "transform2.scaleX")

Another weird thing happens if I try to use pymel to connect

import pymel.core as pm
pm.connectAttr(obj, "transform2.scaleX")

This will start to print integers infinitely.

What I’m doing wrong?

You are not explicitly returning anything in your __getitem__ method. All it does is print the attribute. In python when you don’t explicitly use return then it returns None.
Try directly calling your __getitem__ and assign it to a variable and you’ll see the variable contains None.

The original code which I can’t post here returns self. And the result is the same : # Result: <class '__main__.AttrClass'>

Is this an attempt to get at the underlying attrbute? Like turning myobject.translateX in code into the string "myobject.translateX"?

In a case like that, it’s better to derive from str so there’s no shenanigans and also so the object is immutable like a string (since Maya is using immutable strings, doing something else introduces wierd bugs).

Something like this will let you add pseudo-property access

class PropDescriptor:

    def __init__(self, name ):
        self.name = name
        
    def __get__(self, obj, objtype=None):
        return obj + "." + self.name

    
class AttrClass (str):
    translate = PropDescriptor("translate")

test = AttrClass("top")

print (test.translate)
# top.translate

print(cmds.getAttr(test.translate))
# Result: [(0.0, 1000.1, 0.0)] # 

This is used vey extensively in nodule which coincidentally I just updated to Python 3 today to allo things like connect (nodule_1.translateX, nodule_2.rotateY) or my_cube.visibility = True … pymel without the pymel, as it were.

2 Likes

Thanks for reply. That’s partially solves the problem. Now I need to solve multi attributes(indexed). Actually __getitem__ I was using for that purpose.
By the way nice nodule! Definitely will check it out!