Search code examples
python-2.7user-interfacetypesuser-inputnuke

How to ensure that user can input any datatype (str, float, int, boolean...)?


So this is my first question on the forum and I hope I am doing it correct. General question: How can I ensure that python does not return any errors when writing a script that allows the user to input values of different datatypes depending on the context or parameter they want to change? More specific: I am new to python and want to write a script that allows users of The Foundry's Nuke to change values on multiple nodes of the same class at once. Depending on whether the desired parameter to change is a checkbox('bool'), and RGBA input ('4 floats')... the input has to be of a different type. Searching the forum I found that the type can be checked by type() function and compared in an if statement with the isinstance() function. I guess I could work with that, but the type of e.g. a Gradenode's multiply knob returns type 'AColor_Knob'. I expected something like float. And comparing it in an isinstance() does not give me a match regardless of the datatype I am comparing to.

Mainscript so far:

nukescripts.clear_selection_recursive()

userInput = nuke.getInput('Which type of nodes would you like to select? (!!!first char has to be capitalized!!!)',
                          'Shuffle')

matchingNodes = []

for each in nuke.allNodes():
    if each.Class() == userInput:
        matchingNodes.append(each)
    else:
        pass

for i in matchingNodes:
    i.setSelected(True)

nuke.message(str(len(
    matchingNodes)) + ' matching Nodes have been found and are now selected! (if 0 there either is no node of this type or misspelling caused an error!)')

userInput_2 = nuke.getInput('Which parameter of these nodes would you like to change? \n' +
                            '(!!!correct spelling can be found out by hovering over parameter in Properties Pane!!!)',
                            'postage_stamp')
userInput_3 = nuke.getInput('To what do you want to change the specified parameter? \n' +
                            '(allowed input depends on parameter type (e.g. string, int, boolean(True/False)))', 'True')

for item in matchingNodes:
    item.knob(userInput_2).setValue(userInput_3)

How I checked the datatypes so far:

selected = nuke.selectedNode()
knobsel = selected.knob('multiply')
print(type(knobsel))
#if type(knobsel) == bool:
if isinstance(knobsel, (str,bool,int,float,list)):
    print('match')
else:
    print('no match')

Solution

  • You can call a TCL command with nuke.tcl(). In TCL, everything is a string, so type is irrelevant (in some commands).

    p = nuke.Panel('Property Changer')
    p.addSingleLineInput('class', '')
    p.addSingleLineInput('knob', '')
    p.addSingleLineInput('value', '')
    p.show()
    
    node_class = p.value('class')
    knob_name = p.value('knob')
    knob_value = p.value('value')
    
    for node in nuke.allNodes(node_class):
        tcl_exp = 'knob root.{0}.{1} "{2}"'.format(node.fullName(),knob_name,knob_value)
        print tcl_exp
        nuke.tcl(tcl_exp)
    

    That should answer your question. There are many ways to approach what you're trying to do - if you want to keep it all in python, you can do type checking on the value of the knob. For example:

    b = nuke.nodes.Blur()
    print type(b.knob('size').value()).__name__
    

    This creates a Blur node and prints the string value of the type. Although I don't recommend this route, you can use that to convert the value:

    example = '1.5'
    print type(example)
    exec('new = {}(example)'.format('float'))
    print type(new) 
    

    An alternative route to go down might be building yourself a custom lookup table for knob types and expected values.

    Edit:

    TCL Nuke Commands: http://www.nukepedia.com/reference/Tcl/group__tcl__builtin.html#gaa15297a217f60952810c34b494bdf83d

    If you press X in the nuke Node Graph or go to File > Comp Script Command, you can select TCL and run:

    knob root.node_name.knob_name knob_value
    

    Example:

    knob root.Grade1.white "0 3.5 2.1 1"
    

    This will set values for the named knob.