Maya - cmds.button command duplicated

Hey there,
For an export tool, I need to create a maya window.
The window creates a button for each successfull export to copy the output path.

Problem is, after the window is copied, all the buttons point to the same path.
When printing the output path at button creation, they are correct: the args seem to become wrong once the window is actually created.

Does anyone have a solution?
Thanks

targets = { 'A':{'abc_export_path':'L:/A.abc', 'namespace':'abc_A'},
            'B':{'abc_export_path':'L:/B.abc', 'namespace':'abc_B'},}

import clipboard
from maya import cmds

# create window
myWin = cmds.window(title='Abc Export', widthHeight=(150, 100), resizeToFitChildren=True, toolbox=True)
cmds.columnLayout( adjustableColumn=True )

# logg frame range
for root, data in targets.items():
    # logg success
    print ('creating UI button: ' + data.get('abc_export_path'))

    cmds.text(label = root )

    cmds.button( label='Copy Path' + root, align='center',
                command= lambda x: clipboard.copy( data.get('abc_export_path') ) )
                
# show window
cmds.showWindow(myWin)

So the problem is with loop variables get captured by the lambda.
What is happening is that data is being looked up when the lambda function is called (the button is clicked) not when the lambda function is defined.

One option would be to use functools.partial instead, or another option would be to pass data into the lambda at definition time:

command = lambda x, _data=data: clipboard.copy(_data.get('abc_export_path')))

1 Like

Hey there,

Thanks for the answer!

Ben

Hey there,
Getting the same problem again, this time with a slightly different setup

I have a dictionnary imported from a json with names and functions as string, such as:

d = {
'func1' : {
    'name': 'name 1',
    'command': 'function1( ....)',
    },
'func2' : {
    'name': 'name 2',
    'command': 'function2( ....)',
    },
}

I need to create a shelf button for each function, so I created a loop:

def _exec_py(s):
    exec(s)
    return

for k, v in d.items():
    addMenuItem(   label =  v.get('name'),
               command =   lambda x, d=json_data: _exec_py(v.get('command')),
               parent =    sub_sub_menu,   )

Problem is that, as @bob.w stated it, v is being looked up when lambda function is called, not created, so I get the last value in d for each button.

How can I create an unique lambda function for each key?

Thanks

just capture it into the args of the lambda first

for k, v in d.items():
    addMenuItem(
        label=v.get('name'), command=lambda x, d=json_data cmd=v.get(command): _exec_py(cmd),
        parent=sub_sub_menu
    )
1 Like

That worked perfectly! Thanks a lot