Larry Price
Larry Price

Reputation: 439

Write to stdin of python multiprocessing.Process

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

Answers (1)

Larry Price
Larry Price

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

Related Questions