15

I'm trying to write the results of a function to stdin.

This is the code :

def testy():
    return 'Testy !'

import sys
sys.stdin.write(testy())

And the error I get is :

Traceback (most recent call last):
  File "stdin_test2.py", line 7, in <module>
    sys.stdin.write(testy())
io.UnsupportedOperation: not writable

I'm not completely sure, is this the right way of doing things ?

m_vdbeek
  • 3,704
  • 7
  • 46
  • 77
  • 4
    What are those things you're trying to do? `stdin` is for reading input, it's opened read-only. – Pavel Anossov Feb 24 '13 at 19:17
  • 1
    Yes I know. What I want to do is simulate keystrokes to the input() method by writing into stdin. – m_vdbeek Feb 24 '13 at 19:19
  • The traceback is telling you that it's not writable... did you read that? – Sandeep Raju Prabhakar Feb 24 '13 at 19:19
  • @sandeepraju Yes, but it's not very helpful in trying to achieve what I wrote in my comment just above. – m_vdbeek Feb 24 '13 at 19:20
  • 1
    @Awake It would help to have some context: Why do you want to imitate keystrokes in `input()`? – askewchan Feb 24 '13 at 19:22
  • 1
    Because I have a program that originally was in a shell and now it's using a GUI. What I want to do is convert click events into a string (done) and pipe the result to the previously used input() method. – m_vdbeek Feb 24 '13 at 19:24
  • 1
    Where I previously would ask the user to write 1, 2, or 3 for selecting options I know have three places on the GUI where the user can click on. The event.x and event.y are then converted into a special string and piped to input(). – m_vdbeek Feb 24 '13 at 19:27
  • Maybe you should invoke the old program for the new, separate one, and just pipe input to it. – Pavel Anossov Feb 24 '13 at 19:28
  • What OS are you using? – dawg Feb 24 '13 at 19:29
  • @PavelAnossov there are too many function calls. drewk : Linux – m_vdbeek Feb 24 '13 at 19:33

4 Answers4

28

You could mock stdin with a file-like object?

import sys
import StringIO

oldstdin = sys.stdin
sys.stdin = StringIO.StringIO('asdlkj')

print raw_input('.')       #  .asdlkj
Pavel Anossov
  • 60,842
  • 14
  • 151
  • 124
  • 1
    I think I'm going to try this solution. Thanks ! – m_vdbeek Feb 24 '13 at 19:35
  • 8
    For Python 3: `from io import StringIO` and `sys.stdin = StringIO('asdlkj')`. – orbeckst Sep 03 '19 at 16:40
  • Note that `sys.stdin` does *not* exhibit all the same behavior as `StringIO` and vice versa; for instance `StringIO.readline()` returns an empty string immediately and does not block/wait for input, like `sys.stdin.readline` or `input` does. See https://stackoverflow.com/questions/9929689/is-there-a-way-to-make-stringio-reading-blocking for a solution to *that* problem. – Brendano257 Nov 15 '22 at 22:36
2

I was googling how to do this myself and figured it out. For my situation I was taking some sample input from hackerrank.com and putting it in a file, then wanted to be able to use said file as my stdin, so that I could write a solution that could be easily copy/pasted into their IDE. I made my 2 python files executable, added the shebang. The first one reads my file and writes to stdout.

#!/Users/ryandines/.local/share/virtualenvs/PythonPractice-U9gvG0nO/bin/python
# my_input.py
import sys

def read_input():
    lines = [line.rstrip('\n') for line in open('/Users/ryandines/Projects/PythonPractice/swfdump')]
    for my_line in lines:
        sys.stdout.write(my_line)
        sys.stdout.write("\n")

read_input()

The second file is the code I'm writing to solve a programming challenge. This was mine:

#!/Users/ryandines/.local/share/virtualenvs/PythonPractice-U9gvG0nO/bin/python
def zip_stuff():

    n, x = map(int, input().split(' '))
    sheet = []

    for _ in range(x):
        sheet.append( map(float, input().split(' ')) )

    for i in zip(*sheet): 
        print( sum(i)/len(i) )

zip_stuff()

Then I use the operating system's pipe command to provide the buffering of STDIN. Works exactly like hackerrank.com, so I can easily cut/paste the sample input and also my corresponding code without changing anything. Call it like this: ./my_input.py | ./zip_stuff.py

Community
  • 1
  • 1
Ryan Dines
  • 979
  • 10
  • 18
  • Hey thanks, this is exactly the same use case as I have :) Works like a charm! – Ahndwoo Dec 04 '19 at 19:31
  • Hey Ryan, nicely done. Do you know you can directly use a file as input with the command line, so that you don't need to write your first program at all? Or am I missing something?: `./zip_stuff.py < '/Users/ryandines/Projects/PythonPractice/swfdump'` – tharibo Jan 29 '21 at 13:47
  • @tharibo yep, you're right, or just cat the file `cat swfdump | ./zip_stuff.py`, although for hackerrank I needed some specific behavior...i dont really remember TBH – Ryan Dines Feb 11 '21 at 19:50
1

It is possible on Linux:

import fcntl, termios
import os
tty_path = '/proc/{}/fd/0'.format(os.getpid())

with open(tty_path, 'w') as tty_fd:
        for b in 'Testy !\n':
            fcntl.ioctl(tty_fd, termios.TIOCSTI,b)
# input()

Adam Jenča
  • 582
  • 7
  • 20
0

stdin is an input stream, not an output stream. You can't write to it.

What you might be able to do, possibly, is create a pipe using os.pipe, turn the readable end into a file object using os.fdopen, and replace stdin with that, and then write to the writeable end.

r, w = os.pipe()
new_stdin = os.fdopen(r, 'r')
old_stdin, sys.stdin = sys.stdin, new_stdin

I can't see that ending well, though. It will be easier and less error-prone to just rewrite the parts of your application that are using input.

Cairnarvon
  • 25,981
  • 9
  • 51
  • 65
  • 1
    While it does not solve this question, [turns out you can write to stdin](https://stackoverflow.com/a/53898574/) – The Matt Dec 23 '18 at 06:15