问题
We're using a bit of compiled python code that we don't have the source to. The code prompts for user input and we're trying to automate that portion.
Basically asks for username, password, then some various questions depending on certain circumstances. I don't know whether the compiled function is using raw_input, input or something else.
I've been able to use StringIO to replace stdin w/ the username and password and I can replace stdout with my own class and figure out which prompt is coming up, but I'm stumped when it comes to selectively placing data into stdin based on what I read from stdout.
import sys
import re
from StringIO import StringIO
def test():
overwrite = raw_input("The file exists, overwrite? ")
notify = raw_input("This file is marked for notifies. Notify?")
sys.stdout.write("Overwrite: %s, Notify: %s" % (overwrite,notify))
class Catcher(object):
def __init__(self):
pass
def write(self, msg):
if re.search("The file exists, overwrite", msg):
# put data into stdin
if re.search("The file is marked for notification", msg):
# put data into stdin
sys.stdout = Catcher()
test()
I can't just preload a StringIO object, because the questions may vary depending on the circumstances, but I need to automate feeding into stdin because they're trying to put this into an automated build system, so they'll be providing the defaults via the command line to answer any questions that occur.
If I set stdin to an empty StringIO object before calling the compiled function, then it just errors out with EOF - not sure how to make it wait for input.
Something like this:
import sys
import re
from StringIO import StringIO
def test():
overwrite = raw_input("The file exists, overwrite? ")
notify = raw_input("This file is marked for notifies. Notify?")
sys.__stdout__.write("Overwrite: %s, Notify: %s" % (overwrite,notify))
class Catcher(object):
def __init__(self, stdin):
self.stdin = stdin
def write(self, msg):
if re.search("The file exists, overwrite", msg):
self.stdin.write('yes\n')
if re.search("The file is marked for notification", msg):
self.stdin.write('no\n')
sys.stdin = StringIO()
sys.stdout = Catcher(sys.stdin)
test()
Produces:
Traceback (most recent call last):
File "./teststdin.py", line 25, in <module>
test()
File "./teststdin.py", line 8, in test
overwrite = raw_input("The file exists, overwrite? ")
EOFError: EOF when reading a line
Any ideas?
回答1:
If you want to read from a StringIO
you've just written to, you have to rewind it first to the position you've started writing.
Also, your second search tests for the wrong string.
This should work:
import sys
import re
from StringIO import StringIO
def test():
overwrite = raw_input("The file exists, overwrite? ")
notify = raw_input("This file is marked for notifies. Notify?")
sys.__stdout__.write("Overwrite: %s, Notify: %s" % (overwrite,notify))
class Catcher(object):
def __init__(self, stdin):
self.stdin = stdin
def write(self, msg):
if re.search("The file exists, overwrite?", msg):
self.stdin.truncate(0)
self.stdin.write('yes\n')
self.stdin.seek(0)
if re.search("This file is marked for notifies. Notify?", msg):
self.stdin.truncate(0)
self.stdin.write('no\n')
self.stdin.seek(0)
sys.stdin = StringIO()
sys.stdout = Catcher(sys.stdin)
test()
回答2:
Here's a solution that avoid StringIO
entirely:
import sys
import re
class Catcher(object):
def __init__(self, handler):
self.handler = handler
self.inputs = []
def __enter__(self):
self.__stdin = sys.stdin
self.__stdout = sys.stdout
sys.stdin = self
sys.stdout = self
def __exit__(self, type, value, traceback):
sys.stdin = self.__stdin
sys.stdout = self.__stdout
def write(self, value):
result = self.handler(value)
if result:
self.inputs = [result] + self.inputs
def readline(self):
return self.inputs.pop()
Used as:
def test():
overwrite = raw_input("The file exists, overwrite? ")
notify = raw_input("This file is marked for notifies. Notify?")
sys.__stdout__.write("Overwrite: %s, Notify: %s" % (overwrite,notify))
@Catcher
def exist_notify(msg):
if re.search("The file exists, overwrite", msg):
return 'yes'
if re.search("This file is marked for notifies", msg):
return 'no'
with exist_notify:
test()
来源:https://stackoverflow.com/questions/13480632/python-stringio-selectively-place-data-into-stdin