Salida de subproceso Python en Windows?

Me estoy topando con algunas dificultades para obtener la salida de una tubería de subproceso stdout. Estoy lanzando un código de terceros a través de él, para extraer la salida del registro. Hasta una reciente actualización del código de terceros, todo funcionó bien. Después de la actualización, Python ha comenzado a bloquear de forma indefinida y no muestra ningún resultado. Puedo iniciar manualmente la aplicación de terceros bien y ver el resultado.

Una versión básica del código que estoy usando:

import subprocess, time from threading import Thread def enqueue_output(out): print "Hello from enqueue_output" for line in iter(out.readline,''): line = line.rstrip("\r\n") print "Got %s" % line out.close() proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) thread = Thread(target=enqueue_output, args=(proc.stdout,)) thread.daemon = True thread.start() time.sleep(30) 

Esto funciona perfectamente si sustituyo third_party.exe por este script:

 import time, sys while True: print "Test" sys.stdout.flush() time.sleep(1) 

Por lo tanto, no tengo claro qué hacer con la magia para que esto funcione con el comando original.

Estas son todas las variantes de la línea subprocess.Popen que he intentado sin éxito:

 proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=0) proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, shell=True) proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NEW_CONSOLE) si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, startupinfo=si) 

Edición 1: no puedo usar .communicate () en este caso. La aplicación que estoy lanzando sigue funcionando durante largos períodos de tiempo (días a semanas). La única forma en que podría probar .communicate () sería eliminar la aplicación poco después de que se inicie, lo que no creo que me dé resultados válidos.

Incluso la versión sin hilos de esto falla:

 import subprocess, time from threading import Thread proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, stderr=subprocess.PIPE) print "App started, reading output..." for line in iter(proc.stdout.readline,''): line = line.rstrip("\r\n") print "Got: %s" % line 

Edit 2: Gracias a jdi, los siguientes trabajos están bien:

 import tempfile, time, subprocess w = "test.txt" f = open("test.txt","a") p = subprocess.Popen("third_party.exe", shell=True, stdout=f, stderr=subprocess.STDOUT, bufsize=0) time.sleep(30) with open("test.txt", 'r') as r: for line in r: print line f.close() 

Primero, recomendaría que simplifique este ejemplo para asegurarse de que realmente pueda leer cualquier cosa. Retire la complicación del hilo de la mezcla:

 proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) print proc.communicate() 

Si eso funciona, genial. Entonces está teniendo problemas posiblemente con la forma en que está leyendo la salida estándar directamente o posiblemente en su hilo.

Si esto no funciona, ¿ha intentado también instalar stderr a stdout?

 proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1) 

Actualizar

Ya que dices que communicate() es un interlocking, aquí hay otro enfoque que puedes intentar ver si es un problema con el búfer interno de subproceso …

 import tempfile import subprocess w = tempfile.NamedTemporaryFile() p = subprocess.Popen('third_party.exe', shell=True, stdout=w, stderr=subprocess.STDOUT, bufsize=0) with open(w.name, 'r') as r: for line in r: print line w.close() 
 args = ['svn','log','-v'] def foo(info=''): import logging import subprocess import tempfile try: pipe = subprocess.Popen(args,bufsize = 0,\ stdout = subprocess.PIPE,\ stderr=subprocess.STDOUT) except Exception as e: logging.error(str(e)) return False while 1: s = pipe.stdout.read() if s: print s, if pipe.returncode is None: pipe.poll() else: break if not 0 == pipe.returncode: return False return True print foo() 

Este debería funcionar, no subprocesos, archivos temporales de magia.