Uso de subproceso con select y pty se bloquea al capturar resultados

Estoy tratando de escribir un programa de python que pueda interactuar con otros programas. Eso significa enviar stdin y recibir datos de stdout. No puedo usar pexpect (aunque definitivamente inspiró algo del diseño). El proceso que estoy usando ahora es este:

Adjuntar una pty a la salida estándar del subprocesoRecorrer hasta que el subproceso salga marcandosubprocess.pollCuando haya datos disponibles en la salida estándar, escriba esos datos inmediatamente en la salida estándar actual.¡Terminar!

He estado creando un prototipo de un código (a continuación) que funciona pero parece tener un defecto que me está molestando. Una vez que el proceso hijo se ha completado, el proceso padre se bloquea si no especifico un tiempo de espera al usarselect.select. Realmente preferiría no establecer un tiempo de espera. Simplemente parece un poco sucio. Sin embargo, todas las otras formas en las que he tratado de solucionar el problema no parecen funcionar. Pexpect parece superarlo usandoos.execv ypty.fork en lugar desubprocess.Popen ypty.openpty Una solución que no prefiero. ¿Estoy haciendo algo mal con la forma en que verifico la vida del subproceso? ¿Es mi enfoque incorrecto?

El código que estoy usando está abajo. Estoy usando esto en un Mac OS X 10.6.8, pero también necesito que funcione en Ubuntu 12.04.

Este es el subproceso del corredor.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()

Este es el código de subproceso.outputter.py. Las partes aleatorias extrañas son solo para simular un programa que genera datos a intervalos aleatorios. Puedes eliminarlo si lo deseas. No debería importar:

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()

Gracias por cualquier ayuda que todos puedan proporcionar!

Nota extra

pty se usa porque quiero asegurar que stdout no esté en búfer.

Respuestas a la pregunta(4)

Su respuesta a la pregunta