Question

I'd like to have a Python Cmd instance running in a separate thread, and be able to write input and read output from other parts of my program. In the constructor of Cmd, it is possible to specify stdin(default: sys.stdin) and stdout(default sys.stdout). I was expecting I could use the StringIO module for reading and writing, but the Cmd just reads the initial string, reaches EOF and exits. I need the same behaviour as with sys.stdin, thus that readline() will block until there is input to read.

I made this class, which works as I want:

import Queue

class BlockingLineIO():
    def __init__(self):
        self.closed = False
        self.queue = Queue.Queue()
        self.remainder = ""

    def write(self, s):
        for line in s.splitlines(True):
            if not line.endswith("\n"):
                self.remainder = line
            elif line != "":
                self.queue.put(self.remainder + line)
                self.remainder = ""

    def read(self):
        if self.queue.empty() and self.closed:
            return ""
        else:
            self.queue.put(False)
            return "".join(list(iter(self.queue.get, False)))

    def readline(self):
        if self.queue.empty() and self.closed:
            return ""
        else:
            return self.queue.get()

    def flush(self):
        pass

    def close(self):
        self.queue.put("")
        self.closed = True


def main():
    import cmd, threading
    my_cmd_class = type("Foo", (cmd.Cmd, object),
                        {'do_EOF': lambda self, line: self.stdout.write("Bye.\n") == None})
    my_cmd = my_cmd_class(stdin=BlockingLineIO(), stdout=BlockingLineIO())
    my_cmd.use_rawinput = False
    my_cmd.prompt = ""
    cmd_loop = threading.Thread(target=my_cmd.cmdloop)
    cmd_loop.start()
    my_cmd.stdin.write("help\n")
    print my_cmd.stdout.readline()
    print my_cmd.stdout.read()
    my_cmd.stdin.close()
    cmd_loop.join()
    print my_cmd.stdout.read()


if __name__ == '__main__':
    main()

The question:

Is the above a normal way of achieving what I need? Is there any standard class which I should use for piping stdin and stdout? I get the feeling that I am missing something.

No correct solution

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top