2012-05-02 10 views
5

Sto incontrando alcune difficoltà nell'ottenere l'output da una pipe di stdout del sottoprocesso. Sto lanciando qualche codice di terze parti tramite esso, al fine di estrarre l'output del registro. Fino a un recente aggiornamento del codice di terze parti, tutto ha funzionato bene. Dopo l'aggiornamento, python ha iniziato a bloccare a tempo indeterminato, senza mostrare alcun output. Posso avviare manualmente l'app di terze parti e vedere l'output.Output sottoprocesso Python su Windows?

Una versione di base del codice che sto utilizzando:

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) 

Questo funziona perfettamente se sostituisco third_party.exe in questo script:

import time, sys 

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

Così io sono poco chiaro come alla magia deve essere fatto per farlo funzionare con il comando originale.

Queste sono tutte le varianti della linea subprocess.Popen che ho provato senza successo:

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) 

Edit 1: Non posso effettivamente utilizzare .communicate() in questo caso. L'app che sto lanciando rimane in esecuzione per lunghi periodi di tempo (da giorni a settimane). L'unico modo in cui avrei potuto testare .communicate() sarebbe stato quello di uccidere l'app poco dopo il suo avvio, che non credo mi avrebbe dato risultati validi.

Anche la versione non-threaded di questo fallisce:

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: Grazie a JDI, le seguenti opere va bene:

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

È possibile che il programma di terze parti sia passato a scrivere su stderr? – jdi

+0

Non sembra essere il caso. Se intercetto invece stderr, succede la stessa cosa (però, vedo l'output dell'app sulla console, ma è solo la stampa, non sta attraversando Python). – devicenull

+0

Sembra che l'app abbia smesso di utilizzare l'output standard e stia scrivendo direttamente alla console. Se è così, non c'è molto che tu possa fare al riguardo. Sei in grado di verificare con il fornitore dell'app? –

risposta

5

Prima vi consiglio che a semplificare questo esempio per essere sicuro di poter effettivamente leggere qualcosa. Rimuovere la complicazione del thread dal mix:

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

Se funziona, ottimo. Quindi hai problemi con il modo in cui stai leggendo lo stdout direttamente o eventualmente nella tua discussione.

Se questo non funziona, hai provato a convogliare lo stderr allo stdout?

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

Aggiornamento

Dal momento che dici communicate() è deadlocking, qui è un altro approccio si può provare a vedere se il suo un problema con il buffer interno di sottoprocesso ...

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

Se ho avuto un errore con il thread, perché avrebbe funzionato per la mia semplice app di test, ma non la cosa reale? Non riesco a utilizzare la comunicazione, in quanto l'app in realtà non finisce. È un server e rimane in esecuzione per lunghi periodi di tempo. – devicenull

+0

@devicenull: Direi che la differenza è che lo script di test sta stampando 4 caratteri, lentamente, ogni secondo, mentre non ho idea del tipo di output che sta facendo l'app di terze parti. Potresti essere un deadlock dal buffer. Inoltre, quando si verificano problemi di questo tipo, è sempre consigliabile rimuovere il maggior numero possibile di variabili e assicurarsi che ogni passaggio funzioni correttamente. – jdi

+0

L'output in un file funziona perfettamente. Qualche idea sul perché funzioni, ma i tubi no? – devicenull

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

Questo dovrebbe funzionare, non thread, file temp di magia.

Problemi correlati