Trouble with adding a command to a menu item

936 views
Skip to first unread message

Tim Crowson

unread,
Apr 22, 2014, 9:48:32 AM4/22/14
to python_in...@googlegroups.com
Sorry to keep pestering...

I've got a custom command that I'm wanting to fire via a menuItem in a custom menu. The command runs fine when called via maya.cmds. But so far my menuItem insists on throwing a 'not defined' error for the command flag. Am I following the correct syntax for command flags in Python here?

My command is ShotSetup().

My menuItem code is:
mds.menuItem(p=shotsMenu, l='Shot Setup', c="ShotSetup()")

The menu initializes correctly, but when I run that menu item, I get the following error:

# Error: name 'ShotSetup' is not defined
# Traceback (most recent call last):
#   File "<maya console>", line 1, in <module>
# NameError: name 'ShotSetup' is not defined # 


-Tim

Tony Barbieri

unread,
Apr 22, 2014, 10:12:50 AM4/22/14
to python_in...@googlegroups.com
Hey Tim,

Rather than passing a string to to the command argument, pass a reference to the method itself:

mds.menuItem(p=shotsMenu, l='Shot Setup', c=ShotSetup)

This is a big difference between Maya's menu system and Softimages.  It also removes the requirement for the methods/functions to be available in the global scope which tripped me up when I began working with Softimage's menu system.



--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPh%3D1bmnYOThTfWPvz2ZC80AFHZAy9BZSCB9pbBXM9jEUYVxOQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.



--
-tony

Tim Crowson

unread,
Apr 22, 2014, 10:21:17 AM4/22/14
to python_in...@googlegroups.com
Thanks Toni, I actually tried that at one point and get the same error, except that the error happens when the menu tries to initialize. But I'm confident my command is working correctly. Perhaps it has to do with the order in which things get loaded? Maybe my menu plugin is being loaded before Maya loads the command plugin?

-Tim


Tim Crowson

unread,
Apr 22, 2014, 10:21:32 AM4/22/14
to python_in...@googlegroups.com
"Tony", sorry.... 

Tony Barbieri

unread,
Apr 22, 2014, 10:26:51 AM4/22/14
to python_in...@googlegroups.com
Np! :).

As long as the ShotSetup command is available in the scope where you are creating the menu item it should work.  When you say command, is this a Maya plugin registered command or just a simple python callable?



For more options, visit https://groups.google.com/d/optout.



--
-tony

Tim Crowson

unread,
Apr 22, 2014, 10:31:12 AM4/22/14
to python_in...@googlegroups.com
It's a Maya registered command.

But I got it working now... using:
cmds.menuItem(p=shotsMenu, l='Shot Setup', c=cmds.ShotSetup)
instead of:
cmds.menuItem(p=shotsMenu, l='Shot Setup', c=ShotSetup)

Which makes sense in hindsight...



Tony Barbieri

unread,
Apr 22, 2014, 10:41:32 AM4/22/14
to python_in...@googlegroups.com
Ah ok.  I thought it was just a python callable, not a full on maya registered command.  I'm just curious, why go through the trouble of developing a full on Maya plugin to do Shot setup?



For more options, visit https://groups.google.com/d/optout.



--
-tony

Tim Crowson

unread,
Apr 22, 2014, 10:46:41 AM4/22/14
to python_in...@googlegroups.com
Oh I dunno... to have it self-contained and neat I guess... something we can unload if necessary. To be honest I'm so new to dev work in Maya I'm totally open for suggestions. 


Tony Barbieri

unread,
Apr 22, 2014, 11:06:18 AM4/22/14
to python_in...@googlegroups.com
Hey Tim,

I was just curious if you needed the overhead of a full on Maya plugin, and not calling you out in anyway :)!!  I know you are new to the Maya thing so that's why I pointed it out.  I typically only go the plugin route when I need to create custom Maya nodes, otherwise I just stick to simple python modules that are made available in the python path.  There isn't a wrong way to do it, but as you mentioned before in a previous email, making sure everything is loaded that's needed is another hurdle that could be avoided by simply making sure your python code is available to be imported.

