Maya python modules and mehtod naming


#1

hey guys,

I’m currently trying to wrap my head around an issue I’m having.

I like they way one can organize scripts and modules for different Maya Versions with the MAYA_MODULE_PATH and .mod files.
Thats why i also have some custom scripts stored and loaded this way

the .mod file for my python scripts reads as followed:
+ MAYAVERSION:2018 PLATFORM:win64 mrdebug 1.0 …/modules/mrdebug
+ MAYAVERSION:2017 PLATFORM:win64 mrdebug 1.0 …/modules/mrdebug

the path that is appended to sys.path this way is:
../modules/mrdebug/scripts

there i have my script sitting called. mrdebug.py
so in maya i can easily import this with
import mrdebug

now my problem starts.
thats the code thats in mrdebug.py:

import maya.cmds as mc

if (mc.window(windowID, q=True, exists=True)):
    mc.deleteUI(windowID)

windowID = "mrdebug"
window = mc.window(windowID, title="mrdebug", rtf=True)
windowLayout = mc.columnLayout()
mc.setParent(windowLayout)
mc.button(l="method_a", w=300, c="method_a")
mc.button(l="do_something", w=300, c="do_something")

mc.showWindow(windowID)


def method_a():
    print("this is method A")


def do_something():
    print("doing something")

Now what this does, is that while drawing the UI works fine and all, the method call results in an error because the method would need to be called with mrdebug.method_a() instead of just method_a().

I guess using:
from mrdebug import *
would do the trick, but i find it hard to believe thats the right way to handle this situation.
Can some experienced coder point me to a clean and professional solution for this problem?
I appreciate any help.
thx


#3

Hello,
You can add the function variable itself to the command flag of the mc.button function.

import maya.cmds as mc

WINDOW_ID = "mrdebug"


def method_a(*args):
    print("this is method A")


def do_something(*args):
    print("doing something")
   
    
def show():
    if mc.window(WINDOW_ID, q=True, exists=True):
        mc.deleteUI(WINDOW_ID)
    
    window = mc.window(WINDOW_ID, title="mrdebug", rtf=True)
    windowLayout = mc.columnLayout()
    mc.setParent(windowLayout)
    mc.button(l="method_a", w=300, c=method_a)
    mc.button(l="do_something", w=300, c=do_something)
    
    mc.showWindow(WINDOW_ID)

Now to display your ui you can run the following code

import mrdebug
mrdebug.show()

#4

thx, i saw that my code had issues anyway.

Your example is exactly what i was trying to do before.
put the gui in a seperate method and call this from maya, but for some reason it didn’t work.

I’ll have to fiddle around some more thx for the fast reply


#5

The difference is the following:

You were calling the functions by their name as a string:

mc.button(l="method_a", w=300, c="method_a")
mc.button(l="do_something", w=300, c="do_something")

You can just give the command flag the function variable to run, notice the missing string quotes.

mc.button(l="method_a", w=300, c=method_a)
mc.button(l="do_something", w=300, c=do_something)

#6

ah thx, yeah i think thats exactly the problem.
see i was using a script from the web i was trying to integrate with the MAYA_MODULE_PATH

its working fine when copy and pasted into the script editor (python) and executed, just like this script:

import maya.cmds as mc


def method_a(*args):
    print("this is method SKjhdkjdshfdsf")


def do_something(*args):
    print("bla")


WINDOW_ID = "mrdebug"
if (mc.window(WINDOW_ID, q=True, exists=True)):
    mc.deleteUI(WINDOW_ID)

window = mc.window(WINDOW_ID, title="mrdebug", rtf=True)
windowLayout = mc.columnLayout()
mc.setParent(windowLayout)
mc.button(l="A", w=300, c="method_a()")
mc.button(l="B", w=300, c="do_something()")

mc.showWindow()

But as soon as i load it as a module, the Quotes you mentioned stop working,
can you help me understand the reason it works in the script editor but not when loaded as a module?
again, thanks for helping me out


#7

so when just using:
import debugmr

gui comes up but fails on button press:
# Error: NameError: file <maya console> line 1: name 'method_a' is not defined #

but as soon as I:
from debugmr import *

it works fine


#8

Replace:

mc.button(l="A", w=300, c="method_a()")
mc.button(l="B", w=300, c="do_something()")

with:

mc.button(l="A", w=300, c=method_a)
mc.button(l="B", w=300, c=do_something)

You are still giving the command flag a string variable. You need to give it the actual function.


#9

I understand, what do I do about custom scripts from the web that use a string as the command argument.
which is working fine when not loading as a module?

And how would I pass an argument to my method?


#10

If the custom script from the web is a python script.
You can import that script in your mrdebug.py and use the function when you create the button

import randomTool
mc.button(l="A", w=300, c=randomTool.randomFunction)

If the custom script from the web is a mel script.
You can simply source the mel in your code.

from maya import mel
mel.eval("source <PATHTOMEL>;")

And then use the function name as a string in your button.

mc.button(l="A", w=300, c="randomMelFunction()")

You can pass arguments using lambda or partial
See here the partial example

from functools import partial

def method_a(name, age, *args):
    print name, age

mc.button(l="method_a", w=300, c=partial(method_a, "Bert", 32))


#11

I found this script for example: https://www.highend3d.com/maya/script/joint-on-curve-tool-for-maya :
It hardcodes the module name in the command. making it dependent under which name the module is loaded right. (line 94)
b1 = cmds.button(label = "Get curvy!", w = 205, h = 30, c = nm_python_jointOnCurveTool.nm_python_jointOnCurve_proc()', parent = grid )

how do i handle that? Do i use name instead to make it dynamic?
b1 = cmds.button(label = "Get curvy!", w = 205, h = 30, c = __name__+'.nm_python_jointOnCurve_proc()', parent = grid )


#12

thx, I think what got me confused is, that a lot of people seem to be working with strings for the command.
I’ll try to stick to the way you described it, seems a lot cleaner this way


#13

String commands are used when you want to call a mel function, but you don’t use strings for python functions, you pass in the function directly. Whenever you pass a command to a button, that command isn’t executed until you actually click the button. Maya handles strings and python functions differently.

So for cmds.button(label='My Button', c='myFunction()' ) where the command is a string, the result you get would be the same as executing mel.eval( 'myFunction()' ) whereas with a python function, cmds.button(label='My Button', c=myFunction) would give you the same result as calling myFunction()


#14

thanks for the explanation, I started using the partial command, because I need to pass arguments to my method.
It feels a bit wierd to have to do that, just to call methods with certain arguments passed, via buttons.


#15

TLDR – never use the string form of a command. It’d always an invitation to problems because things that work in the listener when you are testing will fail when run from an imported module.

There’s a lot more here and here on the right way to hook up UI commands.