Nuke & Python Beginners: Understanding object types and using the API reference.

 

In my previous article, Getting Started with python for Nuke, I threw a link to the official nuke python API reference at the end, without much explanation.

In this article, I’ll try to give you a bit of guidance on HOW to use that incredibly useful documentation.

Exploring Nuke Objects.

Python is an object oriented programming language, which is defined as such by Wikipedia:

Object-oriented programming (OOP) is a programming paradigm based on the concept of “objects”, which are data structures that contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods. A distinguishing feature of objects is that an object’s procedures can access and often modify the data fields of the object with which they are associated (objects have a notion of “this”). In object-oriented programming, computer programs are designed by making them out of objects that interact with one another.

[1][2] There is significant diversity in object-oriented programming, but most popular languages are class-based, meaning that objects are instances of classes, which typically also determines their type.

Many of the most widely used programming languages are multi-paradigm programming languages that support object-oriented programming to a greater or lesser degree, typically in combination with imperative, procedural programming. Significant object-oriented languages include Python, C++, Objective-C, Smalltalk,Delphi, Java, C#, Perl, Ruby and PHP.

Basically what we need to remember is that everything has an object type, or class.
If you did learn the basics of python you probably already know a few types: String for text, integers for whole numbers, lists, dictionaries, etc..

var1 = "Hello"
var2 = 3
var3 = 2.5
var4 = ['red', 'green', 'blue']
var5 = {"Shot 01": "final", "Shot 02": "WIP", "Shot 03": "director notes"}
print "Var 1 is of type: " +str(type(var1))
print "Var 2 is of type: " +str(type(var2))
print "Var 3 is of type: " +str(type(var3))
print "Var 4 is of type: " +str(type(var4))
print "Var 5 is of type: " +str(type(var5))
# Result:
Var 1 is of type: <type 'str'>
Var 2 is of type: <type 'int'>
Var 3 is of type: <type 'float'>
Var 4 is of type: <type 'list'>
Var 5 is of type: <type 'dict'>

This code should not be too hard to read, the only thing that you might be wondering about is the syntax of my print statement.
print “Var X is of type: ” should not be a problem to read, but what’s that coming afterwards? The + just tells python I want to print more than just the first string. In this case, I’m interested in the type of the object. There is a function for that: type(variable). That function itself returns an object of type “type”, which we convert into a string by using the function str(). It’s a little confusing at first, and my explanation might not be the clearest, but play around with it a little bit and you should get it.

Each type of object in python is defined by it’s class, and act differently when printed. Let’s take a look at a blur node in nuke:

node = nuke.createNode("Blur")
print node
print "---------------------TYPE--------------------------------------"
print type(node)
print "---------------------------------------------------------------"
print node.knob('size')
print "---------------------TYPE--------------------------------------"
print type(node.knob('size'))
# Result:
channels all
size 0
filter gaussian
quality 15
crop true
maskChannelMask alpha
maskChannelInput none
inject false
invert_mask false
fringe false
process_mask false
mix 1
---------------------TYPE--------------------------------------
<type 'Node'>
---------------------------------------------------------------
<WH_Knob object at 0x00000000161B31B0>
---------------------TYPE--------------------------------------
<type 'WH_Knob'>

As you can see, our node is of type “Node”, which is convenient because it pretty much makes sense. When trying to print this node, it prints some of the knobs of that node along with their values. If you take a closer look, you’ll notice that they correspond to the first tab of the Blur node, but do not include the knobs of the “Node” tab (label, hide_input, font, etc..)

When we look at the size knob, it returns an object of type “WH_Knob”. When we try to print it, it prints this weird result: “”.
What the hell does that mean?
Well, that means that whoever created the class WH_Knob, did not specify how that type of object should be printed, so Python tells us that it’s a WH_Knob object. The crazy number after is a memory address, which is more complex than what we need for daily use, even at higher levels, so let’s just ignore it.

Finding more about this object in the API reference

Ok, time to open the reference from the Foundry, over there: http://docs.thefoundry.co.uk/nuke/90/pythonreference/

It will look something like this:
nukeAPIref

In the first frame, the Table of Contents, you can filter which module you want to explore. Whatever module you select in (1) will be what shows up in (2).

The second frame is a list of all the objects contained in a specific module. By default, because we didn’t select any module in (1), this shows EVERY single type of object available in nuke. (correction: This lists everything that has been added to Python specifically for Nuke, it won’t show any of the basic python functions or other unrelated modules, even though they may be available in Nuke)

The third frame (3) is where the information shows up when you click one of the objects in (2).

I like to keep (1) on Everything, then I use my browser’s search function (ctrl+f on most browsers) to find what I’m looking for. Let’s try to find the WH_Knob we saw previously on our blur node.
My browser search will find it in window (2), under the name nuke.WH_Knob. After I click on it, a bunch of information shows up in (3):

ref_help

At the very top, you can see that WH_Knob is a class of the package Nuke.

Right under that there is a little schematic (A):  This shows that WH_Knob is a child of Array_Knob, which is itself a child of Knob.
Being a child of a class means that the object will inherit all of it’s parent’s attributes and functions.

Then comes a quick description: WH_Knob is a knob which holds width and height values. That’s useful, I suddenly have a much better idea of what we’re dealing with.

