Stupid Python Trick: print statement revisited
December 20th, 2006 by Patrick Boucher - Viewed 6431 times - Popularity: 14% [?]This must be the most stupid piece of code I’ve ever written in Softimage XSI but unfortunately, sometimes I can’t help myself. And, truth be told, some of these wacky possibilities are some of the reasons I prefer Python over other scripting languages for a lot of my work.
A while back I talked about the print statement inside XSI. Well, at some version, I don’t remember which, it stopped working. I miss it. I miss it mainly because some of the code I write is meant to be used outside XSI as much as inside it and using a the more ubiquitous print would be nice instead of Application.LogMessage. To get that functionality back I cooked up a little recipe that makes the print statement in XSI useful again.
Some Background
What happens when you use the print statement? Python has a builtin module called sys. This module has three very usefull objects called stdin, stdout and stderr. They are respectively used to get input, send output and send errors. When you do
1 | print 'Hello World!' |
in Python it can be roughly interpreted as
1 2 | sys.stdout.write('Hello World!') sys.stdout.write('\n') |
The Code
What my little reciepe does is replace sys.stdout with a wrapper to Application.LogMessage thus redirecting all print statements to the XSI log window. You can copy the code below to your script editor and run it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import sys from win32com.client import constants as c class xsiLogger(object): def __init__(self, verboseCode=c.siInfo): self.__verboseCode = verboseCode self.__buffer = '' def write(self, output): for letter in output: if letter == '\n': self.flush() else: self.__buffer += letter def flush(self): Application.LogMessage(self.__buffer, self.__verboseCode) self.__buffer = '' sys.stdout = xsiLogger() sys.stderr = xsiLogger(c.siError) print 'test\ntest2' print 'test5', print 'test6' print 'test8', 'test9' print print >> sys.stderr, 'test3' print 'test\ntest2' |
A Few Explanations
The wrapper is implemented as a class that has a write method. Python’s print statements thus wind up calling the write method of my xsiLogger instance that then calls Application.LogMessage. The first argument to the initialization of the the class is the type of message that will be logged in XSI (siInfo, siError, etc…). Because of this we can also replace sys.stderr by an instance of the xsiLogger but this time give it c.siError as it’s verboseCode and have it spew errors instead of info messages.
Neat huh?
Popularity: 14% [?]




Niiiiice! We were just discussing this topic here at work. And then I see this today. Yay! Time saver and makes my code more portable. Thanks for sharing!
-Lu
To tell you the truth, I didn”t really think someone would find this useful. I”m happy it helped.
If you figure out how to put this into a module and import it on demand, do post it. I tried and couldn”t get it to work, somehow substituting sys.stdout in the module didn”t affect my main code. Maybe I didn”t wrack my brain enough.
This is gonna help for XSI 6.0, because for many people python”s output went to the history log automatically in XSI 5.1.
This worked because their version of python was compiled with VC++ 2003 like XSI 5.1, and we re-route automatically the output of the VC++ run-time we use.
However XSI 6.0 is using the runtime of VC++ 2005 and so this has ceased to work because they are no longer using the same run-time version.
btw I”ve heard Softimage will publish a version of python for XSI on Win64 in the next few weeks…
For anyone who’s interested in the performance aspect of this, I’ve run a little test.
I remember when the print statement used to work, without any form of wrapping, that it was a lot faster than LogMessage(). I was really missing that speed.
import time
nTime1 = time.clock()
for i in range(1000):
print ‘something’
nTime2 = time.clock()
nElapsed1 = round( nTime2 – nTime1, 3 )
Application.LogMessage( nElapsed1 )
#INFO: 17.906
————————————————————
nTime3 = time.clock()
for i in range(1000):
Application.LogMessage( ‘something’ )
nTime4 = time.clock()
nElapsed2 = round( nTime4 – nTime3, 3 )
#INFO: 24.488
Cheers
Bernard
I got a question though.
Have you ever found a reliable way to know in what “environment” you’re running the code? I mean, have you found a way for the session to know if it’s taking place in command line shell or XSI?
Thanks
Bernard
Here is a reliable way to tell if you’re in XSI or not…
import os
if os.getenv( ‘SUMATRAPATH’ ) != None :
print( “you’re in XSI” )
else:
print( “you’re not in XSI” )
Old good recipe like this was unbuffered stdout and stderr:
http://www.faqts.com/knowledge_base/entry/versions/index.phtml?aid=4419
Also remember that you can restore original handles at any time (“in case they have been overwritten with a broken object” :) ):
sys.stdout=sys.__stdout__
sys.stderr=sys.__stderr__
Regards!