As far as unloading goes, not sure why you would need to unload something like a ShotSetup command, but I see where having used Workgroups in Soft could lead one to gravitate towards using plugins.  Most everything you'd need to do is most likely available via the python API (events, callbacks, UI, etc) without having to create a proper Maya plugin.  Also using python modules should help keep everything tidy and in one place.

These are just my opinions!  What you are doing is definitely not wrong, just may be unnecessary depending on your end goals.




For more options, visit https://groups.google.com/d/optout.



--
-tony

Tim Crowson

unread,
Apr 22, 2014, 11:16:27 AM4/22/14
to python_in...@googlegroups.com
Thanks! Yeah I'm definitely dragging along my Softimage experience here.... hehe...
So with respect to a menuItem firing a command, my understanding was that this command needed to be a registered Maya command... but this is not the case? (That was also one of the reasons I went with registering a ShotSetup command, was so I could call it easily from a menu item.)

-Tim


Tony Barbieri

unread,
Apr 22, 2014, 11:21:52 AM4/22/14
to python_in...@googlegroups.com
No sir, It is not the case.  Any python callable can be added to a Maya menu.  In the end they are simply Qt menus.  As I mentioned above if ShotSetup was just a callable python object available in the scope where you added your menuItem, you could just pass the reference to it to the command argument.  For example it could look like:

import tcrowson
...
mds.menuItem(p=shotsMenu, l='Shot Setup', c=tcrowson.ShotSetup)

Or however you'd want to structure it.





For more options, visit https://groups.google.com/d/optout.



--
-tony

Tim Crowson

unread,
Apr 22, 2014, 11:28:10 AM4/22/14
to python_in...@googlegroups.com
Ah ok, I gotcha now.... yeah that is simpler... I may move away from the plugin route...

New app, new API, new stuff to learn. Thanks so much!


Tim Crowson

unread,
Apr 22, 2014, 5:20:30 PM4/22/14
to python_in...@googlegroups.com
So I'm trying this out the way Tony suggested and I'm running into something  I've never encountered in Python before. I have a custom class in its own module that I import:

# myTestClass.py
class test():
def __init__(self):
print 'test'

And my menuItem goes like so:

import myTestClass
...
cmds.menuItem(p=shotsMenu, l='Shot Setup', command=myTestClass.test)

Maya complains when I run this menu item, saying:
# Error: __init__() takes exactly 1 argument (2 given)
# TypeError: __init__() takes exactly 1 argument (2 given) # 

Can someone enlighten on this?

Also, to give you an idea of the broader context here... I'm needing my custom class to actually spawn custom PySide tools, and so far the only working examples I've seen of custom PySide/PyQt tools have been run in the main loop like so...
if __name__ == "__main__":
    form = myPySideTool()
    form.show()

And I'm not sure what the best way is to get that called by my menuItem's command flag. Seems to be very picky.

Tony Barbieri

unread,
Apr 22, 2014, 5:24:31 PM4/22/14
to python_in...@googlegroups.com
Ahhh, If you have your class accept *args, **kwargs it should work.  I believe that the menu/maya is trying to pass some arguments to the callable.  Another option would be:

cmds.menuItem(p=shotsMenu, l='Shot Setup', command=lambda *args, **kwargs: myTestClass.test)



For more options, visit https://groups.google.com/d/optout.



--
-tony

Tony Barbieri

unread,
Apr 22, 2014, 5:25:26 PM4/22/14
to python_in...@googlegroups.com
Sorry, that should read:

cmds.menuItem(p=shotsMenu, l='Shot Setup', command=lambda *args, **kwargs: myTestClass.test())
--
-tony

Justin Israel

