Reputation: 439
I need to write data to a Process I've created. For various reasons, it has to be a multiprocessing.Process
. Let's say that this Process does something like run apt upgrade
, and will then be prompted for a [Y/n] from the user. What is the best way to send a Y or n? I've done a lot of searching and found quite a few half-answers about duplicating stdin, but I haven't been able to come up with a full solution. Here's a minimal example:
#! /usr/bin/python3
import sys
import multiprocessing
e = multiprocessing.Event()
def get_input():
try:
x = input("Go ahead - type something\n")
print("typed " + x)
finally:
e.set()
# 1. Here it seems we should replace stdin?
multiprocessing.Process(target=get_input).start()
# 2. Here I want to write to stdin such that Process started above receives input
e.wait()
Of course, this dies immediately because the stdin used by input is closed and just returns an EOF. How can I override stdin to take input from a file or some kind of local buffer?
Upvotes: 3
Views: 831
Reputation: 439
I've found a solution that works for me. Editing the code sample above:
#! /usr/bin/python3
import multiprocessing
import sys
def get_input(newstdin, done):
sys.stdin = newstdin # replace stdin
try:
x = input("Go ahead - type something\n")
print("typed " + x)
finally:
done.set()
# This class will pretend to be stdin for my process
class FakeStdin(object):
def __init__(self):
self.input = multiprocessing.Queue()
def readline(self):
output = self.input.get(timeout=10)
return output or ''
def write(self, message):
self.input.put(message)
done = multiprocessing.Event()
newstdin = FakeStdin()
multiprocessing.Process(target=get_input, args=(newstdin, done)).start()
newstdin.write("test string") # write to the fake stdin
done.wait()
Basically, I create a fake stdin to give to me process which sets sys.stdin. this fake stdin only needs to implement readline
to duck-type my usage of stdin here. In readline
, I wait for input using a Queue
, which I set with a method I call write
.
Upvotes: 2