wxPython – Redirecting stdout / stderr

New programmers start using Python and wxPython each week. So it follows that every few months, I see people asking how to redirect stdout to a wx.TextCtrl on comp.lang.python or the wxPython mailing list. Since this is such a common question, I thought I would write an article about it. Regular readers will know that I have mentioned this concept before in a previous post.

Updated 2015-10-06

Originally I thought we’d need to create a class that can duck-type the writing API of a wx.TextCtrl. Notice that I use the so-called “new style” class that subclasses object (see code below).

Note that there’s only one method in this class (besides the initialization method, of course). It allows us to write the text from stdout or stderr to the text control. It should be noted that the write method is not thread-safe. If you want to redirect text from threads, then change the write statement like this:

In the code above, I create a read-only multi-line text control and a button whose sole purpose is to print some text to stdout. I add them to a BoxSizer to keep the widgets from stacking on top of each other and to better handle resizing of the frame. Next I instantiate the RedirectText class by passing it an instance of my text control. Finally, I set stdout to the RediectText instance, redir (i.e. sys.stdout=redir).

If you want to redirect stderr as well, then just add the following right after “sys.stdout=redir”: sys.stderr=redir

Improvements could be made to this, namely color coding (or pre-pending) which messages are from stdout and which are from stderr, but I’ll leave that as an exercise for the reader.

Recently it was pointed out to me that I shouldn’t need to jump through all these hoops. Instead, you can just redirect stdout directly to the TextCtrl widget because it has its very own write method. So here’s an example:

You will note that the code above no longer references the RedirectText class because we don’t need it. I am pretty sure that if you want to use threads, doing it this way will not be thread-safe. You’ll need to override the TextCtrl’s write method in a similar manner as was previously mentioned to make it safe. Special thanks goes to carandraug for pointing this out to me.

Thanks guys. Sorry my commenting system didn’t keep the formatting of your code very well. I think someone mentioned that I should try writing a redirect logging tutorial one time, but now I don’t have to.

– Mike

Anonymous

Just save a reference to stdout. Something like “self.stdoutRef = sys.stdout”. Then after you’ve redirected it, you can restore it by doing the reverse: sys.stdout = self.stdoutRef

Anonymous

What do you mean? It won’t be able to redirect anything until the MainLoop starts. If you have loops, put them in a function and call that after your application starts. You can use a button or just wx.CallAfter.