Использование подпроцесса с select и pty зависает при захвате вывода

Я пытаюсь написать программу на Python, способную взаимодействовать с другими программами. Это означает отправку стандартного ввода и получение данных стандартного вывода. Я не могу использовать pexpect (хотя это определенно вдохновило некоторые дизайны). Процесс, который я сейчас использую, заключается в следующем:

Attach a pty to the subprocess's stdout Loop until the subprocess exits by checking subprocess.poll When there is data available in the stdout write that data immediately to the current stdout. Finish!

Я прототипировал некоторый код (ниже), который работает, но, похоже, у меня есть один недостаток, который меня беспокоит. После завершения дочернего процесса родительский процесс зависает, если я не указываю время ожидания при использованииselect.select, Я действительно предпочел бы не устанавливать тайм-аут. Это кажется немного грязным. Однако все остальные способы, которые я пытался обойти, не работают. Pexpect обходит это, используяos.execv а такжеpty.fork вместоsubprocess.Popen а такжеpty.openpty решение я не предпочитаю. Я делаю что-то не так с тем, как я проверяю жизнь подпроцесса? Мой подход неверен?

Код, который я использую, приведен ниже. Я использую это на Mac OS X 10.6.8, но мне нужно, чтобы оно работало и на Ubuntu 12.04.

Это бегун подпроцессаrunner.py:

import subprocess
import select
import pty
import os
import sys

def main():
    master, slave = pty.openpty()

    process = subprocess.Popen(['python', 'outputter.py'], 
            stdin=subprocess.PIPE, 
            stdout=slave, stderr=slave, close_fds=True)

    while process.poll() is None:
        # Just FYI timeout is the last argument to select.select
        rlist, wlist, xlist = select.select([master], [], [])
        for f in rlist:
            output = os.read(f, 1000) # This is used because it doesn't block
            sys.stdout.write(output)
            sys.stdout.flush()
    print "**ALL COMPLETED**"

if __name__ == '__main__':
    main()

Это код подпроцессаoutputter.py. The strange random parts are just to simulate a program outputting data at random intervals. You can remove it if you wish. It shouldn't matter:

import time
import sys
import random

def main():
    lines = ['hello', 'there', 'what', 'are', 'you', 'doing']
    for line in lines:
        sys.stdout.write(line + random.choice(['', '\n']))
        sys.stdout.flush()
        time.sleep(random.choice([1,2,3,4,5])/20.0)
    sys.stdout.write("\ndone\n")
    sys.stdout.flush()

if __name__ == '__main__':
    main()

Спасибо за любую помощь, которую вы все можете предоставить!

Extra note

pty используется, потому что я хочу убедиться, что stdout не буферизован.

Ответы на вопрос(4)

Ваш ответ на вопрос