Nuke save / restore script editor input

by on Jan.24, 2015, under Nuke, Python

This is something that has bugged me since i started working with nuke, if you doing a little interactive scripting, if you forgot to copy/paste it to your script editor, then it was gone on load / nuke exit.

Her is a snap shot of the code i have in my site , that is in the NUKE_PATH:

# find the script editor:
import PySide
import PySide.QtGui as QtGui
import os
# get the current qtgui instance
nuke_app = QtGui.QApplication.instance()
# global vars
temp_dir = os.environ['NUKE_TEMP_DIR']
saved_text = '%s/nuke_script_editor.txt' % temp_dir

def get_script_editor():
              returns the QTextDocument which is the input area for the script editor
       # get all the widgets
       all_widgets = nuke_app.allWidgets()
       script_editor = None
       for w in all_widgets:
           name =  w.objectName()
           # lots of the wigets are not named, ignore them
           if not len(name) == 0:
              if name == 'Script Editor.1':
                   script_editor = w
       # get plain text:
       #get the QTextDocument correctly from the 
       txt_doc = None
       for child in script_editor.children():
           if isinstance(child,PySide.QtGui.QTextDocument):
               txt_doc = child
       return txt_doc

def save_script_editor():
              saves the data from the script edotor to disk
       script_editor = get_script_editor()
       text = script_editor.toPlainText()
       fid = open(saved_text,'w')
       print "script editor saved to: ",saved_text

def restore_script_editor():
              restore the saved script editor data
       script_editor = get_script_editor()
       text = open(saved_text,).read()
def checkRootCallbacksSet():
              setup all the callbacks
       if nuke.Root().knob('onScriptClose').getValue() == '':
           nuke.addOnScriptClose(save_script_editor, nodeClass='Root')
       if nuke.Root().knob('onScriptLoad').getValue() == '':
           nuke.addOnScriptLoad(restore_script_editor, nodeClass='Root')

nuke.addOnCreate(checkRootCallbacksSet, nodeClass='Root')

So a quick explanation for what im doing.
Using the QApplication.instance(), im getting the Nuke app, from here i have a convenience method “get_script_editor” that i use to get the QTextDocument that nuke is using to store the script editor data.
I then have 2 methods for saving the data to disk and reading it back from disk.

Then to tie it all together, i use nukes call backs to set it so, when nuke loads for the first time or loads a nuke script, it loads the data from disk. I then use the script close function, this works for either a save / clear or closing the ui, it will write out the script editor data to disk.

I have tested this with nuke 7.0v9, but it should work with all versions of nuke.

Leave a Comment :, , , more...

Capturing Nuke’s stdout and err to a file

by on Jan.20, 2015, under Nuke, Python

Something that has bothered me for quite some time, is not being able to capture Nuke’s STDOUT and STDERR, to a file ot ticket, so that when the Artist come accross an issue and none of the TD’s can help we can save it to a ticket or log for when someone has time.

I was reading through some of the python script in nuke an came accross what i was after at the bottom of:

C:\Program Files\Nuke<version>\plugins\

So in our site, i have added the following code that is executed  after the above script is run by nuke:


# save to an env, so that nuke and any threads that share the environment can find the logger
log_path = os.environ['NUKE_LOGGING_PATH']

import logging
logger = logging.getLogger()
hdlr = logging.FileHandler(log_path)
formatter = logging.Formatter('%(levelname)s %(message)s') #%(asctime)s

# stream redirectors
# pulled from: C:\Program Files\Nuke<version>\plugins\

class SESysStdIn(SERedirector, nuke.FnPySingleton):
  def readline(self):
    return ""

class SESysStdOut(SERedirector, nuke.FnPySingleton):
  def write(self, out):
    if not len(out.strip()) == 0:'\n'))

class SESysStdErr(SERedirector, nuke.FnPySingleton):
  def write(self, out):
    if not len(out.strip()) == 0:

if nuke.GUI:
  sys.stdin  = SESysStdIn(sys.stdin)
  sys.stdout = SESysStdOut(sys.stdout)
  sys.stderr = SESysStdErr(sys.stderr)

