This is an old revision of the document!
====== A Better "getpass()" Function for Unix ====== ===== UPDATE ===== It looks like my version of ''getpass'' (using the tty) is actually the default in the standard library version of ''getpass'' as of python 2.6. If you are using python 2.6 or greater, use the standard library version as it also falls back to stdin if using the tty fails. ===== What is This About? ===== I've had this problem in the past and it cropped up again today and pissed me off once again so I decided to tackle the issue. The issue is the Python standard library version of ''getpass()'' from the ''getpass'' module. It works fine in terms of really basic usage, but the big problem comes when you want to write a script that reads from ''STDIN'' //and// calls ''getpass()''. Since the built in ''getpass()'' reads from ''STDIN'', it ends up borking your script. Now, for anyone who has ever used ''ssh'' before (and I assume if you are reading this, you have), you will have noticed that the ''ssh'' client gets around this very issue since you can pipe info to ''ssh'' //and// enter your password when prompted. This is due to the fact that ''ssh'' client reads and writes directly to your terminal, rather than reading and writing from ''STDIN'' and ''STDOUT''. This is exactly what I've done with my version of ''getpass()''. I used most of the code used in the standard library ''getpass()'', but made it write the prompt and read directly from a connection to the terminal itself. This has been tested on linux (Gentoo) and FreeBSD 6.2 and it works fine on both. ===== The Code ===== Here is my simple version of the standard library ''getpass()''. Of course, this will only work on a *nix platform. <code python> def getPass(prompt='Password: '): """ Writes the password prompt and reads from terminal directly, just like the openssh client """ if not os.isatty(sys.stderr.fileno()): raise IOError , 'You can only call getPass() from a tty' ttyname = os.ttyname(sys.stderr.fileno()) ttyh = open(ttyname , 'w+b') ttyfd = ttyh.fileno() old = termios.tcgetattr(ttyfd) # a copy to save new = old[:] new = new & ~termios.ECHO # 3 == 'lflags' try: termios.tcsetattr(ttyfd , termios.TCSADRAIN, new) ttyh.write(prompt) ttyh.flush() passwd = ttyh.readline().strip() finally: termios.tcsetattr(ttyfd , termios.TCSADRAIN, old) ttyh.close() sys.stdout.write('\n') return passwd </code>