Ascii Menu I/O redirection

Hendrik van Rooyen mail at microcorp.co.za
Sat Sep 20 17:14:26 EDT 2008


I am writing a small application with a simple ascii based menu.

The menu is used to test individual functions, and to change some timings.
Otherwise the application just runs automatically, depending on command
line options.

I want to be able to redirect the menu.
The console, a serial port, or possibly a socket are target candidates.

Now a serial port and a socket are single files, so I need a "file"
that represents the console, to pass to the working functions.

Simply re-assigning for instance sys.stdin.write to point to
sys.stdout.write, and using sys.stdin as such a file does not work...

So I do the following:

<start code fragment>

class console(object):
    """
    This spoofs a single file like object, using stdout & - in
    (Minimalistic proof of concept implementation)
    """

    def __init__(self):
        self.read = sys.stdin.read
        self.readline = sys.stdin.readline
        self.write = sys.stdout.write
        self.flush = sys.stdout.flush
        self.closeout = sys.stdout.close # keep references to close
        self.closein = sys.stdin.close

    def close(self):
        self.closein()
        self.closeout()

# see if we must run, and how:

if __name__ == "__main__":

    if 'serial' in sys.argv:         # for RS-232 i/o to terminal
        f = open('/dev/ttyS0','r+b')
    else:                                 # console i/o
        f = console()

    sys.stderr  = f                  # redirect errors
    sys.stdout = f                  # redirect printing
    sys.stdin   = f                  # redirect raw_input stuff

    if 'menu' in sys.argv:         # test and timing changes
        menu_loop(menu_dict,f)      # (menu_dict is dispatch dict)
    else:                                # else just run the system
        autorun(menu_dict,f)

<end code fragment>

The above just shows a choice between console and serial as an
example - adding a socket option would be trivial.

This all seems to work, but I am asking here before I take the
trouble to turn it into production code, as I don't think it
is exactly a new problem.

Questions are:

    Is this a reasonable way of doing this kind of thing?
    Is there a canonical or better way of doing it?
    Am I missing something?

Using Linux only.

- Hendrik







More information about the Python-list mailing list