Frage

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?

War es hilfreich?

Lösung

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()

Andere Tipps

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()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top