I'm using the subprocess module to start a subprocess and connect to it's output stream (stdout). I want to be able to execute non-blocking reads on its stdout. Is there a way to make .readline non-blocking or to check if there is data on the stream before I invoke .readline
? I'd like this to be portable or at least work under Windows and Linux.
here is how I do it for now (It's blocking on the .readline
if no data is avaible):
p = subprocess.Popen('myprogram.exe', stdout = subprocess.PIPE)
output_str = p.stdout.readline()
My problem is a bit different as I wanted to collect both stdout and stderr from a running process, but ultimately the same since I wanted to render the output in a widget as its generated.
I did not want to resort to many of the proposed workarounds using Queues or additional Threads as they should not be necessary to perform such a common task as running another script and collecting its output.
After reading the proposed solutions and python docs I resolved my issue with the implementation below. Yes it only works for POSIX as I'm using the
select
function call.I agree that the docs are confusing and the implementation is awkward for such a common scripting task. I believe that older versions of python have different defaults for
Popen
and different explanations so that created a lot of confusion. This seems to work well for both Python 2.7.12 and 3.5.2.The key was to set
bufsize=1
for line buffering and thenuniversal_newlines=True
to process as a text file instead of a binary which seems to become the default when settingbufsize=1
.ERROR, DEBUG and VERBOSE are simply macros that print output to the terminal.
This solution is IMHO 99.99% effective as it still uses the blocking
readline
function, so we assume the sub process is nice and outputs complete lines.I welcome feedback to improve the solution as I am still new to Python.
The select module helps you determine where the next useful input is.
However, you're almost always happier with separate threads. One does a blocking read the stdin, another does wherever it is you don't want blocked.
why bothering thread&queue? unlike readline(), BufferedReader.read1() wont block waiting for \r\n, it returns ASAP if there is any output coming in.
In my case I needed a logging module that catches the output from the background applications and augments it(adding time-stamps, colors, etc.).
I ended up with a background thread that does the actual I/O. Following code is only for POSIX platforms. I stripped non-essential parts.
If someone is going to use this beast for long runs consider managing open descriptors. In my case it was not a big problem.
Existing solutions did not work for me (details below). What finally worked was to implement readline using read(1) (based on this answer). The latter does not block:
Why existing solutions did not work:
I add this problem to read some subprocess.Popen stdout. Here is my non blocking read solution: