Ejecute el comando y obtenga su stdout, stderr por separado en tiempo casi real como en una terminal

Estoy tratando de encontrar una manera en Python para ejecutar otros programas de tal manera que:

El stdout y el stderr del programa que se está ejecutando se pueden registrar por separado.El stdout y stderr del programa que se está ejecutando se puede ver casi en tiempo real, de modo que si el proceso secundario se bloquea, el usuario puede ver. (es decir, no esperamos que se complete la ejecución antes de imprimir el stdout / stderr al usuario)Criterios adicionales: el programa que se está ejecutando no sabe que se está ejecutando a través de Python y, por lo tanto, no hará cosas inesperadas (como fragmentar su salida en lugar de imprimirlo en tiempo real o salir porque requiere un terminal para ver su salida) . Este pequeño criterio significa que tendremos que usar una empanada, creo.

Esto es lo que tengo hasta ahora ... Método 1:

def method1(command):
    ## subprocess.communicate() will give us the stdout and stderr sepurately, 
    ## but we will have to wait until the end of command execution to print anything.
    ## This means if the child process hangs, we will never know....
    proc=subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable='/bin/bash')
    stdout, stderr = proc.communicate() # record both, but no way to print stdout/stderr in real-time
    print ' ######### REAL-TIME ######### '
    ########         Not Possible
    print ' ########## RESULTS ########## '
    print 'STDOUT:'
    print stdout
    print 'STDOUT:'
    print stderr

Método 2

def method2(command):
    ## Using pexpect to run our command in a pty, we can see the child's stdout in real-time,
    ## however we cannot see the stderr from "curl google.com", presumably because it is not connected to a pty?
    ## Furthermore, I do not know how to log it beyond writing out to a file (p.logfile). I need the stdout and stderr
    ## as strings, not files on disk! On the upside, pexpect would give alot of extra functionality (if it worked!)
    proc = pexpect.spawn('/bin/bash', ['-c', command])
    print ' ######### REAL-TIME ######### '
    proc.interact()
    print ' ########## RESULTS ########## '
    ########         Not Possible

Método 3:

def method3(command):
    ## This method is very much like method1, and would work exactly as desired
    ## if only proc.xxx.read(1) wouldn't block waiting for something. Which it does. So this is useless.
    proc=subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable='/bin/bash')
    print ' ######### REAL-TIME ######### '
    out,err,outbuf,errbuf = '','','',''
    firstToSpeak = None
    while proc.poll() == None:
            stdout = proc.stdout.read(1) # blocks
            stderr = proc.stderr.read(1) # also blocks
            if firstToSpeak == None:
                if stdout != '': firstToSpeak = 'stdout'; outbuf,errbuf = stdout,stderr
                elif stderr != '': firstToSpeak = 'stderr'; outbuf,errbuf = stdout,stderr
            else:
                if (stdout != '') or (stderr != ''): outbuf += stdout; errbuf += stderr
                else:
                    out += outbuf; err += errbuf;
                    if firstToSpeak == 'stdout': sys.stdout.write(outbuf+errbuf);sys.stdout.flush()
                    else: sys.stdout.write(errbuf+outbuf);sys.stdout.flush()
                    firstToSpeak = None
    print ''
    print ' ########## RESULTS ########## '
    print 'STDOUT:'
    print out
    print 'STDERR:'
    print err

Para probar estos métodos, deberáimport sys,subprocess,pexpect

Pexpect es Python puro y se puede tener con

sudo pip install pexpect

Creo que la solución involucrará el módulo pty de python, que es algo así como un arte negro que no puedo encontrar a nadie que sepa cómo usarlo. Quizás SO sabe :) Como aviso, le recomiendo que use 'curl www.google.com' como comando de prueba, porque por algún motivo imprime su estado en stderr: D

ACTUALIZACIÓN-1:
OK, entonces la biblioteca pty no es apta para el consumo humano. Los documentos, esencialmente, son el código fuente. Aquí no funcionará ninguna solución presentada que esté bloqueando y no asincrónica. El método Threads / Queue de Padraic Cunningham funciona muy bien, aunque no es posible agregar soporte pty, y es 'sucio' (para citar #python de Freenode). Parece que la única solución adecuada para el código estándar de producción es usar el marco Twisted, que incluso admite pty como un interruptor booleano para ejecutar procesos exactamente como si fueran invocados desde el shell. Pero agregar Twisted a un proyecto requiere una reescritura total de todo el código. Esto es un fastidio total: /

ACTUALIZACIÓN-2:

Se proporcionaron dos respuestas, una de las cuales aborda los dos primeros criterios y funcionará bien donde solo necesita tanto stdout como stderr usandoThreads and Queue. La otra respuesta usaselect, un método sin bloqueo para leer descriptores de archivos, y pty, un método para "engañar" al proceso generado para que crea que se está ejecutando en un terminal real como si se ejecutara directamente desde Bash, pero puede o no tener efectos Desearía poder aceptar ambas respuestas, porque el método "correcto" realmente depende de la situación y de por qué estás subprocesando en primer lugar, pero, por desgracia, solo podía aceptar una.

Respuestas a la pregunta(3)

Su respuesta a la pregunta