python setattr() on nested attributes of a pymxs-node

python setattr() on nested attributes of a pymxs-node

morten_bohne
Advocate Advocate
3,529 Views
3 Replies
Message 1 of 4

python setattr() on nested attributes of a pymxs-node

morten_bohne
Advocate
Advocate

Hi, I am trying to set an attribute on a pymxs-node based on the string name of an attribute.
It seems to work fine for simple attributes:

import pymxs
rt = pymxs.runtime
teapot = rt.teapot()
attribute = "ishidden"
setattr(teapot, attribute, True)

 

 but when I need to set nested attributes ("controller.position.x") I run into problems.

Normally I would expect that I need to find the teapot.controller.position-object and then setattr on that:

import pymxs
rt = pymxs.runtime

teapot = rt.teapot()
object = teapot
attribute = "controller.position.x"
attribute_parts = attribute.split(".")
for a in attribute_parts[:-1]:
	object = getattr(object, a)
	
print "posX: {0}".format(getattr(object, attribute_parts[-1]))
# prints: posX: 0.0
setattr(object, attribute_parts[-1], 20)
print "posX: {0}".format(getattr(object, attribute_parts[-1]))
# prints: posX: 20.0

this all looks fine, but my object doesn't update in the viewport, and if i try to get the controller.position-object again, it hasn't changed:

object = teapot
attribute = "controller.position.x"
attribute_parts = attribute.split(".")
for a in attribute_parts[:-1]:
	object = getattr(object, a)

print "posX: {0}".format(getattr(object, attribute_parts[-1]))
# prints: posX: 0.0

any ideas on how to set that kind of attribute?

0 Likes
Accepted solutions (1)
3,530 Views
3 Replies
Replies (3)
Message 2 of 4

har1sf0x
Advocate
Advocate
Accepted solution

Hello there,

 

 Check this:

import pymxs
rt = pymxs.runtime

teapot = rt.teapot()
object = teapot
attribute = "controller.position.x" #it works with 'controller.pos.x' as well
attribute_parts = attribute.split(".")
#~ for a in attribute_parts[:-1]:
	#~ object = getattr(object, a)
	
#~ print "posX: {0}".format(getattr(object, attribute_parts[-1]))
# prints: posX: 0.0
setattr(object, '.'.join(attribute_parts[1:]), 20)
#~ print "posX: {0}".format(getattr(object, attribute_parts[-1]))
# prints: posX: 20.0

  In maxscript (the source of pymxs) the correct attribute is 'position.x' or 'pos.x'. For some reason it gives you results with 'controller.position.x'. I can only suppose that python 'creates' these attributes on the class but these are not the attributes that are being used from the node for the positioning.

 

Enjoy,

har1sf0x

0 Likes
Message 3 of 4

morten_bohne
Advocate
Advocate

thank you so much!

way easier than the way i was trying. 

I still can't get it to set local position this way, but i just ended up adding a property for that where the .setter converts it to world pos before setting it. Not a pretty solution, but it works for now.

 

I did find it interesting that that this didn't work for me:

teapot.pos.x = 2

but this did:

setattr(teapot, "pos.x", 2)

but i guess that's back to max creating these child objects that doesn't really do anything other than storing a value you can read? I would love if anyone had some more insight on how this actually works under the hood, or if people have noticed any other pitfalls with the normal python-functionality that differs in pymxs?

 

0 Likes
Message 4 of 4

har1sf0x
Advocate
Advocate

Hello,

 

  pymxs is too undocumented. I do not know your background but i would go for either maxscript (if you are a 3ds max user that wants to script) or maxplus (if you are a python guy which learns max) and use pymxs for stuff that are not exposed or stuff that you know how to do easier in maxscript but you need to be in a python environment. (c++ sdk is the best root to take but the most difficult in my opinion for a non programmer or someone that does not know max inside out)

 

Enjoy,

har1sf0x

0 Likes