mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Update get{opt,pass}.py from 3.14.3
This commit is contained in:
committed by
Jeong, YunWon
parent
bbe5412aea
commit
c29d2d9a1c
63
Lib/getopt.py
vendored
63
Lib/getopt.py
vendored
@@ -2,8 +2,8 @@
|
||||
|
||||
This module helps scripts to parse the command line arguments in
|
||||
sys.argv. It supports the same conventions as the Unix getopt()
|
||||
function (including the special meanings of arguments of the form `-'
|
||||
and `--'). Long options similar to those supported by GNU software
|
||||
function (including the special meanings of arguments of the form '-'
|
||||
and '--'). Long options similar to those supported by GNU software
|
||||
may be used as well via an optional third argument. This module
|
||||
provides two functions and an exception:
|
||||
|
||||
@@ -24,21 +24,14 @@ option involved with the exception.
|
||||
# TODO for gnu_getopt():
|
||||
#
|
||||
# - GNU getopt_long_only mechanism
|
||||
# - allow the caller to specify ordering
|
||||
# - RETURN_IN_ORDER option
|
||||
# - GNU extension with '-' as first character of option string
|
||||
# - optional arguments, specified by double colons
|
||||
# - an option string with a W followed by semicolon should
|
||||
# treat "-W foo" as "--foo"
|
||||
|
||||
__all__ = ["GetoptError","error","getopt","gnu_getopt"]
|
||||
|
||||
import os
|
||||
try:
|
||||
from gettext import gettext as _
|
||||
except ImportError:
|
||||
# Bootstrapping Python: gettext's dependencies not built yet
|
||||
def _(s): return s
|
||||
from gettext import gettext as _
|
||||
|
||||
|
||||
class GetoptError(Exception):
|
||||
opt = ''
|
||||
@@ -61,12 +54,14 @@ def getopt(args, shortopts, longopts = []):
|
||||
running program. Typically, this means "sys.argv[1:]". shortopts
|
||||
is the string of option letters that the script wants to
|
||||
recognize, with options that require an argument followed by a
|
||||
colon (i.e., the same format that Unix getopt() uses). If
|
||||
colon and options that accept an optional argument followed by
|
||||
two colons (i.e., the same format that Unix getopt() uses). If
|
||||
specified, longopts is a list of strings with the names of the
|
||||
long options which should be supported. The leading '--'
|
||||
characters should not be included in the option name. Options
|
||||
which require an argument should be followed by an equal sign
|
||||
('=').
|
||||
('='). Options which accept an optional argument should be
|
||||
followed by an equal sign and question mark ('=?').
|
||||
|
||||
The return value consists of two elements: the first is a list of
|
||||
(option, value) pairs; the second is the list of program arguments
|
||||
@@ -105,7 +100,7 @@ def gnu_getopt(args, shortopts, longopts = []):
|
||||
processing options as soon as a non-option argument is
|
||||
encountered.
|
||||
|
||||
If the first character of the option string is `+', or if the
|
||||
If the first character of the option string is '+', or if the
|
||||
environment variable POSIXLY_CORRECT is set, then option
|
||||
processing stops as soon as a non-option argument is encountered.
|
||||
|
||||
@@ -118,8 +113,13 @@ def gnu_getopt(args, shortopts, longopts = []):
|
||||
else:
|
||||
longopts = list(longopts)
|
||||
|
||||
return_in_order = False
|
||||
if shortopts.startswith('-'):
|
||||
shortopts = shortopts[1:]
|
||||
all_options_first = False
|
||||
return_in_order = True
|
||||
# Allow options after non-option arguments?
|
||||
if shortopts.startswith('+'):
|
||||
elif shortopts.startswith('+'):
|
||||
shortopts = shortopts[1:]
|
||||
all_options_first = True
|
||||
elif os.environ.get("POSIXLY_CORRECT"):
|
||||
@@ -133,8 +133,14 @@ def gnu_getopt(args, shortopts, longopts = []):
|
||||
break
|
||||
|
||||
if args[0][:2] == '--':
|
||||
if return_in_order and prog_args:
|
||||
opts.append((None, prog_args))
|
||||
prog_args = []
|
||||
opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
|
||||
elif args[0][:1] == '-' and args[0] != '-':
|
||||
if return_in_order and prog_args:
|
||||
opts.append((None, prog_args))
|
||||
prog_args = []
|
||||
opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
|
||||
else:
|
||||
if all_options_first:
|
||||
@@ -156,7 +162,7 @@ def do_longs(opts, opt, longopts, args):
|
||||
|
||||
has_arg, opt = long_has_args(opt, longopts)
|
||||
if has_arg:
|
||||
if optarg is None:
|
||||
if optarg is None and has_arg != '?':
|
||||
if not args:
|
||||
raise GetoptError(_('option --%s requires argument') % opt, opt)
|
||||
optarg, args = args[0], args[1:]
|
||||
@@ -177,13 +183,19 @@ def long_has_args(opt, longopts):
|
||||
return False, opt
|
||||
elif opt + '=' in possibilities:
|
||||
return True, opt
|
||||
# No exact match, so better be unique.
|
||||
elif opt + '=?' in possibilities:
|
||||
return '?', opt
|
||||
# Possibilities must be unique to be accepted
|
||||
if len(possibilities) > 1:
|
||||
# XXX since possibilities contains all valid continuations, might be
|
||||
# nice to work them into the error msg
|
||||
raise GetoptError(_('option --%s not a unique prefix') % opt, opt)
|
||||
raise GetoptError(
|
||||
_("option --%s not a unique prefix; possible options: %s")
|
||||
% (opt, ", ".join(possibilities)),
|
||||
opt,
|
||||
)
|
||||
assert len(possibilities) == 1
|
||||
unique_match = possibilities[0]
|
||||
if unique_match.endswith('=?'):
|
||||
return '?', unique_match[:-2]
|
||||
has_arg = unique_match.endswith('=')
|
||||
if has_arg:
|
||||
unique_match = unique_match[:-1]
|
||||
@@ -192,8 +204,9 @@ def long_has_args(opt, longopts):
|
||||
def do_shorts(opts, optstring, shortopts, args):
|
||||
while optstring != '':
|
||||
opt, optstring = optstring[0], optstring[1:]
|
||||
if short_has_arg(opt, shortopts):
|
||||
if optstring == '':
|
||||
has_arg = short_has_arg(opt, shortopts)
|
||||
if has_arg:
|
||||
if optstring == '' and has_arg != '?':
|
||||
if not args:
|
||||
raise GetoptError(_('option -%s requires argument') % opt,
|
||||
opt)
|
||||
@@ -207,7 +220,11 @@ def do_shorts(opts, optstring, shortopts, args):
|
||||
def short_has_arg(opt, shortopts):
|
||||
for i in range(len(shortopts)):
|
||||
if opt == shortopts[i] != ':':
|
||||
return shortopts.startswith(':', i+1)
|
||||
if not shortopts.startswith(':', i+1):
|
||||
return False
|
||||
if shortopts.startswith('::', i+1):
|
||||
return '?'
|
||||
return True
|
||||
raise GetoptError(_('option -%s not recognized') % opt, opt)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
78
Lib/getpass.py
vendored
78
Lib/getpass.py
vendored
@@ -1,6 +1,7 @@
|
||||
"""Utilities to get a password and/or the current user name.
|
||||
|
||||
getpass(prompt[, stream]) - Prompt for a password, with echo turned off.
|
||||
getpass(prompt[, stream[, echo_char]]) - Prompt for a password, with echo
|
||||
turned off and optional keyboard feedback.
|
||||
getuser() - Get the user name from the environment or password database.
|
||||
|
||||
GetPassWarning - This UserWarning is issued when getpass() cannot prevent
|
||||
@@ -25,13 +26,15 @@ __all__ = ["getpass","getuser","GetPassWarning"]
|
||||
class GetPassWarning(UserWarning): pass
|
||||
|
||||
|
||||
def unix_getpass(prompt='Password: ', stream=None):
|
||||
def unix_getpass(prompt='Password: ', stream=None, *, echo_char=None):
|
||||
"""Prompt for a password, with echo turned off.
|
||||
|
||||
Args:
|
||||
prompt: Written on stream to ask for the input. Default: 'Password: '
|
||||
stream: A writable file object to display the prompt. Defaults to
|
||||
the tty. If no tty is available defaults to sys.stderr.
|
||||
echo_char: A single ASCII character to mask input (e.g., '*').
|
||||
If None, input is hidden.
|
||||
Returns:
|
||||
The seKr3t input.
|
||||
Raises:
|
||||
@@ -40,6 +43,8 @@ def unix_getpass(prompt='Password: ', stream=None):
|
||||
|
||||
Always restores terminal settings before returning.
|
||||
"""
|
||||
_check_echo_char(echo_char)
|
||||
|
||||
passwd = None
|
||||
with contextlib.ExitStack() as stack:
|
||||
try:
|
||||
@@ -68,12 +73,16 @@ def unix_getpass(prompt='Password: ', stream=None):
|
||||
old = termios.tcgetattr(fd) # a copy to save
|
||||
new = old[:]
|
||||
new[3] &= ~termios.ECHO # 3 == 'lflags'
|
||||
if echo_char:
|
||||
new[3] &= ~termios.ICANON
|
||||
tcsetattr_flags = termios.TCSAFLUSH
|
||||
if hasattr(termios, 'TCSASOFT'):
|
||||
tcsetattr_flags |= termios.TCSASOFT
|
||||
try:
|
||||
termios.tcsetattr(fd, tcsetattr_flags, new)
|
||||
passwd = _raw_input(prompt, stream, input=input)
|
||||
passwd = _raw_input(prompt, stream, input=input,
|
||||
echo_char=echo_char)
|
||||
|
||||
finally:
|
||||
termios.tcsetattr(fd, tcsetattr_flags, old)
|
||||
stream.flush() # issue7208
|
||||
@@ -93,10 +102,11 @@ def unix_getpass(prompt='Password: ', stream=None):
|
||||
return passwd
|
||||
|
||||
|
||||
def win_getpass(prompt='Password: ', stream=None):
|
||||
def win_getpass(prompt='Password: ', stream=None, *, echo_char=None):
|
||||
"""Prompt for password with echo off, using Windows getwch()."""
|
||||
if sys.stdin is not sys.__stdin__:
|
||||
return fallback_getpass(prompt, stream)
|
||||
_check_echo_char(echo_char)
|
||||
|
||||
for c in prompt:
|
||||
msvcrt.putwch(c)
|
||||
@@ -108,25 +118,48 @@ def win_getpass(prompt='Password: ', stream=None):
|
||||
if c == '\003':
|
||||
raise KeyboardInterrupt
|
||||
if c == '\b':
|
||||
if echo_char and pw:
|
||||
msvcrt.putwch('\b')
|
||||
msvcrt.putwch(' ')
|
||||
msvcrt.putwch('\b')
|
||||
pw = pw[:-1]
|
||||
else:
|
||||
pw = pw + c
|
||||
if echo_char:
|
||||
msvcrt.putwch(echo_char)
|
||||
msvcrt.putwch('\r')
|
||||
msvcrt.putwch('\n')
|
||||
return pw
|
||||
|
||||
|
||||
def fallback_getpass(prompt='Password: ', stream=None):
|
||||
def fallback_getpass(prompt='Password: ', stream=None, *, echo_char=None):
|
||||
_check_echo_char(echo_char)
|
||||
import warnings
|
||||
warnings.warn("Can not control echo on the terminal.", GetPassWarning,
|
||||
stacklevel=2)
|
||||
if not stream:
|
||||
stream = sys.stderr
|
||||
print("Warning: Password input may be echoed.", file=stream)
|
||||
return _raw_input(prompt, stream)
|
||||
return _raw_input(prompt, stream, echo_char=echo_char)
|
||||
|
||||
|
||||
def _raw_input(prompt="", stream=None, input=None):
|
||||
def _check_echo_char(echo_char):
|
||||
# Single-character ASCII excluding control characters
|
||||
if echo_char is None:
|
||||
return
|
||||
if not isinstance(echo_char, str):
|
||||
raise TypeError("'echo_char' must be a str or None, not "
|
||||
f"{type(echo_char).__name__}")
|
||||
if not (
|
||||
len(echo_char) == 1
|
||||
and echo_char.isprintable()
|
||||
and echo_char.isascii()
|
||||
):
|
||||
raise ValueError("'echo_char' must be a single printable ASCII "
|
||||
f"character, got: {echo_char!r}")
|
||||
|
||||
|
||||
def _raw_input(prompt="", stream=None, input=None, echo_char=None):
|
||||
# This doesn't save the string in the GNU readline history.
|
||||
if not stream:
|
||||
stream = sys.stderr
|
||||
@@ -143,6 +176,8 @@ def _raw_input(prompt="", stream=None, input=None):
|
||||
stream.write(prompt)
|
||||
stream.flush()
|
||||
# NOTE: The Python C API calls flockfile() (and unlock) during readline.
|
||||
if echo_char:
|
||||
return _readline_with_echo_char(stream, input, echo_char)
|
||||
line = input.readline()
|
||||
if not line:
|
||||
raise EOFError
|
||||
@@ -151,6 +186,35 @@ def _raw_input(prompt="", stream=None, input=None):
|
||||
return line
|
||||
|
||||
|
||||
def _readline_with_echo_char(stream, input, echo_char):
|
||||
passwd = ""
|
||||
eof_pressed = False
|
||||
while True:
|
||||
char = input.read(1)
|
||||
if char == '\n' or char == '\r':
|
||||
break
|
||||
elif char == '\x03':
|
||||
raise KeyboardInterrupt
|
||||
elif char == '\x7f' or char == '\b':
|
||||
if passwd:
|
||||
stream.write("\b \b")
|
||||
stream.flush()
|
||||
passwd = passwd[:-1]
|
||||
elif char == '\x04':
|
||||
if eof_pressed:
|
||||
break
|
||||
else:
|
||||
eof_pressed = True
|
||||
elif char == '\x00':
|
||||
continue
|
||||
else:
|
||||
passwd += char
|
||||
stream.write(echo_char)
|
||||
stream.flush()
|
||||
eof_pressed = False
|
||||
return passwd
|
||||
|
||||
|
||||
def getuser():
|
||||
"""Get the username from the environment or password database.
|
||||
|
||||
|
||||
87
Lib/test/test_getopt.py
vendored
87
Lib/test/test_getopt.py
vendored
@@ -19,21 +19,34 @@ class GetoptTests(unittest.TestCase):
|
||||
self.assertRaises(getopt.GetoptError, *args, **kwargs)
|
||||
|
||||
def test_short_has_arg(self):
|
||||
self.assertTrue(getopt.short_has_arg('a', 'a:'))
|
||||
self.assertFalse(getopt.short_has_arg('a', 'a'))
|
||||
self.assertIs(getopt.short_has_arg('a', 'a:'), True)
|
||||
self.assertIs(getopt.short_has_arg('a', 'a'), False)
|
||||
self.assertEqual(getopt.short_has_arg('a', 'a::'), '?')
|
||||
self.assertError(getopt.short_has_arg, 'a', 'b')
|
||||
|
||||
def test_long_has_args(self):
|
||||
has_arg, option = getopt.long_has_args('abc', ['abc='])
|
||||
self.assertTrue(has_arg)
|
||||
self.assertIs(has_arg, True)
|
||||
self.assertEqual(option, 'abc')
|
||||
|
||||
has_arg, option = getopt.long_has_args('abc', ['abc'])
|
||||
self.assertFalse(has_arg)
|
||||
self.assertIs(has_arg, False)
|
||||
self.assertEqual(option, 'abc')
|
||||
|
||||
has_arg, option = getopt.long_has_args('abc', ['abc=?'])
|
||||
self.assertEqual(has_arg, '?')
|
||||
self.assertEqual(option, 'abc')
|
||||
|
||||
has_arg, option = getopt.long_has_args('abc', ['abcd='])
|
||||
self.assertIs(has_arg, True)
|
||||
self.assertEqual(option, 'abcd')
|
||||
|
||||
has_arg, option = getopt.long_has_args('abc', ['abcd'])
|
||||
self.assertFalse(has_arg)
|
||||
self.assertIs(has_arg, False)
|
||||
self.assertEqual(option, 'abcd')
|
||||
|
||||
has_arg, option = getopt.long_has_args('abc', ['abcd=?'])
|
||||
self.assertEqual(has_arg, '?')
|
||||
self.assertEqual(option, 'abcd')
|
||||
|
||||
self.assertError(getopt.long_has_args, 'abc', ['def'])
|
||||
@@ -49,9 +62,9 @@ class GetoptTests(unittest.TestCase):
|
||||
self.assertEqual(opts, [('-a', '1')])
|
||||
self.assertEqual(args, [])
|
||||
|
||||
#opts, args = getopt.do_shorts([], 'a=1', 'a:', [])
|
||||
#self.assertEqual(opts, [('-a', '1')])
|
||||
#self.assertEqual(args, [])
|
||||
opts, args = getopt.do_shorts([], 'a=1', 'a:', [])
|
||||
self.assertEqual(opts, [('-a', '=1')])
|
||||
self.assertEqual(args, [])
|
||||
|
||||
opts, args = getopt.do_shorts([], 'a', 'a:', ['1'])
|
||||
self.assertEqual(opts, [('-a', '1')])
|
||||
@@ -61,6 +74,14 @@ class GetoptTests(unittest.TestCase):
|
||||
self.assertEqual(opts, [('-a', '1')])
|
||||
self.assertEqual(args, ['2'])
|
||||
|
||||
opts, args = getopt.do_shorts([], 'a', 'a::', ['1'])
|
||||
self.assertEqual(opts, [('-a', '')])
|
||||
self.assertEqual(args, ['1'])
|
||||
|
||||
opts, args = getopt.do_shorts([], 'a1', 'a::', [])
|
||||
self.assertEqual(opts, [('-a', '1')])
|
||||
self.assertEqual(args, [])
|
||||
|
||||
self.assertError(getopt.do_shorts, [], 'a1', 'a', [])
|
||||
self.assertError(getopt.do_shorts, [], 'a', 'a:', [])
|
||||
|
||||
@@ -77,6 +98,22 @@ class GetoptTests(unittest.TestCase):
|
||||
self.assertEqual(opts, [('--abcd', '1')])
|
||||
self.assertEqual(args, [])
|
||||
|
||||
opts, args = getopt.do_longs([], 'abc', ['abc=?'], ['1'])
|
||||
self.assertEqual(opts, [('--abc', '')])
|
||||
self.assertEqual(args, ['1'])
|
||||
|
||||
opts, args = getopt.do_longs([], 'abc', ['abcd=?'], ['1'])
|
||||
self.assertEqual(opts, [('--abcd', '')])
|
||||
self.assertEqual(args, ['1'])
|
||||
|
||||
opts, args = getopt.do_longs([], 'abc=1', ['abc=?'], [])
|
||||
self.assertEqual(opts, [('--abc', '1')])
|
||||
self.assertEqual(args, [])
|
||||
|
||||
opts, args = getopt.do_longs([], 'abc=1', ['abcd=?'], [])
|
||||
self.assertEqual(opts, [('--abcd', '1')])
|
||||
self.assertEqual(args, [])
|
||||
|
||||
opts, args = getopt.do_longs([], 'abc', ['ab', 'abc', 'abcd'], [])
|
||||
self.assertEqual(opts, [('--abc', '')])
|
||||
self.assertEqual(args, [])
|
||||
@@ -95,7 +132,7 @@ class GetoptTests(unittest.TestCase):
|
||||
# note: the empty string between '-a' and '--beta' is significant:
|
||||
# it simulates an empty string option argument ('-a ""') on the
|
||||
# command line.
|
||||
cmdline = ['-a', '1', '-b', '--alpha=2', '--beta', '-a', '3', '-a',
|
||||
cmdline = ['-a1', '-b', '--alpha=2', '--beta', '-a', '3', '-a',
|
||||
'', '--beta', 'arg1', 'arg2']
|
||||
|
||||
opts, args = getopt.getopt(cmdline, 'a:b', ['alpha=', 'beta'])
|
||||
@@ -106,33 +143,53 @@ class GetoptTests(unittest.TestCase):
|
||||
# accounted for in the code that calls getopt().
|
||||
self.assertEqual(args, ['arg1', 'arg2'])
|
||||
|
||||
cmdline = ['-a1', '--alpha=2', '--alpha=', '-a', '--alpha', 'arg1', 'arg2']
|
||||
opts, args = getopt.getopt(cmdline, 'a::', ['alpha=?'])
|
||||
self.assertEqual(opts, [('-a', '1'), ('--alpha', '2'), ('--alpha', ''),
|
||||
('-a', ''), ('--alpha', '')])
|
||||
self.assertEqual(args, ['arg1', 'arg2'])
|
||||
|
||||
self.assertError(getopt.getopt, cmdline, 'a:b', ['alpha', 'beta'])
|
||||
|
||||
def test_gnu_getopt(self):
|
||||
# Test handling of GNU style scanning mode.
|
||||
cmdline = ['-a', 'arg1', '-b', '1', '--alpha', '--beta=2']
|
||||
cmdline = ['-a', 'arg1', '-b', '1', '--alpha', '--beta=2', '--beta',
|
||||
'3', 'arg2']
|
||||
|
||||
# GNU style
|
||||
opts, args = getopt.gnu_getopt(cmdline, 'ab:', ['alpha', 'beta='])
|
||||
self.assertEqual(args, ['arg1'])
|
||||
self.assertEqual(opts, [('-a', ''), ('-b', '1'),
|
||||
('--alpha', ''), ('--beta', '2')])
|
||||
self.assertEqual(args, ['arg1', 'arg2'])
|
||||
self.assertEqual(opts, [('-a', ''), ('-b', '1'), ('--alpha', ''),
|
||||
('--beta', '2'), ('--beta', '3')])
|
||||
|
||||
opts, args = getopt.gnu_getopt(cmdline, 'ab::', ['alpha', 'beta=?'])
|
||||
self.assertEqual(args, ['arg1', '1', '3', 'arg2'])
|
||||
self.assertEqual(opts, [('-a', ''), ('-b', ''), ('--alpha', ''),
|
||||
('--beta', '2'), ('--beta', '')])
|
||||
|
||||
# recognize "-" as an argument
|
||||
opts, args = getopt.gnu_getopt(['-a', '-', '-b', '-'], 'ab:', [])
|
||||
self.assertEqual(args, ['-'])
|
||||
self.assertEqual(opts, [('-a', ''), ('-b', '-')])
|
||||
|
||||
# Return positional arguments intermixed with options.
|
||||
opts, args = getopt.gnu_getopt(cmdline, '-ab:', ['alpha', 'beta='])
|
||||
self.assertEqual(args, ['arg2'])
|
||||
self.assertEqual(opts, [('-a', ''), (None, ['arg1']), ('-b', '1'), ('--alpha', ''),
|
||||
('--beta', '2'), ('--beta', '3')])
|
||||
|
||||
# Posix style via +
|
||||
opts, args = getopt.gnu_getopt(cmdline, '+ab:', ['alpha', 'beta='])
|
||||
self.assertEqual(opts, [('-a', '')])
|
||||
self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2'])
|
||||
self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2',
|
||||
'--beta', '3', 'arg2'])
|
||||
|
||||
# Posix style via POSIXLY_CORRECT
|
||||
self.env["POSIXLY_CORRECT"] = "1"
|
||||
opts, args = getopt.gnu_getopt(cmdline, 'ab:', ['alpha', 'beta='])
|
||||
self.assertEqual(opts, [('-a', '')])
|
||||
self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2'])
|
||||
self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2',
|
||||
'--beta', '3', 'arg2'])
|
||||
|
||||
def test_issue4629(self):
|
||||
longopts, shortopts = getopt.getopt(['--help='], '', ['help='])
|
||||
|
||||
75
Lib/test/test_getpass.py
vendored
75
Lib/test/test_getpass.py
vendored
@@ -161,6 +161,81 @@ class UnixGetpassTest(unittest.TestCase):
|
||||
self.assertIn('Warning', stderr.getvalue())
|
||||
self.assertIn('Password:', stderr.getvalue())
|
||||
|
||||
def test_echo_char_replaces_input_with_asterisks(self):
|
||||
mock_result = '*************'
|
||||
with mock.patch('os.open') as os_open, \
|
||||
mock.patch('io.FileIO'), \
|
||||
mock.patch('io.TextIOWrapper') as textio, \
|
||||
mock.patch('termios.tcgetattr'), \
|
||||
mock.patch('termios.tcsetattr'), \
|
||||
mock.patch('getpass._raw_input') as mock_input:
|
||||
os_open.return_value = 3
|
||||
mock_input.return_value = mock_result
|
||||
|
||||
result = getpass.unix_getpass(echo_char='*')
|
||||
mock_input.assert_called_once_with('Password: ', textio(),
|
||||
input=textio(), echo_char='*')
|
||||
self.assertEqual(result, mock_result)
|
||||
|
||||
def test_raw_input_with_echo_char(self):
|
||||
passwd = 'my1pa$$word!'
|
||||
mock_input = StringIO(f'{passwd}\n')
|
||||
mock_output = StringIO()
|
||||
with mock.patch('sys.stdin', mock_input), \
|
||||
mock.patch('sys.stdout', mock_output):
|
||||
result = getpass._raw_input('Password: ', mock_output, mock_input,
|
||||
'*')
|
||||
self.assertEqual(result, passwd)
|
||||
self.assertEqual('Password: ************', mock_output.getvalue())
|
||||
|
||||
def test_control_chars_with_echo_char(self):
|
||||
passwd = 'pass\twd\b'
|
||||
expect_result = 'pass\tw'
|
||||
mock_input = StringIO(f'{passwd}\n')
|
||||
mock_output = StringIO()
|
||||
with mock.patch('sys.stdin', mock_input), \
|
||||
mock.patch('sys.stdout', mock_output):
|
||||
result = getpass._raw_input('Password: ', mock_output, mock_input,
|
||||
'*')
|
||||
self.assertEqual(result, expect_result)
|
||||
self.assertEqual('Password: *******\x08 \x08', mock_output.getvalue())
|
||||
|
||||
|
||||
class GetpassEchoCharTest(unittest.TestCase):
|
||||
|
||||
def test_accept_none(self):
|
||||
getpass._check_echo_char(None)
|
||||
|
||||
@support.subTests('echo_char', ["*", "A", " "])
|
||||
def test_accept_single_printable_ascii(self, echo_char):
|
||||
getpass._check_echo_char(echo_char)
|
||||
|
||||
def test_reject_empty_string(self):
|
||||
self.assertRaises(ValueError, getpass.getpass, echo_char="")
|
||||
|
||||
@support.subTests('echo_char', ["***", "AA", "aA*!"])
|
||||
def test_reject_multi_character_strings(self, echo_char):
|
||||
self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char)
|
||||
|
||||
@support.subTests('echo_char', [
|
||||
'\N{LATIN CAPITAL LETTER AE}', # non-ASCII single character
|
||||
'\N{HEAVY BLACK HEART}', # non-ASCII multibyte character
|
||||
])
|
||||
def test_reject_non_ascii(self, echo_char):
|
||||
self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char)
|
||||
|
||||
@support.subTests('echo_char', [
|
||||
ch for ch in map(chr, range(0, 128))
|
||||
if not ch.isprintable()
|
||||
])
|
||||
def test_reject_non_printable_characters(self, echo_char):
|
||||
self.assertRaises(ValueError, getpass.getpass, echo_char=echo_char)
|
||||
|
||||
# TypeError Rejection
|
||||
@support.subTests('echo_char', [b"*", 0, 0.0, [], {}])
|
||||
def test_reject_non_string(self, echo_char):
|
||||
self.assertRaises(TypeError, getpass.getpass, echo_char=echo_char)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user