Then, when nuke ui starts it will create this log and write to it.
The “os.environ[‘NUKE_LOGGING_PATH’]” is because we define a new log for every nuke instance. this is defined when running the in your site config.

Leave a Comment :, more...

long time no post.

by on Aug.26, 2012, under Uncategorized

since may the ultimaker has taken over my life. which is not a bad thing. im going to be putting all the 3d printing exploits on a new blog here.


Leave a Comment more...

The 3D adventure begins….

by on Apr.24, 2012, under 3d Printing, Ultimaker

I have spent allot of time over the 6 months heavily researching 3d printers. My girlfriend and i had an idea we want to try and getting a 3d printer would be easier and cheaper than a cnc mill, plus we could use it at home.

I spent a ton of time looking at hte pro and cons of all the printers, there is a really good comparison at protoparadigm.

We ended out going with Ultimaker.

Today after a 5 week wait i have the box and im ready to start…. Im looking forward to where this jorney will take me.


Some useful links:





Leave a Comment more...

Useful links for scripting with Nuke

by on Mar.05, 2012, under Nuke, Python

I have been doing some scripting with Nuke, While the Documentation is great, not being a compositor by trade, knowing the lingo for items in nuke was a pain to get my head around.

So here are some useful links in case i forget what im looking for…

Creating custom panels / widgets and popups in nuke’s python:

Visual guide to nuke Knob types:

Nuke knob flags (These apply in  python aswell):

Some useful example scripts i have found:

Pyside webbroswer in nuke:

Split multichannel exrs into visible layers in nuke:

Query all the read nodes in a script:

Path swapping reads and write for a company that has 2 facilities. hmm its hard to guess:

Leave a Comment more...

PySide in maya 2010.

by on Jan.01, 2012, under Uncategorized

The last time i tired this it broke and it broke good, but this time when i installed pyside, i made sure it was the 64bit version from:

maya 2010 uses python 2.6, so make sure you have that installed and then install pyside on that.

Getting pyside to lauch in maya was as easy as:

**EDIT: Forgot to check to the instance..
Checking for the instance gets rid of this error:
# Error: RuntimeError: A QApplication instance already exists. #

<br />
import sys<br />
sys.path.append('C:/Python26/Lib/site-packages/')# this is where python and pyside exist.<br />
#from PySide import QtCore, QtGui<br />
from PySide.QtCore import *<br />
from PySide.QtGui import *<br />
# Create a Qt applicatio<br />
app = QApplication.instance()<br />
if app == None:<br />
    app = QApplication(sys.argv)<br />
# Create a Label and show it<br />
label = QLabel("Hello World")<br /><br />
# Enter Qt application main loop<br />
app.exec_()<br />
sys.exit()<br />

That loads hello world.

Next up, so you can load the .ui file in a python app with out having to compile the file.
Nathan Horne wrote a nice wrapper:

So then you can do this:

<br />
&amp;amp;amp;lt;pre&amp;amp;amp;gt;from PySide import QtCore, QtGui<br />
from PySide_loadUiType import loadUiType<br />
form_class,base_class = loadUiType('C:/temp/sgToolCreator02.ui')<br />
class AssetTaskCreator(form_class, base_class):<br />
    def __init__(self, parent=None):<br />
        super(AssetTaskCreator, self).__init__(parent)<br />
        self.setupUi(self)<br />
        #i have a button in the ui, i can now assign it a function that exist out side the ui:<br />
        # in the qt designer, i have called my button: createButton<br />
        # so if i want to assign something, i do it like this:<br />
        self.createButton.clicked.connect(self.onCreateButton)<br />

Then the rest of the ui goes below this point.
So if i make any changes to the layout of the ui, as long as i dont change the names of the ui elements that i have already assigned functions.
everything will work fine.

2 Comments more...

Replying to Shotgun messages on an Android phone.

by on Aug.03, 2011, under Coding, Python

On the project “Them Greeks“, we are using Shotgun for managing the project.

One of the things that annoys me the most is that i cannot reply straight to one of the shotgun emails from a note or Ticket.

To make it even more frustrating i have an android phone and using any of the browsers available i cannot for  the life of me make a reply….

