By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,127 Members | 1,160 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,127 IT Pros & Developers. It's quick & easy.

Catching stderr output from graphical apps

P: n/a

Here's a module to show stderr output from console-less Python
apps, and stay out of the way otherwise. I plan to make a ASPN
recipe of it, but I thought I'd run it by this group first.

To use it, import the module. That's it. Upon import it will
assign sys.stderr.

In the normal case, your code is perfect so nothing ever gets
written to stderr, and the module won't do much of anything.
Upon the first write to stderr, if any, the module will launch a
new process, and that process will show the stderr output in a
window. The window will live until dismissed; I hate, hate, hate
those vanishing-consoles-with-critical-information.
The code shows some arguably-cool tricks. To fit everthing in
one file, the module runs the Python interpreter on itself; it
uses the "if __name__ == '__main__'" idiom to behave radically
differently upon import versus direct execution. It uses TkInter
for the window, but that's in a new process; it does not import
TkInter into your application.

To try it out, save it to a file -- I call it "errorwindow.py" -
- and import it into some subsequently-incorrect code. For
example:

import errorwindow

a = 3 + 1 + nonesuchdefined

should cause a window to appear, showing the traceback of a
Python NameError.

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

if __name__ == '__main__':

from Tkinter import *
import Queue
queue = Queue.Queue(99)
def read_stdin(app):
while 1:
data = os.read(sys.stdin.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.empty = True
def on_first_write(self):
command = "%s %s %s" % (sys.executable, __file__, sys.argv[0])
self.pipe = os.popen(command, 'w')
def _write(self, data):
self.pipe.write(data)
os.fsync(self.pipe)
def write(self, data):
self.lock.acquire()
try:
if self.empty:
self.on_first_write()
self.empty = False
self._write(data)
finally:
self.lock.release()
sys.stderr = ErrorPipe()

Aug 10 '05 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Bryan Olson wrote:
Here's a module to show stderr output from console-less Python
apps, and stay out of the way otherwise. I plan to make a ASPN
recipe of it, but I thought I'd run it by this group first.


For what it's worth, I believe you've basically duplicated the
functionality available in wxPython in the standard App object.

-Peter
Aug 10 '05 #2

P: n/a
Peter Hansen wrote:
Bryan Olson wrote:
Here's a module to show stderr output from console-less Python
apps, and stay out of the way otherwise. I plan to make a ASPN
recipe of it, but I thought I'd run it by this group first.


For what it's worth, I believe you've basically duplicated the
functionality available in wxPython in the standard App object.


I'm not a wxPython user, but what I've heard is that it tries to
write stderr to a regular window within the process. Crashing
apps vanish from the screen, taking their error windows with
them. Most any GUI toolkit has to return to its event-loop
before it will update the screen, preventing it from showing
messages of fatal errors.
--
--Bryan
Aug 10 '05 #3

P: n/a
gry
Python 2.3.3, Tkinter.__version__'$Revision: 1.177 $'

Hmm, the error window pops up with appropriate title, but contains no
text.
I stuck an unbuffered write to a log file in ErrorPipe.write and got
only one line: Traceback (most recent call last):$

Any idea what's wrong?

-- George

Aug 10 '05 #4

P: n/a
gr*@ll.mit.edu wrote:
Python 2.3.3, Tkinter.__version__'$Revision: 1.177 $'

Hmm, the error window pops up with appropriate title, but contains no
text.
I stuck an unbuffered write to a log file in ErrorPipe.write and got
only one line: Traceback (most recent call last):$

Any idea what's wrong?


Darn. Are you on Windoze/Mac/Unix/, and what version?

If you can spare the time, could you please try:
import errorwindow
import sys

sys.stderr.write("Hello\nWorld.\n")

x = 7 + nosuchvariable
and tell me what happens?

Thanks.
--
--Bryan
Aug 10 '05 #5

P: n/a
gry
Linux -2.4.20 (x86), Python 2.3.3.
I did exactly as you suggested.
After the stderr.write, a window pops up with title "Error Stream from
run of errorwindow.pyc".
The window is otherwise blank.
Nothing more happens when I do the "x=7+nosuchvariable", I just get
the next python ">>>" prompt, but no error messages.
When I try to exit the python, e.g. sys.exit(), it hangs and I have to
Control-C.
After the control-C, the "Error Stream..." window goes away.

Any more suggestions? Perhaps we should take this to email, instead of
newsgroup?
This *is* something I would like to be able to use, if we can get it
working.

-- George

Aug 12 '05 #6

P: n/a

Thanks.

Yeah, guess I was naive to test on Windows and expect that kind
of process stuff to be portable. I'll be away from Linux for a
week or so, so this will take me a while.

Further bulletins as events warrant.

--
--Bryan
Aug 12 '05 #7

P: n/a
Bryan Olson wrote:

Thanks.

Yeah, guess I was naive to test on Windows and expect that kind
of process stuff to be portable. I'll be away from Linux for a
week or so, so this will take me a while.

Further bulletins as events warrant.


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.
Aug 12 '05 #8

P: n/a
Christopher Subich wrote:
Bryan Olson wrote:
Thanks.

Yeah, guess I was naive to test on Windows and expect that kind
of process stuff to be portable. I'll be away from Linux for a
week or so, so this will take me a while.

Further bulletins as events warrant.


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

--
Robert Kern
rk***@ucsd.edu

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter

Aug 13 '05 #9

P: n/a
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()
Aug 13 '05 #10

This discussion thread is closed

Replies have been disabled for this discussion.