(See Edit 1 below for update)
I need to interact with a menu I wrote in Python 3.
However, whatever I try, I cannot make the input()
line to be called.
(It's the last line in the get_action()
function).
Following is the (boiled down) script I want to interact with from subprocess()
:
$ cat test_menu.py
#!/usr/bin/env python3
action_text = """
5. Perform addition
6. Perform subtraction
Q. Quit
"""
def get_action():
print(action_text)
reply = input("Which action to use? ")
if __name__ == "__main__":
get_action()
subprocess()
based code to interact with test_menu.py
above is:
$ cat tests1.py
import subprocess
cmd = ["/usr/bin/python3","./test_menu.py"]
process = subprocess.Popen(cmd,
shell=False,
bufsize=0,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
for i in range(8):
output = process.stdout.readline()
print output.strip()
process.stdin.write('%s\n' % "5")
process.stdin.flush()
But, when I run tests1.py,
it never gets to the input()
line:
$ python ./tests1.py
5. Perform addition [default]
6. Perform subtraction
Q. Quit
Any suggestions how can I get subprocess()
to display and interact with the input()
line (e.g., to display the Which action to use?
prompt) ?
Edit 1:
Following @Serge suggestion, the subprocess()
is able to display the prompt line, but it still does not display the input (5) I feed the PIPE.
Changed tests1.py:
import subprocess
def terminated_read(fd, terminators):
buf = []
while True:
r = fd.read(1)
buf += r
if r in terminators:
break
return ''.join(buf)
cmd = ["/usr/bin/python3","./test_menu.py"]
process = subprocess.Popen(cmd,
shell=False,
bufsize=0,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
for i in range(5):
output = process.stdout.readline()
print output.strip()
process.stdin.write("5\n")
process.stdin.flush()
for i in range(80):
output = terminated_read(process.stdout, "?")
print output," ",
Execution:
$ python ./tests1.py
5. Perform addition [default]
6. Perform subtraction
Q. Quit
Which action to use?
The problem is that readline
reads a stream until it finds a newline, and that input("Which action to use? ")
does not print one.
One simple workaround would be to write
...
reply = input("Which action to use? \n")
...
If you do not want (or cannot) to change anything in test menu, you will have to implement a read with timeout, or read one char at a time until you find either a new line or a ?
.
For example this should work:
...
def terminated_read(fd, terminators):
buf = []
while True:
r = fd.read(1).decode()
buf += r
if r in terminators:
break
return ''.join(buf)
process = subprocess.Popen(cmd,
shell=False,
bufsize=0,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
for i in range(8):
output = terminated_read(process.stdout, "\n?")
print(output.strip())
...
Passing the answer to subprocess is simple. The hard part is to guess when to answer. Here, you know that you can answer as soon as an input ends in ?
. I changed your test_menu.py to be able to confirm that it correctly get the command to:
#!/usr/bin/env python3
import sys
action_text = """
5. Perform addition
6. Perform subtraction
Q. Quit
"""
def get_action():
print(action_text)
reply = input("Which action to use? ")
print("Was asked ", reply) # display what was asked
if reply == '5':
print("subtract...")
if __name__ == "__main__":
get_action()
The wrapper test1.py
is then simply:
import subprocess
cmd = ["/usr/bin/python3","./test_menu.py"]
def terminated_read(fd, terminators):
buf = []
while True:
r = fd.read(1).decode()
# print(r)
buf.append(r)
if r in terminators:
break
return "".join(buf)
process = subprocess.Popen(cmd,
shell=False,
bufsize=0,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
while True:
output = terminated_read(process.stdout, "\n?")
print(output.strip())
if output[-1] == '?':
break
process.stdin.write(('%s\n' % "5").encode())
cr = process.wait()
end = process.stdout.read().decode()
print("Child result >" + end + "<")
print("Child code" + str(cr))
Started with either Python 3.4 or Python 2.7 the output is as expected:
5. Perform addition
6. Perform subtraction
Q. Quit
Which action to use?
Child result > Was asked 5
subtract...
<
Child code0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With