Catching stderr output from graphical apps

Bryan Olson fakeaddress at nowhere.org
Sun Aug 14 00:45:13 CEST 2005


Robert Kern wrote:
 > Christopher Subich wrote:
 >> If you can get a cross-platform solution, please re-annoucne it; this
 >> sounds like a really neat module to have handy for graphical programs.
 >
 >
 > Look at py.io[1]. It seems to have implemented a probably-cross-platform
 > solution. Please check it out and let c.l.py and the py mailing list
 > know if it works on Windows.
 >
 > [1] http://codespeak.net/py/current/doc/home.html

Thanks guys. I found I had a bootable Linux system. With some
stuff  from py.io, and *without* the fsync(), this one worked on
Windows and Linux in my not-so-extensive testing.

-- 
--Bryan



"""

     Import this module into graphical Python apps to provide a
     sys.stderr. No functions to call, just import it. It uses
     only facilities in the Python standard distribution.

     If nothing is ever written to stderr, then the module just
     sits there and stays out of your face. Upon write to stderr,
     it launches a new process, piping it error stream. The new
     process throws up a window showing the error messages.

"""

import sys
import os
import thread

import time

if __name__ == '__main__':

     from Tkinter import *
     import Queue
     queue = Queue.Queue(99)
     def read_stdin(app):
         fd = os.dup(sys.stdin.fileno())
         infile = os.fdopen(fd, 'r', 0)
         while 1:
             data = os.read(infile.fileno(), 2048)
             queue.put(data)
             if not data:
                 break
     class Application(Frame):
         def __init__(self, master=None):
             Frame.__init__(self, master)
             self.master.title("Error Stream from run of %s" % sys.argv[-1])
             self.pack(fill=BOTH, expand=YES)
             self.logwidget = Text(self)
             self.logwidget.pack(side=TOP, fill=BOTH, expand=YES)
             # Disallow key entry, but allow copy with <Control-c>
             self.logwidget.bind('<Key>', lambda x: 'break')
             self.logwidget.bind('<Control-c>', lambda x: None)
             self.after(200, self.start_thread, ())
         def start_thread(self, _):
             thread.start_new_thread(read_stdin, (self,))
             self.after(200, self.check_q, ())
         def check_q(self, _):
             go = True
             while go:
                 try:
                     data = queue.get_nowait()
                     if not data:
                         self.logwidget.configure(foreground ='#0000AA')
                         data = "\n==== File Closed ====\n"
                         go = False
                     self.logwidget.insert(END, data)
                     self.logwidget.see(END)
                 except Queue.Empty:
                     self.after(200, self.check_q, ())
                     go = False
     app = Application()
     app.mainloop()

else:

     class ErrorPipe(object):
         def __init__(self):
             self.lock = thread.allocate_lock()
             self.pipe = None
         def on_first_write(self):
             command = "%s %s %s" % (sys.executable, __file__, sys.argv[0])
             self.rawpipe = os.popen(command, 'w')
             fd = os.dup(self.rawpipe.fileno())
             self.pipe = os.fdopen(fd, 'w', 0)
         def write(self, data):
             self.lock.acquire()
             try:
                 if not self.pipe:
                     self.on_first_write()
                 self.pipe.write(data)
             finally:
                 self.lock.release()
     sys.stderr = ErrorPipe()
     # sys.stdout = ErrorPipe()





More information about the Python-list mailing list