So i decided to see if i could get the shotgun_api3 to run on SL4A python on my android. It worked. Next to write a little wrapper i could use to reply to messages i got in my email.

One of the things I had to do was get the email notes to include the note id, so that i could reply directly to the note via the api.

So to get this to work, you will need to have an android phone with SL4A installed on your android phone.

You will also need Python for Android installed.

Once you have these, you will need to get hold of the shotgun_api and copy it to your phone.
You will need to place the in your sl4a scripts dir, it should live here:


So here is my first version of the code, it will need to go into the same directory as above to run.

You can put it into a new directory, but you need to put the in there as well.

# setup imports.
import android,os,sys
# setup android
droid = android.Android()
# setup where to find the shotgun api on my phone
# I placed it in my sl4a scripts directory
scripts = os.getcwd()
scripts = scripts +'/scripts/'
from shotgun_api3 import Shotgun
# setup the api script and project im working on.
# this is how sg allows us to communicate with it.
SERVER_PATH = "server path"
SCRIPT_NAME = "script name here"
SCRIPT_KEY = "script key here"
# currently I am the only one using this.
# at a later date ill allow for other users.
userId = 188#kym watts
def replytoNote(noteId='',noteText='',userId=''):
 #  this is a base function for replying to a note in sg with some android ui
 #  bits added to the mix.
 noteID = droid.dialogGetInput('Value', 'enter noteid:', str(noteId)).result
 print type(noteID), noteID
 if not noteID == None:

  noteId = int(noteID)
  replyText = 'enter reply for note %s:' % (noteId)
  noteText = droid.dialogGetInput('Value', replyText, '').result
  #noteId = 974 #"pipeline - planning" note
  #noteText = 'Did you know if you put your mind to it.\nYou can do awesome things.\n\n'
  dReply = {
   'content': noteText
  print 'msg sent to note id:%s'%(noteId)
 print 'no note id returned.'

noteId = 1304
noteText = 'sent from my android phone.'

So some things that you need to update yourself before you run this for the first time:

SERVER_PATH = "server path"
SCRIPT_NAME = "script name here"
SCRIPT_KEY = "script key here"

These you need to get from your shogun server. It might be good in terms of tracking and debgging to create a api script just for this script.

userId = 188#kym watts

You will also need to know what your user name is , so that your reply’s will come from you and not the api script.

So thats pretty much it.
Some stuff i would like to add in the future is:

Functions to handle tickets and other things to reply to in shotgun.
Functions to deal with queue of reply’s till there is a valid connection with the sg server, this would mean i cn read my mail and do replys on the train and have them send when my phone has service again.

So what happens when you run this?

It will prompt you with 2 text inputs.

The First needs to know what the noteid is. This s the note you want to reply to.

The second is the text that you want to reply with. This text field will accept the enter key to seperate things with a new line.

If you can think of any other useful things this could have give me a shout at:

watts[ d o t]kym[ a t ]gmail[ d o t]com

Leave a Comment :, , , more...


by on Jul.24, 2011, under Uncategorized

Since April 2011 i have been activley involved with the animated short film called ThemGreeks.

What interests me most about the film is that everyone is working remotely, so there is a huge technology and infrastructure that has to be worked out to make this work.




Leave a Comment more...

arduino cont.

by on Jan.12, 2011, under Arduino, Coding, Electronics, Uncategorized

Some photos of the prototyping with the lcd and relay replacing the transistor, as well as my workspace:




More Photos and code soon.

Leave a Comment :, , , more...

Jump in to Arduino 002

by on Dec.10, 2010, under Uncategorized

I have been crazy busy at the moment with work  and organising for christmas holidays.

I have been hanging out every thursday at the site3 lab (makerspace) here in toronto. There are some good friendly folks here. I could learn alot from them.

I havent spent much time on the hardware, thou i have found a small box i want to try and fit the project in.

I have done a ton of code work, because i can do that on any computer i have access to with out the arduino connected.

Here is my latest iteration:

simple program for setting my canon cameras shutter time.

I do long welding glass exposures and this will come in handy so i wont need to hold the trigger down for too long.
The arduino will do that for me.

//start includes
#include <LiquidCrystal.h>
//end includes
// start shutter pins
#define SHUTTER 12    //definesthe shutter control
#define TRIGGER 11    // defines the trigger button
#define UP      10    // defines the +1 second button
#define DOWN    9    // defines the -1 second button
#define MODE    8     // defines the -1 second button
#define SECOND  1000  // defines how long a second is
// end shutter pins
// start shutter vars
long curTime = 1000; // sets the current time to be one second at the start of the program
int val = 0;           // this is the trigger button control
int modeButton = 0;
int upButton = LOW;
int downButton = LOW;
int currentMode = 0; // modes 1:,2:,3:
// end shutter vars
// shutter timing //
int idx = 15;
int lastMode = 99;
//String shutterSettings[]   = {"10'","9'30\"","9'","8'30\"","8'","7'30\"","7'","6'30\"","6'","5'30\"","5'","4'30","4'","3'30\"","3'","2'30\"","2'","1'30\"","1'","55\"","50\"","45\"","40\"","35\"","30\"","25\"","20\"","15\"","13\"","10\"","8\"","6\"","5\"","4\"","3\"2","2\"5","2\"","1\"6","1\"3","1","0\"8","0\"6","0\"5","0\"4","0\"3","NONE","4","5","6","8","10","13","15","20","25","30","40","50","60","80","100","125","160","200","250","320","400","500","640","800","1000","1250","1600","2000","2500","3200","4000","5000","6400","8000"};
String shutterSettings[]   = {"10'","9'30\"","9'","8'30\"","8'","7'30\"","7'","6'30\"","6'","5'30\"","5'","4'30","4'","3'30\"","3'","2'30\"","2'","1'30\"","1'","55\"","50\"","45\"","40\"","35\"","30\"","25\"","20\"","15\"","13\"","10\"","8\"","6\"","5\"","4\"","3\"","2\"","1\""};
//long delaySettings[]       = {600000000, 570000000, 540000000, 510000000, 480000000, 450000000, 420000000, 390000000, 360000000, 330000000, 300000000, 0, 240000000, 210000000, 180000000, 150000000, 120000000, 90000000, 60000000, 55000000, 50000000, 45000000, 40000000, 35000000, 30000000, 25000000, 20000000, 15000000, 13000000, 10000000, 8000000, 6000000, 5000000, 4000000, 3000000, 2000000, 1000000};
long delaySettings[]       = {600000, 570000, 540000, 510000, 480000, 450000, 420000, 390000, 360000, 330000, 300000, 0, 240000,210000, 180000, 150000, 120000, 90000, 60000, 55000, 50000, 45000, 40000, 35000, 30000, 25000, 20000, 15000, 13000, 10000, 8000, 6000, 5000, 4000, 3000, 2000, 1000};
// start lcd setup
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
// end lcd setup
// setup
void setup()
 Serial.begin(9600);      // open the serial port at 9600 bps:
 //                       // so we can see what the arduino is doing before we attach the lcd screen later.
 //lcd pins
 // set up the LCD's number of columns and rows:
 lcd.begin(16, 2);
 // Print a message to the LCD.
 //lcd.print("Shutter Cnt v004");
 printFirstRow("Shutter Cnt v004");
//  fuction to clear the whole first row.
void clearFirstRow()
 lcd.setCursor(0, 0);
 lcd.print("                ");
//  fuction to clear the whole second row.
void clearSecondRow()
 lcd.setCursor(0, 1);
 lcd.print("                ");
//    a function fo print stuff on the first line
void printFirstRow(String toPrint)
 lcd.setCursor(0, 0);
//    a function fo print stuff on the second line
void printSecondtRow(String toPrint)
 lcd.setCursor(0, 1);
//  pull the delay and the lcd text from the arrays using the index.
long setLCDReturnDelay(int id)
 String displayTime = shutterSettings[id];
 long delayTime = delaySettings[id];
 //  convert the time to something easy to understand on the lcd
 displayTime = displayTime.replace("'","m");
 displayTime = displayTime.replace("\"","sec");
 String strid = id;
 Serial.print("DEBUG: index:"+strid+"\n");
 Serial.print("DEBUG: lcd print:"+displayTime+"\n");
 //Serial.print("DEBUG: delay time:"+delayTime+"\n");
 return delayTime;

 get modes working.
 // long exposure
 // time lapse
 // time lapse + long exposure
 // sound trigger?
 single exposure
 time lapse + multi exposure
 sound trigger

 frre mode to set the trigger time, or canon defualt:
 30",25",20",15",13",10",8",6",5",4, 3"2,2"5,2",1"6,1"3,1" 0"8,0"6,0"5,0"4,0"3,,4,5,6,8,10,13,15,20,25,30,40,50,60,80,100,125,160,200,250,320,400,500,640,800,
 40",45",50", 55",1', 1'30",2',2'30",3',3'30",4',4'30,5',5'30",6',6'30",7',7'30",8',8'30",9',9'30,10'
 String shutterSettings[] = {"10'","9'30","9'","8'30"","8'","7'30"","7'","6'30"","6'","5'30"","5'","4'30","4'","3'30"","3'","2'30"","2'","1'30"","1'","55"","50"","45"","40"","35"","30"","25"","20"","15"","13"","10"","8"","6"","5"","4"," 3"2","2"5","2"","1"6","1"3","1" 0"8","0"6","0"5","0"4","0"3","NONE","4","5","6","8","10","13","15","20","25","30","40","50","60","80","100","125","160","200","250","320","400","500","640","800","1000","1250","1600","2000","2500","3200","4000","5000","6400","8000"};

 get down/ negative time sorted out
 //  currently if it is less than 1000 it become a negative.
 // cant delay in negative time.
 get counter working for trigger delay
 // currently delay = curtime.
 // should be a for loop ,
 // for every second
 print curseccond of total time
 delay second

 // display mode and times in real world seconds.
 // display high speed in mili seconds and canon shutter settings.
 // 1000 ms  || 1sec
 // 1ms || 1000/sec

// the loop function
void loop()
 // get the vars.
 upButton = digitalRead(UP);
 downButton = digitalRead(DOWN);
 val = digitalRead(TRIGGER);
 modeButton = digitalRead(MODE);
 // mode settings:
 if (modeButton == HIGH)
 if (currentMode >= 2)  // 2 is currently the highest setting.
 currentMode = 0;
 if ( currentMode != lastMode)
 if (currentMode == 0)
 printFirstRow("1:Single Exp");
 else if (currentMode == 1)
 printFirstRow("2:Time Lapse");
 else if (currentMode == 2)
 printFirstRow("3:Sound Trigger");
 lastMode = currentMode;
 String strCurMode = lastMode;
 Serial.print("DEBUG: current Mode:"+strCurMode+"\n");
 if (upButton == HIGH)
 // adds one second on to current time
 curTime = curTime + SECOND;
 Serial.print("DEBUG: up button in high\n");
 if (idx != 36)
 idx = 36;
 curTime = setLCDReturnDelay(idx);
 if (downButton == HIGH)
 /* a little more complex.
 the shutter doesnt understand negative numbers.... doesnt work like that
 Serial.print("DEBUG: down button high\n");
 if (idx != 0)
 idx = 0;
 //lcd.setCursor(0, 1);
 curTime = setLCDReturnDelay(idx);
 if (val == HIGH)
 Serial.print("DEBUG: value is high\n");
 // takes the photo.
 String secConvert = (curTime /1000);
 lcd.setCursor(0, 1);
 lcd.print("open for "+secConvert+"s");
 //need to convert to milliseconds in stead of micro seconds, some numbers too high.
 lcd.setCursor(0, 1);
 lcd.print("shutter closed");
 curTime = setLCDReturnDelay(idx);
 // delays the loop for a tad
 //Serial.print("DEBUG: end loop\n");

I have added some functions to help with clearing and adding data to my lcd.

Also 2 arrays that i treat like a python dictonary, like a key / value system.

Thanks to the folks on the arduino forum for the help.
I set up shutter times for everthing over a second, because those are the most usefull to me a t the moment.

Im going to start looking at the Aiko library for the next iteration.



I will try in the next few days to post some new photos.

Leave a Comment more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!