7

I'm starting on a Python project in which stdin redirection is necessary, using code similar to below:

import sys
import StringIO

s = StringIO.StringIO("Hello")
sys.stdin = s
a = raw_input("Type something: ")
sys.stdin = sys.__stdin__
print("You typed in: "+a)

The problem is, after the code runs, the following is displayed:

Type something: You typed in: Hello

Is there a way to modify my code such that the following is displayed instead?

Type something: Hello

You typed in: Hello

I've been searching high and low but have found no answer yet. I'll really appreciate if anyone has an idea. Thanks!

Community
  • 1
  • 1
dangmai
  • 337
  • 6
  • 12
  • 3
    "stdin redirection is necessary"? Really? That seems like an impossible situation. Why not replace `raw_input` with a callable object that does what you want? – S.Lott Apr 28 '11 at 00:43
  • I understand this is not a common situation, but it is really necessary. The code above is just a very simple example; in reality I need to run other people's code that asks for input, so I can't change the way they code their programs. – dangmai Apr 28 '11 at 02:18
  • You don't change their code. You redefine a built-in function with your own version, import their code, and run their code using your version of the built-in. – S.Lott Apr 28 '11 at 02:20
  • Oh I see what you mean. However, I still can't think of an implementation using your idea that would be satisfactory yet. Would you mind posting a sample piece of code that might help me get closer to the solution? Thanks a lot! – dangmai Apr 28 '11 at 02:26

3 Answers3

3

I'm not sure why you would need to, but you could always do this:

a = raw_input("Type something: ")
if sys.stdin is not sys.__stdin__:
    print(a)
print("You typed in: "+a)

Then again, swapping raw_input for your own implementation as needed would probably make more sense.

Edit: okay, based on your, comment it looks like you'll want to do some monkey patching. Something like this:

old_raw_input = raw_input

def new_raw_input(prompt):
    result = old_raw_input(prompt)
    if sys.stdin is not sys.__stdin__:
        print result
    return result

raw_input = new_raw_input

Of course, this might make the point of redirecting stdin moot.

Ian B.
  • 243
  • 1
  • 6
  • Thanks for your answer! However, that's not what I need. I'm trying to run other people's codes that ask for input, so I can't change the way their programs are written. – dangmai Apr 28 '11 at 02:20
  • Sounds like you should monkey patch the raw_input to your own implementation. – Ian B. Apr 28 '11 at 02:48
  • This is exactly what I want! Thanks a lot! I never knew we can do this crazy monkey patch thing with Python :) – dangmai Apr 28 '11 at 03:08
  • If you're using 3.x [this](http://stackoverflow.com/questions/954834/how-do-i-use-raw-input-in-python-3-1) is useful. – DanSkeel Jun 05 '13 at 09:48
3

Do this.

class MyRawInputFakeOutObject( object ):
    def __init__( self, the_fake_out_input_text ):
        self.input= the_fake_out_input_text
    def __call__( self, prompt ):
        print( prompt )
        return self.input

raw_input= MyRawInputFakeOutObject( "Hello" )

import some_existing_module

some_existing_module.the_existing_main()

Now the existing module is working with your raw_input, not the built-in raw_input. Yours can do anything to provide fake inputs and fake outputs.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • great answer! however, i find ian b's code to be a little bit easier to work with. Both should solve my problem though. Thanks a lot! – dangmai Apr 28 '11 at 03:09
  • Would this method work for code that was not broken up into modules? For example, if one was given a script that had no functions or main defined wouldn't the import command just run the script (ie before raw_input is redefined)? Just a thought. – Adam Lewis Apr 28 '11 at 03:31
  • @Adam Lewis: Every Python file **is** a module. By definition. You cannot avoid breaking Python up into modules. When you have a "script" it's a module. Importing it will run it. While your comment has a lot of confusion in it, it does point up a change that's needed to handle those really poorly-written scripts with no `if __name__=="__main__":` section. – S.Lott Apr 28 '11 at 09:51
  • Point taken about the module comment. Your change addressed what I was trying to convey. I only brought it up because I can see a teacher's assistant grading a python assignment in this way. That said, if it is to grade a homework assignment I doubt well-written code is normal. Thanks for the clarification! – Adam Lewis Apr 28 '11 at 13:08
  • actually adam you just described my exact situation (I'm an assistant writing a program to automatically check students' answers) :) That's why I can't change part of the code myself. Thanks again everyone! – dangmai Apr 28 '11 at 21:28
1

EDIT: After reading the other answers and comments I think I have found a good way to really redirect the stdin. Note that I have assumed that you will know the the inputs to the end user's raw_inputs need to be.

User's Code (Named some_module.py)

print "running some module with 5 raw_input requests"
for x in range(5):
    value = raw_input("This is someone else's code asking its (" + str(x) + ") raw_input: ")
    print 'stdin value: ' + value

Your Test Script (Named whatever you like)

    import sys
    class MY_STD_IN( object ):
        def __init__(self, response_list):
            self.std_in_list = response_list
            self.std_in_length = len(response_list)
            self.index = 0

        def readline(self):
            value = self.std_in_list[self.index]      
            print value
            if self.index < self.std_in_length -1:
                self.index += 1
            else:
                self.index = 0

            return value

    predetermined_stdin_responses = ['Value 1\r', 'Value 2\r', 'Value 3\r']
    sys.stdin = MY_STD_IN( predetermined_stdin_responses )

    import some_module

Running the Script Yields

running some module with 5 raw_input requests
This is someone else's code asking its (0) raw_input: Value 1
stdin value: Value 1
This is someone else's code asking its (1) raw_input: Value 2
stdin value: Value 2
This is someone else's code asking its (2) raw_input: Value 3
stdin value: Value 3
This is someone else's code asking its (3) raw_input: Value 1
stdin value: Value 1
This is someone else's code asking its (4) raw_input: Value 2
stdin value: Value 2

Original Answer

Not sure if you're looking for such a literal answer but here it is

import sys
import StringIO

s = StringIO.StringIO("Hello")
sys.stdin = s
a = raw_input("Type something: ")
sys.stdin = sys.__stdin__
print(a+"\nYou typed in: "+a)

Yields:

Type something: Hello

You typed in: Hello

Adam Lewis
  • 7,017
  • 7
  • 44
  • 62
  • Thanks for your answer, but it's not what I need. I have to run other people's codes, so I can't change the way they code their programs. All I can do (that I know of) is to somehow manipulate stdin and stdout – dangmai Apr 28 '11 at 02:22
  • Would you mind giving more of an example of what their code is and how you intend to interact with it? Meaning are you wanting to control the raw_input() of their program with your own data? – Adam Lewis Apr 28 '11 at 03:21
  • Yes, that's correct. I need to check a student's answer by feeding data into their function (either by providing an argument or through stdin) and then compare the stdout to a provided answer. – dangmai Apr 28 '11 at 21:30