Stupid Python Trick: print statement revisited

December 20th, 2006 by Patrick Boucher - Viewed 4102 times - Popularity: 11%




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?

7 Responses to “Stupid Python Trick: print statement revisited”

  1. Meng-Yang Lu Says:

    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

  2. Patrick Boucher Says:

    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.

  3. Luc-Eric Says:

    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…

  4. Bernard Lebel Says:

    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

  5. Bernard Lebel Says:

    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

  6. Luc-Eric Says:

    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” )

  7. Denis Barmenkov Says:

    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!

Leave a Reply