15

I have been going crazy over a seemingly easy question with Python: I want to call a function that uses raw_input() and input(), and somehow supply those with a string in my program. I've been searching and found that subprocess can change stdin and stdout to PIPE; however, I can't use subprocess to call a function. Here's an example:

def test():
    a = raw_input("Type something: ")
    return a

if __name__=='__main__':
    string = "Hello World" # I want to a in test() to be Hello World
    returnValue = test()

Of course this is much simpler than what I'm trying to accomplish, but the basic idea is very similar.

Thanks a lot!

dangmai
  • 337
  • 6
  • 12

2 Answers2

17

Temporarily replace sys.stdin with a StringIO or cStringIO with the desired string.

>>> s = StringIO.StringIO('Hello, world!')
>>> sys.stdin = s ; r = raw_input('What you say?\n') ; sys.stdin = sys.__stdin__ 
What you say?
>>> r
'Hello, world!'
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • I've been using your suggestion code for a week and it's working perfectly. However, one disadvantage to it is that the stdout doesn't show what the input (so after "What you say?" there's no output for "Hello, world!"). Do you by any chance know how to solve that? – dangmai Mar 02 '11 at 03:58
  • The only way to fix that is to print it yourself; since there's no console input, there's nothing for it to echo. – Ignacio Vazquez-Abrams Mar 02 '11 at 04:03
  • 2
    Note in Python2 this requires [`import StringIO`](https://docs.python.org/2/library/stringio.html), in Python3 this requires [`import io`](https://stackoverflow.com/a/18284900/4080966). – Erik Koopmans Mar 22 '18 at 13:10
1

In Python >= 3.4, you can make it a bit more elegant by creating a _RedirectStream context manager.

import contextlib
import io

class redirect_stdin(contextlib._RedirectStream):
    """Context manager for temporarily receiving stdin from another source."""
    _stream = "stdin"

def test():
    a = input("Type something: ")
    return a

if __name__=='__main__':
    with redirect_stdin(io.StringIO("Hello World")):
        returnValue = test()

This can be combined with the existing redirect_stdout and redirect_stderr decorators for even more flexibility. Somehow, stdin was not given the same treatment. You can read the diucussion on Python Issue #15805 for more context.

m000
  • 5,932
  • 3
  • 31
  • 28
  • +1 because while using anything that starts with an underscore is fragile, this might be the most reasonable way to deal with code that should work with sources other than stdin, but doesn't. – Terry Brown Sep 16 '22 at 18:42