[Tutor] capture output from a subprocess while it is being produced

Albert-Jan Roskam sjeik_appie at hotmail.com
Tue Jun 14 16:03:31 EDT 2016


Hi,

I have a Tkinter program where I can fire up a commandline program which could run for quite a while (let's say 15 minutes or more). While the program is running, I would like to show the output that I normally see in the terminal (actually, the target platform is windows but now I am on Linux) in a text entry widget. The main purpose of this is to show that "something is happening". 

Anyway, below I tried to make a simplified version, without Tkinter. I fire up the commandline process in a separate thread, and I try to append lines of the output to a deque. The 'ls' command returns 2964 lines on my system. So I expect the deque to contain less items, because every time the while loop in process() sleeps, it would miss a few items. But it doesn't! It's like the ls output is returned as one chunk.

What am I doing wrong?

Thanks!

Albert-Jan


from subprocess import Popen, PIPE
from threading import Thread
from collections import deque
import sys
import time
import os.path


def process(dq):
    """Run a commandline program, with lots of output"""
    cwd = os.path.dirname(sys.executable)
    proc = Popen("ls -lF", cwd=cwd, shell=True, stdout=PIPE, stderr=PIPE)  
    #print len(proc.stdout.readlines())  # 2964
    output = errors = None
    while True:
        try:
            #output, errors = proc.communicate() # "Wait for process to terminate."  
            output = proc.stdout.read()  # docs: "Use communicate() rather than .stdin.write, .stdout.read or .stderr.read"
            errors = proc.stderr.read()
            proc.stdout.flush()
        except ValueError:
            break
        finally:
            if errors:
                raise RuntimeError(str(errors))

        if output:
            dq.append(output)
        time.sleep(0.0001)
        if not output:
            break

def update(dq):
    """This is supposed to return a new, not necessarily contiguous, chunk of output"""
    if dq:
        result = dq.pop()
        print time.asctime().center(79, "*")
        print result
        return result

if __name__ == "__main__": 
    
    dq = deque()
    output_thread = Thread(target=process, args=(dq,), name="output_thread")
    #output_thread.setDaemon(True)
    output_thread.start()
    
    
    lines = []
    while output_thread.is_alive():
        update(dq)
        time.sleep(0.1)
        if not dq: 
            break
        for item in dq:
            lines += item.splitlines()
    output_thread.join()
    print len(lines)
 		 	   		  


More information about the Tutor mailing list