unread,
Apr 22, 2014, 11:32:10 PM4/22/14
to python_in...@googlegroups.com
Although I am not really sure why you would want to use a callback in the form of instantiating a class. 


Marcus Ottosson

unread,
Apr 23, 2014, 1:48:17 AM4/23/14
to python_in...@googlegroups.com
Seems slightly unconventional yes. You would have no way to reference that class afterwards (unless its a singleton) so why not simply use a function?



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Apr 23, 2014, 4:11:32 AM4/23/14
to python_in...@googlegroups.com
For more context about my comment, check out this really great pycon video called "Stop Writing Classes": https://www.youtube.com/watch?v=o9pEzgHorH0

He says if you have a class with 2 functions, and one of them is __init__, then you probably want a function

Pretty good watch.


finale.ad1492

unread,
Apr 23, 2014, 9:13:15 AM4/23/14
to python_in...@googlegroups.com
Hi, Tim,

there are 2 links might let you understand more about how to add UI widget callbacks.
I found them pretty useful when I started writing python script in maya.

ther first is from maya document, please scroll down of the page to find "positional arguments" part.

the second is from pymel document. some methods of adding callback functions have been listed,
and detailed with pros and cons.  this one should be very helpful!
http://download.autodesk.com/global/docs/maya2014/en_us/PyMel/ui.html

and if you really want to use object as a callback function,
you will probably have to implement __call__() method in you object.
you can take a look of pymel Callback object for detail.
but just like Marcus and Justin said, function is really capable of doing this, really!

hope these 2 links help!


Tim Crowson

unread,
Apr 23, 2014, 9:36:29 AM4/23/14
to python_in...@googlegroups.com
Thanks guys! I would much rather use a simple function for the command and not use the instance at all, but I wasn't able to get that to work until I read the section linked above on "positional arguments". I've got it working now and it's much more straightforward. The problem I was having was that if I had a function in my menu plugin called something like this:

def runThis():
    print 'running'

I was trying to assign it to a command like this:
cmds.menuItem(p=shotsMenu, l='Shot Setup', command=lambda *args, **kwargs: runThis)

But in fact, all I needed to do was this:

def runThis(*args):
    print 'running'
...
cmds.menuItem(p=shotsMenu, l='Shot Setup', command=runThis)


And that seems to be working fine. So no more dangling instances. Anything off about doing it this way?


-Tim



--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Tony Barbieri

unread,
Apr 23, 2014, 9:57:18 AM4/23/14
to python_in...@googlegroups.com
Nope, that should be fine!  

I only mentioned the lambda way of dealing with it if you didn't want your callable to accept *args and/or **kwargs.  I don't like to blanket add *args and **kwargs if it doesn't fit the design of my code.  In a lot of situations the code I'm writing is being used in multiple places, calling via a menu just being one of those, so I don't like the menu influencing how I have to write the code.

In the above example you gave using a lambda it should have worked if you added parentheses after runThis:

cmds.menuItem(p=shotsMenu, l='Shot Setup', command=lambda *args, **kwargs: runThis())



For more options, visit https://groups.google.com/d/optout.



--
-tony

Tim Crowson

unread,
Apr 23, 2014, 10:04:05 AM4/23/14
to python_in...@googlegroups.com
Yep I'm cooking with oil now! :-D 

Can't thank you guys enough for helping me with these first basic steps.

-Tim


Justin Israel

unread,
Apr 23, 2014, 3:54:51 PM4/23/14
to python_in...@googlegroups.com

The problem with lamdas though is they don't create a closure. So they will execute using the scope in which they run, which means if the function you are calling in there is not global then it might not be reachable. It just depends where you have defined that function.

Tony Barbieri

unread,
Apr 23, 2014, 4:09:26 PM4/23/14
to python_in...@googlegroups.com
Ah, good point Justin.



For more options, visit https://groups.google.com/d/optout.



--
-tony
Reply all
Reply to author
Forward
0 new messages