If you want to avoid having the output shown in the terminal at all, you can use the following on MacOS and Linux:
import sys
import tty
import termios
def hidden_input(*args):
stdin = sys.stdin.fileno()
tattr = termios.tcgetattr(stdin)
try:
tty.setcbreak(stdin, termios.TCSANOW)
return input(*args)
finally:
termios.tcsetattr(stdin, termios.TCSANOW, tattr)
This works by setting the TTY (99% of the time a terminal emulator) to cbreak mode. Which does the following:
The traditional 'raw' mode is the easier one to explain; it does no in-kernel processing of input or output at all. All characters are returned immediately when typed and all output is produced as-is. The traditional 'cbreak' mode is used for things like password entry; it returns characters immediately as they're typed, doesn't echo characters, and doesn't do any in-kernel line editing (which mostly means that your program can actually see the various editing characters). At a high level, there are two major differences between 'cbreak' and 'raw'. First, cbreak leaves output handling unchanged, which may be relatively 'cooked'. Second, cbreak still allows you to interrupt the program with ^C, suspend it, and so on. You can see this in action with most programs (such as passwd, su, or sudo) that ask for a password; you can immediately interrupt them with ^C in a way that, eg, vi does not respond to.
The low-level settings for cbreak are:
- disable ECHO; this stops typed characters from being echoed.
- disable ICANON; this turns off line editing.
set VMIN to 1 and VTIME to 0; this makes it so that a read() returns immediately once there's (at least) one character available.
Note that because readline
is still in use, you will still be able to edit lines as they are typed like normal.
On Windows, I am not sure how to do this easily.
if you want to clear the input that was typed after the user presses enter, that's a little harder, as it requires partially clearing already-printed output, which needs to use special control codes.
One possible easier solution for Windows: the following will clear the whole terminal on MacOS and Linux, but will also work in Windows Terminal (not the same as the default cmd.exe!)
print('\x1b[2J')
You could also try to get this to work with the the ordinary Windows terminal via the colorama package, as suggested in martineau's comment.