Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Direct passing of cmdx.Node to vanilla cmds #55

Open
rigGitLikeYouDigGit opened this issue Apr 1, 2021 · 3 comments
Open

Direct passing of cmdx.Node to vanilla cmds #55

rigGitLikeYouDigGit opened this issue Apr 1, 2021 · 3 comments
Labels
enhancement New feature or request

Comments

@rigGitLikeYouDigGit
Copy link

Using cmds.listRelatives as example, are there plans to allow direct passing of cmdx.Node objects, without explicitly converting them?
At the moment this is possible using cmds.listRelatives( str( myNode ) ) but will error out if the object is passed directly.
I tried this myself a while ago, but providing str() on the object is not enough to fool cmds, you actually need to subclass str itself. My solution never worked too well, I wondered if you had any other ideas on it, or plans for this in general.

@mottosso
Copy link
Owner

mottosso commented Apr 2, 2021

Hi @edart76, I did actually experiment with this at first, I really wanted the interaction between cmdx and cmds to be completely seamless. But, and I can't remember exactly which, there were commands that just couldn't cope with anything that wasn't strictly a string. So subclassing didn't matter. :(

In the end, I resorted to having them all be str(node) for compatibility.

That said, I can't actually remember what commands didn't like it.. Maybe give it a try? If you do find that it does in fact work, then yes that would be great I think.

I tried this myself a while ago, but providing str() on the object is not enough to fool cmds, you actually need to subclass str itself.

Can you elaborate on this? Are there nodes/types in cmdx that cannot be passed with str()?

@mottosso mottosso added the enhancement New feature or request label Apr 2, 2021
@rigGitLikeYouDigGit
Copy link
Author

Sorry this took me a while, but I did a bit more of an investigation, I put a script that shows the results here: https://gist.github.com/edart76/3e231181ac0db58e536a12afda1bb206

In short there are two main avenues that can be explored : either you use normal objects, and only override __str__ and __repr__ to return an internal, mutable string value; or you go all in, inherit directly from str, and make them mutable (more importantly find a way to get Maya to recognise that they're mutable).

The first, simple approach actually seems enough to fool cmds - you can pass in a proxy object, change its internal/presented value (eg in response to a node's string name changing), and pass it in again to other cmds calls with absolutely no problems. I remembered this being more difficult, and it's possible there are special-case cmds out there, but I tried it with listHistory, listRelatives, rename, etc, and it worked fine.

OpenMaya is where it breaks down, because OpenMaya checks the type of arguments directly - if the literal object that you pass in is not a string, you get a typeerror.

For this I tried inheriting directly from str, and while this is now legal to pass to OM, there is a new issue: Maya's interpreter(?) does not update the string value of the object after the first time it is retrieved. You can override __str__ on the string object and return a new value, and python functions will pick it up fine - even passing it to cmds will still call __str__ on the object - the returned result is just ignored. This can be seen with cmds.warning(). If your string proxy obj first gives a value of "a", then as far as Maya is concerned, its value will always be "a".

This might be an artefact of string interning, it might be something else, but it's well beyond my knowledge for now. It's possible it could be solved by manually updating the memory addresses of the objects - I also tried monkeypatching the OM functions with a wrapper to convert the string objects before the functions are called, but since they're generated modules I couldn't find a way to assign the functions back to the classes.

Hopefully the script is clear enough, let me know if it's confusing at all.

I would also be VERY interested to try the first method in Python3, since we can now override __class__ , but I haven't found time to download 2022 yet :D

And sorry, before I didn't mean to say that cmdx doesn't work with calling str(), just that the __str__ method doesn't always register properly, as described.

Thanks

@mottosso
Copy link
Owner

The first, simple approach actually seems enough to fool cmds

This... is odd/interesting. Given cmdx.Node.__str__ also exists? If this is true, then cmdx should already work? :O

For this I tried inheriting directly from str, and while this is now legal to pass to OM, there is a new issue: Maya's interpreter(?) does not update the string value of the object after the first time it is retrieved.

I'm quite certain this is because OM is a C++ binding and it isn't getting the string's value from __str__ but rather from the internally stored, non-mutable, string value of the type itself. I'm actually quite surprised you got any of the maya.cmds function to call that, given those are also heading straight to C++, although as a MPxCommand rather than a direct Python SWIG binding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants