2

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.

celtichindu
  • 33
  • 1
  • 4
  • `StringIO` is indeed not a stream but a finite file; what are you trying to achieve? – Martijn Pieters Jan 27 '13 at 12:47
  • So, no user will use your Cmd ? Only the program itself ? If it's the case you sall not use Cmd, Queue and some tuples sent over the Queue is sufficient to make your threads communicate. – Julien Palard Jan 27 '13 at 16:25
  • @JulienPalard I'd like to make a client and a server part, where a client can open a Cmd session similar to when running the Cmd locally on the server. So when the client connects, he will get the same output, and be able to send the same commands as when running the command locally. It should be possible to leave and reconnect with the session still living, until quit is sent. So clients should be able to either start a new cmdloop, or connect to an existing. – celtichindu Jan 28 '13 at 14:17
  • @MartijnPieters : Yes, so the question is: is there a standard class for making such streams, since StringIO is not what I need? – celtichindu Jan 28 '13 at 16:27

0 Answers0