how to read stdout without blocking

Hamish McKenzie hamish at valvesoftware.com
Tue Dec 22 13:13:37 EST 2009


I need to run a cmd line app from python whose run time can vary from a fraction of a second to minutes.  I need to be able to tell whether the process is still waiting, or whether it has stalled - and this is farily easily done by keeping an eye on whether its writing to stdout or not.  The process under working conditions will write to stdout fairly regularly.

So I want to bail out waiting for the process if it is no longer writing to stdout, but whenever I read stdout the script blocks and doesn't return until the process has finished.

This is under windows, python 2.5.  Can anyone help?  The code I'm using is below.


import subprocess
import time


TIMEOUT_PERIOD = 5  #timeout period in seconds

def run( *args ):
                cmdStr = 'somePotentiallyLengthyCmdHere'

                try:
                                proc = subprocess.Popen( cmdStr, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
                except OSError:
                                return False

                startTime = time.clock()
                stdoutAccum = []
                stderrAccum = []
                hasTimedOut = False
                while True:
                                ret = proc.poll()
                                newStdout = proc.stdout.read()
                                newStderr = proc.stderr.read()
                                print 'waiting...'

                                stdoutAccum += newStdout
                                stderrAccum += newStderr

                                #if the proc has terminated, deal with returning appropriate data
                                if ret is not None:
                                                if hasTimedOut:
                                                                if callable( RETURNED_CALLBACK ):
                                                                                try: RETURNED_CALLBACK( *args )
                                                                                except: pass

                                                return stdoutAccum + stderrAccum

                                #if there has been new output, the proc is still alive so reset counters
                                if newStderr or newStdout:
                                                startTime = time.clock()

                                #make sure we haven't timed out
                                curTime = time.clock()
                                if curTime - startTime > TIMEOUT_PERIOD:
                                                hasTimedOut = True
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20091222/32c80ef8/attachment.html>


More information about the Python-list mailing list