0

I'm trying to write a python program to test a java program that takes input from stdin using Scanner.

All other posts point to using communicate with popen, but for me it absolutely does not work. When i run my python program, it just calls popen and then stops while the java program waits for input. I wrote a print statement after popen to check. It never prints.

Its very simple. I just want to give this program that waits for input some input.

here is the code:

import os.path, subprocess
from subprocess import PIPE

p = subprocess.Popen(['java', 'Main'], stdin=PIPE, stdout=PIPE)
print 'after subprocess' #this never get's printed
output = p.communicate(input='5 5 4 3 2 1'.encode())[0]
print output
bgenchel
  • 3,739
  • 4
  • 19
  • 28
  • If you change your print to something like "assert False" do you see a traceback? The communicate call might not immediately return depending on what your call is doing, but Popen should. This works for me: p = subprocess.Popen(['xargs'], stdin=PIPE, stdout=PIPE); print p.communicate(input='hello') – jtg May 02 '15 at 04:29
  • The reason he may not see the `after subprocess` is that it may be in stdout's buffer. (A `sys.stdout.flush()` would fix that.) Or it may even be in the _input_ buffer of whatever he's using to look at the output, if he's not just running this on the command line. At any rate, the output should be visible after he terminates the program with ^C or whatever, but possibly mixed in with an ugly traceback. – abarnert May 03 '15 at 21:47
  • unrelated: don't call `.encode()` on a bytestring. `print output` statements suggests that you are using Python 2. – jfs May 09 '15 at 18:21
  • `Popen()` does not wait for the child process to exit. It is very unlikely that it blocks for long in your case. If you add `sys.stdout.flush()` after `print 'after subprocess'` then you should see the message. – jfs May 09 '15 at 18:25

1 Answers1

0

Without more information (like some sample Java code) it's hard to be sure, but I'll bet the problem is that the Java code is waiting for a complete line, and you haven't sent one.

If so, the fix is simple:

output = p.communicate(input='5 5 4 3 2 1\n'.encode())[0]

As a side note, why exactly are you calling encode on that string? It's already encoded in whatever character set your source code uses. So, when you call encode, it has to first decode that to Unicode. And then, because you didn't pass an argument to encode, it's going to encode it to your default character set (sys.getdefaultencoding()), which doesn't seem any more likely to match what the Java code is expecting than what you already have. It's rarely worth calling encode with an argument, and you should almost* never call it on a str, only a unicode.

* In case you're wondering, the exception is when you're using a handful of special codecs like hex or gzip. In Python 3, they decided that the occasional usefulness of those special cases was nowhere near as much as the frequent bug-magnet of calling encode on already-encoded strings, so they took it out of the language.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thank you so much! That worked. I was using encode because I saw it in another example for communicate and I thought that might have been the issue. I took it out as per your suggestion – bgenchel May 02 '15 at 21:33
  • @bgenchel: Don't just randomly call methods without understanding what they do. That never fixes anything. At best, it makes your code work on one particular test case, but then fail in a harder-to-debug way on the next one. – abarnert May 03 '15 at 21:45
  • 1
    the Java code that doesn't accept EOF instead of `'\n'` seems broken. Don't use `.encode()` here (Python 2). – jfs May 09 '15 at 18:24
  • @J.F.Sebastian: That's a good point, especially since his goal here is to test that Java code, so testing that its input handling is up to spec (there must be a spec; Java code always has a spec, right?) seems worth doing. (For the second half of your comment, I already explained that in the answer.) – abarnert May 09 '15 at 20:39