Guification of console app

Fredrik Lundh fredrik at pythonware.com
Fri Nov 25 04:49:54 EST 2005


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






More information about the Python-list mailing list