6

I am trying to wrap gnugo in a python script.

I've gone over the other questions in SO about wrapping CLI applications here and here and though they've helped somewhat, I haven't been able to get my script to work completely. It appears the process is killed after the first input from stdin.

The script looks like this:

import subprocess 

proc = subprocess.Popen(['gnugo', '--mode', 'gtp'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)

c = raw_input('first command: ')

while True:
    r = proc.communicate(c)
    print 'gnugo says: ' + str(r)
    c = raw_input('next command: ')

The error I'm getting is this:

$ python testgnu.py
first command: play b c4
gnugo says: ('= \n\n', None)
next command: genmove w
Traceback (most recent call last):
  File "testgnu.py", line 8, in <module>
    r = proc.communicate(c)
  File "/usr/local/Cellar/python/2.7.3/lib/python2.7/subprocess.py", line 754, in communicate
    return self._communicate(input)
  File "/usr/local/Cellar/python/2.7.3/lib/python2.7/subprocess.py", line 1307, in _communicate
    self.stdin.flush()
ValueError: I/O operation on closed file

I am running python 2.7.3 (and it probably doesn't matter but the gnugo version is 3.8).

Some answers in the other questions suggested pexpect but I'd like to use as few external libraries as possible.

Community
  • 1
  • 1
almostflan
  • 640
  • 4
  • 15

1 Answers1

8

Your issue is that Popen.communicate closes the file after performing its reads and writes.

You will have to manually call proc.stdin.write(...) to send the process text and proc.stdout.read*() to read text:

while True:
    proc.stdin.write(c)
    r = proc.stdout.readline()
David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • Yep, I think that's it. Now stdout.read() hangs, though that appears to be another issue. Thanks! – almostflan Jun 09 '12 at 15:47
  • `stdout.read()` will hang because `.read()` tries to read *all* the output. Instead, use `.readline()` (as in my example), which will only read one line at a time, or `.read(n)`, which will read (up to) `n` bytes. – David Wolever Jun 09 '12 at 15:50
  • It appears the issue is that it never receives the EOF so it never terminates. `gnugo` returns almost instantly when a player is playing a move. I tried to explicitly write `\n` to stdin and it looks like that let `readline()` go through at least once (it hangs if I don't write `\n` to stdin), but `read()` still hangs. – almostflan Jun 09 '12 at 16:02
  • Why are you calling straight `.read()`? You should only need to call `.readline()`… No? – David Wolever Jun 09 '12 at 16:13
  • `readline()` hangs as well. I could pass stdin a bunch of newlines and just `readline()` them up. At the moment, I don't quite understand why adding the newlines to the END of the stdin buffer makes `readline()` work multiple times (each time I get more of the data I want from stdout - not just the empty newlines you might expect). I wouldn't mind doing `readline()` so long as it doesn't hang eventually. – almostflan Jun 09 '12 at 16:22
  • I've got it now (and I think you were saying it all along). The kick was that [`raw_input()`](http://docs.python.org/library/functions.html#raw_input) strips newlines so they need to be added back if it's an interactive prompt I'm dealing with. Your note about `read()` makes sense now. (basically that it will always hang since its effectively just following the output of gnugo while gnugo is waiting for input) Thanks again for the help! – almostflan Jun 09 '12 at 16:53