Search code examples
pythonpython-3.xsubprocessstdoutpopen

Popen([...], stderr=PIPE) ignores input() message from spawned python program


I have one file running the other through the Popen().

# a.py
import subprocess

p = subprocess.Popen(['python3','/home/scotty/b.py'], 
stderr=subprocess.PIPE)
p.wait()

# b.py
input('???')

When I run a.py "???" doesn't appear but the prompt still works... why? And how can I fix it?

If I remove stderr=subprocess.PIPE then "???" does show up.

According to the docs the output of input "is written to standard output" and I'm not touching standard output.


Solution

  • It seems that in your exemple, everything happens as if opening a pipe for stderr but not for stdout has the effect of redirecting stdout to stderr because in the tests that I made, stderr receives the input's prompt.

    Below is a code that works for me in linux. It is probably overcomplicated because I use socketpairs, which is most certainly not necessary, but at least it is robust and it works.

    ##################################
    # a.py
    
    import subprocess
    import socket
    import select
    
    esock, echildsock = socket.socketpair()
    osock, ochildsock = socket.socketpair()
    p = subprocess.Popen(['python3','b.py'], 
        stderr=echildsock.fileno(),
        stdout=ochildsock.fileno())
    
    while p.poll() is None:
        r, w, x = select.select([esock, osock],[],[], 1.0)
        if not r:
            continue # timed out
        for s in r:
            print('stdout ready' if s is osock else 'stderr ready')
            data = s.recv(1024)
            print('received', data.decode('utf8'))
    osock.shutdown(socket.SHUT_RDWR)
    osock.close()
    esock.shutdown(socket.SHUT_RDWR)
    esock.close()
    
    ##################################
    # b.py
    
    res = input('???')
    print('in b:', res)