Guification of console app

Chris Mellon arkanes at gmail.com
Fri Nov 25 14:50:54 CET 2005


On 11/25/05, Fredrik Lundh <fredrik at pythonware.com> wrote:
> "metiu" wrote:
>
> > you have a compression utility that works as a standard *nix filter, so
> > it takes something from stdin and gives it back compressed to stdout
> > you like to use it as such, because it's nice to call it from the
> > command line
> >
> > now someone finds your utility quite nice, and says it would be nice to
> > have a GUI that shows you, for example, how long it will take to
> > compress...
> >
> > one way for sure it would be to fork your app, but this would be a
> > waste of time
> >
> > you'd like to reuse the compression library you've already written for
> > your GUI and your console, but:
> > - you'd like to have your console app clean and simple, such as:
> >
> > import sys
> > import CompressLib
> >
> > data = sys.stdin.read()
> > cdata = CompressLib.compress(data)
> > print cdata
> >
> > but you'd like the GUI to show some progress and status info.
>
> here's a simple, stupid, and portable solution.  the first script simulates
> your compression utility:
>
>     # compress.py (simulator)
>
>     import time, sys
>
>     for i in range(100):
>         sys.stdout.write(".")
>         sys.stderr.write("%d%% done\r" % i)
>         sys.stderr.flush()
>         time.sleep(0.1)
>
> (it prints "N% done" messages to stderr during the compression)
>
> the second script simulates your GUI.  the stuff in the while loop should
> be run by a timer/alarm function, at regular intervals:
>
>     import re, subprocess, time, os
>
>     class monitor:
>         # looks for "N% done" messages in the output stream
>         def __init__(self, tfile):
>             # could use dup/reopen instead
>             self.file = open(tfile.name, "r")
>         def poll(self):
>             pos = self.file.tell()
>             data = self.file.read()
>             if data:
>                 data = re.findall("(\d+)% done", data)
>             if not data:
>                 self.file.seek(pos)
>             else:
>                 return int(data[-1])
>         def close(self):
>             self.file.close()
>
>     ifile = open("in.txt", "rb")
>     ofile = open("out.dat", "wb")
>     tfile = open("out.tmp~", "wb")
>
>     p = subprocess.Popen(
>         "python compress.py",
>         stdin=ifile, stdout=ofile, stderr=tfile,
>         )
>
>     m = monitor(tfile)
>
>     while 1:
>         # this should be placed in a background task that's called
>         # every second or so
>         if p.poll() is not None:
>             print "DONE"
>             break
>         status = m.poll()
>         if status is not None:
>             # update status monitor
>             print status, "PERCENT DONE"
>         # wait a while before calling the background task again
>         print "."
>         time.sleep(0.5)
>
>     # clean up
>     ifile.close()
>     ofile.close()
>     m.close()
>     name = tfile.name
>     tfile.close()
>     os.remove(name)
>
> if you limit yourself to Unix only, you can simplify things quite a bit (e.g.
> using a pipe instead of the temporary file and use select to poll it, or use
> dup/reopen tricks to avoid opening the temporary file twice; if you do
> the latter, you can also use safe tempfile creation methods (see the
> "tempfile" method for details.  etc).
>
> hope this helps!
>
> </F>
>
>

If you are using wxPython, you can skip writing this scaffolding
yourself and use wx.Execute and wx.Process, which will allow you to
execute other processes and re-direct thier input and output. The
wxPython demo has an example.

>
> --
> http://mail.python.org/mailman/listinfo/python-list
>



More information about the Python-list mailing list