1515# Guido van Rossum (Windows support and cleanup)
1616# Gregory P. Smith (tty support & GetPassWarning)
1717
18- import os , sys , warnings
18+ import contextlib
19+ import io
20+ import os
21+ import sys
22+ import warnings
1923
2024__all__ = ["getpass" ,"getuser" ,"GetPassWarning" ]
2125
@@ -38,53 +42,57 @@ def unix_getpass(prompt='Password: ', stream=None):
3842
3943 Always restores terminal settings before returning.
4044 """
41- fd = None
42- tty = None
4345 passwd = None
44- try :
45- # Always try reading and writing directly on the tty first.
46- fd = os .open ('/dev/tty' , os .O_RDWR | os .O_NOCTTY )
47- tty = os .fdopen (fd , 'w+' , 1 )
48- input = tty
49- if not stream :
50- stream = tty
51- except OSError as e :
52- # If that fails, see if stdin can be controlled.
46+ with contextlib .ExitStack () as stack :
5347 try :
54- fd = sys .stdin .fileno ()
55- except (AttributeError , ValueError ):
56- passwd = fallback_getpass (prompt , stream )
57- input = sys .stdin
58- if not stream :
59- stream = sys .stderr
60-
61- if fd is not None :
62- passwd = None
63- try :
64- old = termios .tcgetattr (fd ) # a copy to save
65- new = old [:]
66- new [3 ] &= ~ termios .ECHO # 3 == 'lflags'
67- tcsetattr_flags = termios .TCSAFLUSH
68- if hasattr (termios , 'TCSASOFT' ):
69- tcsetattr_flags |= termios .TCSASOFT
48+ # Always try reading and writing directly on the tty first.
49+ fd = os .open ('/dev/tty' , os .O_RDWR | os .O_NOCTTY )
50+ tty = io .FileIO (fd , 'w+' )
51+ stack .enter_context (tty )
52+ input = io .TextIOWrapper (tty )
53+ stack .enter_context (input )
54+ if not stream :
55+ stream = input
56+ except OSError as e :
57+ # If that fails, see if stdin can be controlled.
58+ stack .close ()
59+ try :
60+ fd = sys .stdin .fileno ()
61+ except (AttributeError , ValueError ):
62+ fd = None
63+ passwd = fallback_getpass (prompt , stream )
64+ input = sys .stdin
65+ if not stream :
66+ stream = sys .stderr
67+
68+ if fd is not None :
7069 try :
71- termios .tcsetattr (fd , tcsetattr_flags , new )
72- passwd = _raw_input (prompt , stream , input = input )
73- finally :
74- termios .tcsetattr (fd , tcsetattr_flags , old )
75- stream .flush () # issue7208
76- except termios .error :
77- if passwd is not None :
78- # _raw_input succeeded. The final tcsetattr failed. Reraise
79- # instead of leaving the terminal in an unknown state.
80- raise
81- # We can't control the tty or stdin. Give up and use normal IO.
82- # fallback_getpass() raises an appropriate warning.
83- del input , tty # clean up unused file objects before blocking
84- passwd = fallback_getpass (prompt , stream )
85-
86- stream .write ('\n ' )
87- return passwd
70+ old = termios .tcgetattr (fd ) # a copy to save
71+ new = old [:]
72+ new [3 ] &= ~ termios .ECHO # 3 == 'lflags'
73+ tcsetattr_flags = termios .TCSAFLUSH
74+ if hasattr (termios , 'TCSASOFT' ):
75+ tcsetattr_flags |= termios .TCSASOFT
76+ try :
77+ termios .tcsetattr (fd , tcsetattr_flags , new )
78+ passwd = _raw_input (prompt , stream , input = input )
79+ finally :
80+ termios .tcsetattr (fd , tcsetattr_flags , old )
81+ stream .flush () # issue7208
82+ except termios .error :
83+ if passwd is not None :
84+ # _raw_input succeeded. The final tcsetattr failed. Reraise
85+ # instead of leaving the terminal in an unknown state.
86+ raise
87+ # We can't control the tty or stdin. Give up and use normal IO.
88+ # fallback_getpass() raises an appropriate warning.
89+ if stream is not input :
90+ # clean up unused file objects before blocking
91+ stack .close ()
92+ passwd = fallback_getpass (prompt , stream )
93+
94+ stream .write ('\n ' )
95+ return passwd
8896
8997
9098def win_getpass (prompt = 'Password: ' , stream = None ):
0 commit comments