Instance Methods (B): In this table, we discover all the functions that have been added specifically for this object, along with a quick description of them.
Let’s make a quick change in our previously created Blur Node:

blur

and let’s try the specific functions for our knob:

print node.knob('size').names(0)
print node.knob('size').x()
print node.knob('size').x_at(10)
print node.knob('size').names(1)
print node.knob('size').y()
print node.knob('size').y_at(10)

I’ll let you run that by yourself to see what printed.
As you can see, we can use all of the functions listed on the page without too many issues.
For the functions __init__ and __new__ are not really for us to use directly, so in general I avoid using any functions in between “__”.

Finally (C) is the list of every function this object inherited from it’s parents. You’ll notice the value() function we’re familiar with.

Exploring our Blur Node

Let’s explore quickly our Blur node. We already know it is an object of type “Node”. Let’s see what the documentation tells us about Node objects.
There is no description, but there is a pretty big list of functions. One of them in particular interests me here:

knobs(self): Get a dictionary of (name, knob) pairs for all knobs in this node.

Let’s try it on our Blur node:

print node.knobs()
# Result:
{'layer': <Obsolete_Knob object at 0x00000000161B31E0>, 'invert_mask': <Boolean_Knob object at 0x00000000161B32A0>,
'help': <EvalString_Knob object at 0x00000000161B3390>, 'dope_sheet': <Boolean_Knob object at 0x00000000161B3588>,
'hide_input': <Boolean_Knob object at 0x00000000161B3540>, 'xpos': <Array_Knob object at 0x00000000161B34E0>,
'crop': <Boolean_Knob object at 0x00000000161B3228>, 'channels': <ChannelMask_Knob object at 0x00000000161B31C8>,
'note_font_color': <ColorChip_Knob object at 0x00000000161B34B0>, 'onCreate': <PythonKnob object at 0x00000000161B33A8>,
'quality': <Array_Knob object at 0x00000000161B3210>, 'updateUI': <PythonKnob object at 0x00000000161B33F0>,
'size': <WH_Knob object at 0x00000000161B31B0>, 'knobChanged': <PythonKnob object at 0x00000000161B33D8>,
'note_font': <Font_Knob object at 0x00000000161B3480>, 'tile_color': <ColorChip_Knob object at 0x00000000161B3438>,
'bookmark': <Boolean_Knob object at 0x00000000161B35A0>, 'selected': <Boolean_Knob object at 0x00000000161B34C8>,
'autolabel': <PythonKnob object at 0x00000000161B3408>, 'process_mask': <Boolean_Knob object at 0x00000000161B3330>,
'label': <Multiline_Eval_String_Knob object at 0x00000000161B3468>, 'mix': <Array_Knob object at 0x00000000161B3348>,
'onDestroy': <PythonKnob object at 0x00000000161B33C0>, 'inject': <Boolean_Knob object at 0x00000000161B3288>,
'indicators': <Array_Knob object at 0x00000000161B3528>, 'icon': <File_Knob object at 0x00000000161B3510>,
'channel': <Obsolete_Knob object at 0x00000000161B3198>, 'maskFrom': <Obsolete_Knob object at 0x00000000161B32E8>,
'maskChannelMask': <Channel_Knob object at 0x00000000161B3258>, 'enable': <Obsolete_Knob object at 0x00000000161B3360>,
'maskChannelInput': <Channel_Knob object at 0x00000000161B3270>, 'Mask': <Obsolete_Knob object at 0x00000000161B3240>,
'ypos': <Array_Knob object at 0x00000000161B34F8>, 'postage_stamp_frame': <Array_Knob object at 0x00000000161B35D0>,
'postage_stamp': <Boolean_Knob object at 0x00000000161B35B8>, 'disable': <Disable_Knob object at 0x00000000161B3570>,
'maskChannel': <Obsolete_Knob object at 0x00000000161B3300>, 'panel': <Obsolete_Knob object at 0x00000000161B3420>,
'maskFromFlag': <Boolean_Knob object at 0x00000000161B32D0>, 'name': <String_Knob object at 0x00000000161B3378>,
'cached': <Boolean_Knob object at 0x00000000161B3558>, 'fringe': <Boolean_Knob object at 0x00000000161B32B8>,
'mask': <Obsolete_Knob object at 0x00000000161B3318>, 'note_font_size': <Array_Knob object at 0x00000000161B3498>,
'filter': <Enumeration_Knob object at 0x00000000161B31F8>, 'gl_color': <ColorChip_Knob object at 0x00000000161B3450>}

BOOM! That’s a big ugly block of text. Actually, it would be even worse in Nuke because I added line returns here to make it a minimum readable.
Although, if we look a bit closer, we can see it contains a lot of information. This is a list of every single knob that our Node contains.
There is much more than we can see in the user interface.

Now that you know how to use the documentation, you should be able to figure out what kind of object everyone of these knobs is, and find out what function you can use on them!

Get to work!

Bonus:

Ok, node.knobs() didn’t get us the most beautiful output, you could use that instead:

def printKnobs(node):
    knobs = node.knobs()
    for key in sorted(knobs):
        print "%s : %s object" % (key, type(knobs[key]).__name__)

printKnobs(node)
By |2017-01-09T04:13:43+00:00April 6th, 2015|Nuke, Python, Tutorials|0 Comments

Share This Story, Choose Your Platform!

Leave A Comment