Two posts ago, I described how I wrote a function in Python that reads in a binary file from Labview. In my last post, I described using wxPython to write a GUI to process the data from those binary files. Naturally, I called the binary-file-reader function from the GUI. The problem is that the file reader prints a lot of information to the terminal, using Python print statements. None of this goes to the GUI, requiring the user to run the GUI from a terminal and keep an eye on the text output, which is inconvenient. However, I don’t want to modify the file reader to include GUI-specific code, because that would be less modular and less re-usable. Instead, I learned that Python has a very easy facility to redirect stdout, the default destination of the print statement. I modified the file reader as follows:
def readWGMfile(binaryFile, readSecondDerivatives, output=None): if output is not None: # allow the caller to hand in an alternative to standard out--for example, if # the caller is a GUI, redirect "print" statements to a GUI control print "Redirecting output..." import sys sys.stdout = output # rest of the function...
I added an optional argument to the file reader, allowing the caller to specify an object to replace stdout. The sys module is then used to redirect stdout to the object specified by the caller. There’s no change to the default usage of the function, but it’s a lot more flexible. Here is the object that I defined to capture the text:
class Monitor: """The Monitor class defines an object which is passed to the function readWGMfile(). Standard output is redirected to this object.""" def __init__(self, notifyWindow): import sys self.out = sys.stdout self._notifyWindow = notifyWindow # keep track of which window needs to receive events def write(self, s): """Required method that replaces stdout.""" if s.rstrip() != "": # don't need to be passing blank messages # self.out.write("Posting string: " + s.rstrip() + "n") wx.PostEvent(self._notifyWindow, TextMessageEvent(s.rstrip()))
The only requirement of the Monitor class is that it implement a write(self, string) method that accepts a string that would otherwise have gone to standard out. In my case, I post a special event which is sent to the specified window. Here is the definition of that event:
class TextMessageEvent(wx.PyEvent): """Event to notify GUI that somebody wants to pass along a message in the form of a string.""" def __init__(self,message): wx.PyEvent.__init__(self) self.SetEventType(TEXT_MESSAGE) self.message = message
Once again, I’m impressed with the way that Python makes hard things easy and very hard things possible. In my next post, I’ll give a quick example of how easy it is “thread” things in Python.