Python StringIO - selectively place data into stdin

99封情书 提交于 2019-12-11 10:01:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!