So I'm using some libraries that (unfortunately and much to my chagrin) print to stdout for certain debug info. Okay, no problem, I just disabled it with:
import sys,os
sys.stdout = open(os.devnull,'wb')
I've recently added code for getting user input and printing output in the terminal, which of course needs stdout. But again, no problem, instead of print
I can just do:
sys.__stdout__.write('text\n')
Finally, since I'm doing raw_input
in a separate thread and the program's output can interrupt the user typing, I wanted to re-echo the test as described in the first part of this answer to make it more or less seamless using readline.get_line_buffer()
. For example, if the user entered foobar
:
> foobar
And then another thread says Interrupting text!
it should look like:
Interrupting text!
> foobar
But instead I observe:
Interrupting text!
>
It turns out that readline.get_line_buffer()
is always blank, and the code fails to re-echo what the user had typed. If I remove the sys.stdout
override, everything works as expected (except now the debug output from libraries isn't blocked).
I'm using Python 2.7 on Linux if that matters. Perhaps what I want to do is impossible, but I'd really like to know why this is happening. In my mind, doing things with stdout
shouldn't affect the stdin
line buffer, but I'm admittedly not familiar with the underlying libraries or implementation.
A minimum working example is below. Just type something and wait for the interrupting text. The prompt "> "
will be re-echoed, but the text you entered won't be. Simply comment out the second line to see it work correctly. When the thread prints, it logs the line buffer to stdin.log
.
import time,readline,thread,sys,os
sys.stdout = open(os.devnull,'wb') # comment this line!
def noisy_thread():
while True:
time.sleep(5)
line = readline.get_line_buffer()
with open('stdin.log','a') as f:
f.write(time.asctime()+' | "'+line+'"\n')
sys.__stdout__.write('\r'+' '*(len(line)+2)+'\r')
sys.__stdout__.write('Interrupting text!\n')
sys.__stdout__.write('> ' + line)
sys.__stdout__.flush()
thread.start_new_thread(noisy_thread, ())
while True:
sys.__stdout__.write('> ')
s = raw_input()
I've also tried sys.stdout = sys.__stdout__
right before the get_line_buffer()
call, but that doesn't work either. Any help or explanation is greatly appreciated.
Its the raw_input()
that stops working when you redirect the stdout.
If you try sys.stdout = sys.__stdout__
just before the raw_input()
it works again.
Both stdin
and stdout
need to be connected to the terminal in order for raw_input
to work.