Write function result to stdin
Asked Answered
D

5

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 ?

Decani answered 24/2, 2013 at 19:16 Comment(10)
What are those things you're trying to do? stdin is for reading input, it's opened read-only.Warfare
Yes I know. What I want to do is simulate keystrokes to the input() method by writing into stdin.Decani
The traceback is telling you that it's not writable... did you read that?Hoeve
@sandeepraju Yes, but it's not very helpful in trying to achieve what I wrote in my comment just above.Decani
@Awake It would help to have some context: Why do you want to imitate keystrokes in input()?Synge
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.Decani
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().Decani
Maybe you should invoke the old program for the new, separate one, and just pipe input to it.Warfare
What OS are you using?Slippery
@PavelAnossov there are too many function calls. drewk : LinuxDecani
W
29

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
Warfare answered 24/2, 2013 at 19:27 Comment(3)
I think I'm going to try this solution. Thanks !Decani
For Python 3: from io import StringIO and sys.stdin = StringIO('asdlkj').Klemens
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 #9930189 for a solution to that problem.Arbour
E
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

Exhibitioner answered 6/8, 2018 at 19:11 Comment(3)
Hey thanks, this is exactly the same use case as I have :) Works like a charm!Meteoric
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'Purl
@Purl 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 TBHExhibitioner
S
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()

Sturm answered 9/12, 2021 at 7:0 Comment(0)
M
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.

Mangan answered 24/2, 2013 at 19:25 Comment(1)
While it does not solve this question, turns out you can write to stdinTenure
I
0

Having this issue for an async server, and needing to call a framework that requested a user prompt.

This is similar to the stdin solution of @Cairnarvon but with a focus on repeatable prompts and reverting standard in when closed. Except the callback flushes the files, which is very important as input's stdin.read() will block until flushed.


import time
import asyncio
import os,sys
class obj:
    def blocks_on_input(self):
        attempts = 0
        strt = time.time()
        while attempts < 5:
            got = input('need input pls')
            attempts += 1
            print(f'\nthanks got: {got} @ {time.time() - strt} | {attempts}')
            time.sleep(1)
            
        
    async def main(self):
        loop = asyncio.get_event_loop()
        self.setup_std_fake()
        tsk = asyncio.to_thread(self.test)
        tsk.add_done_callback(self.reset_std_in)
        for i in range(10):
            wt = 2*(1+i)
            loop.call_later(wt,self.send_signal)
        return await tsk
        
    def send_signal(self):
        print('go for pls')
        self.wt.write('go\r\n'.encode())
        self.wt.flush()#very important!
        self.rd.flush() #very important!

    def setup_std_fake(self):
        r, w = os.pipe()
        self.rd = os.fdopen(r, 'rb')
        self.wt = os.fdopen(w, 'wb')
        self._old_stdin = sys.stdin
        sys.stdin = self.rd

    def reset_std_in(self,*args):
        sys.stdin = self._old_stdin

o = obj()    
loop = asyncio.get_event_loop()
tsk = loop.create_task(o.testcoro())
tsk.add_done_callback(o.reset_std_in)

loop.run_until_complete(tsk)
Idou answered 8/5, 2024 at 22:49 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.