Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intercepting stdout of a subprocess while it is running

Tags:

If this is my subprocess:

import time, sys for i in range(200):     sys.stdout.write( 'reading %i\n'%i )     time.sleep(.02) 

And this is the script controlling and modifying the output of the subprocess:

import subprocess, time, sys  print 'starting'      proc = subprocess.Popen(     'c:/test_apps/testcr.py',     shell=True,     stdin=subprocess.PIPE,     stdout=subprocess.PIPE  )  print 'process created'  while True:     #next_line = proc.communicate()[0]     next_line = proc.stdout.readline()     if next_line == '' and proc.poll() != None:         break     sys.stdout.write(next_line)     sys.stdout.flush()      print 'done' 

Why is readline and communicate waiting until the process is done running? Is there a simple way to pass (and modify) the subprocess' stdout real-time?

I'm on Windows XP.

like image 468
Paul Avatar asked Feb 09 '09 05:02

Paul


People also ask

How do you capture stdout subprocess run?

To capture the output of the subprocess. run method, use an additional argument named “capture_output=True”. You can individually access stdout and stderr values by using “output. stdout” and “output.

What is stdout flush?

stdout. flush() forces it to “flush” the buffer, meaning that it will write everything in the buffer to the terminal, even if normally it would wait before doing so.

Does subprocess Popen need to be closed?

There the connection is not closed. So you do not need to close most probably. unrelated: you could use stdin=open('test. sql', 'rb', 0) to redirect child's stdin from the file without loading the whole file into your Python process first.

What does stdout subprocess PIPE mean?

stdout=PIPE means that subprocess' stdout is redirected to a pipe that you should read e.g., using process.communicate() to read all at once or using process.stdout object to read via a file/iterator interfaces.


2 Answers

As Charles already mentioned, the problem is buffering. I ran in to a similar problem when writing some modules for SNMPd, and solved it by replacing stdout with an auto-flushing version.

I used the following code, inspired by some posts on ActiveState:

class FlushFile(object):     """Write-only flushing wrapper for file-type objects."""     def __init__(self, f):         self.f = f     def write(self, x):         self.f.write(x)         self.f.flush()  # Replace stdout with an automatically flushing version sys.stdout = FlushFile(sys.__stdout__) 
like image 186
Kamil Kisiel Avatar answered Oct 11 '22 08:10

Kamil Kisiel


Process output is buffered. On more UNIXy operating systems (or Cygwin), the pexpect module is available, which recites all the necessary incantations to avoid buffering-related issues. However, these incantations require a working pty module, which is not available on native (non-cygwin) win32 Python builds.

In the example case where you control the subprocess, you can just have it call sys.stdout.flush() where necessary -- but for arbitrary subprocesses, that option isn't available.

See also the question "Why not just use a pipe (popen())?" in the pexpect FAQ.

like image 28
Charles Duffy Avatar answered Oct 11 '22 09:10

Charles Duffy