Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Popen.communicate

I have a script named 1st.py which creates a REPL (read-eval-print-loop):

print "Something to print" while True:     r = raw_input()     if r == 'n':         print "exiting"         break     else:         print "continuing" 

I then launched 1st.py with the following code:

p = subprocess.Popen(["python","1st.py"], stdin=PIPE, stdout=PIPE) 

And then tried this:

print p.communicate()[0] 

It failed, providing this traceback:

Traceback (most recent call last):   File "1st.py", line 3, in <module>     r = raw_input() EOFError: EOF when reading a line 

Can you explain what is happening here please? When I use p.stdout.read(), it hangs forever.

like image 718
Black_Hat Avatar asked May 27 '13 07:05

Black_Hat


People also ask

What is subprocess Popen communicate?

communicate() writes input (there is no input in this case so it just closes subprocess' stdin to indicate to the subprocess that there is no more input), reads all output, and waits for the subprocess to exit.

How does Python communicate with subprocess?

To start a new process, or in other words, a new subprocess in Python, you need to use the Popen function call. It is possible to pass two parameters in the function call. The first parameter is the program you want to start, and the second is the file argument.

Do you need to close Popen?

Popen do we need to close the connection or subprocess automatically closes the connection? Usually, the examples in the official documentation are complete. There the connection is not closed. So you do not need to close most probably.

What is the difference between subprocess call and Popen?

Popen is more general than subprocess. call . Popen doesn't block, allowing you to interact with the process while it's running, or continue with other things in your Python program. The call to Popen returns a Popen object.


1 Answers

.communicate() writes input (there is no input in this case so it just closes subprocess' stdin to indicate to the subprocess that there is no more input), reads all output, and waits for the subprocess to exit.

The exception EOFError is raised in the child process by raw_input() (it expected data but got EOF (no data)).

p.stdout.read() hangs forever because it tries to read all output from the child at the same time as the child waits for input (raw_input()) that causes a deadlock.

To avoid the deadlock you need to read/write asynchronously (e.g., by using threads or select) or to know exactly when and how much to read/write, for example:

from subprocess import PIPE, Popen  p = Popen(["python", "-u", "1st.py"], stdin=PIPE, stdout=PIPE, bufsize=1) print p.stdout.readline(), # read the first line for i in range(10): # repeat several times to show that it works     print >>p.stdin, i # write input     p.stdin.flush() # not necessary in this case     print p.stdout.readline(), # read output  print p.communicate("n\n")[0], # signal the child to exit,                                # read the rest of the output,                                 # wait for the child to exit 

Note: it is a very fragile code if read/write are not in sync; it deadlocks.

Beware of block-buffering issue (here it is solved by using "-u" flag that turns off buffering for stdin, stdout in the child).

bufsize=1 makes the pipes line-buffered on the parent side.

like image 165
jfs Avatar answered Oct 08 '22 02:10

jfs