mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
GH-99749: Add optional feature to suggest correct names (ArgumentParser) (GH-124456)
This commit is contained in:
parent
a5a7f5e16d
commit
624be8699a
4 changed files with 144 additions and 23 deletions
|
@ -2253,6 +2253,95 @@ class TestNegativeNumber(ParserTestCase):
|
|||
('--complex -1e-3j', NS(int=None, float=None, complex=-0.001j)),
|
||||
]
|
||||
|
||||
class TestArgumentAndSubparserSuggestions(TestCase):
|
||||
"""Test error handling and suggestion when a user makes a typo"""
|
||||
|
||||
def test_wrong_argument_error_with_suggestions(self):
|
||||
parser = ErrorRaisingArgumentParser(suggest_on_error=True)
|
||||
parser.add_argument('foo', choices=['bar', 'baz'])
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('bazz',))
|
||||
self.assertIn(
|
||||
"error: argument foo: invalid choice: 'bazz', maybe you meant 'baz'? (choose from bar, baz)",
|
||||
excinfo.exception.stderr
|
||||
)
|
||||
|
||||
def test_wrong_argument_error_no_suggestions(self):
|
||||
parser = ErrorRaisingArgumentParser(suggest_on_error=False)
|
||||
parser.add_argument('foo', choices=['bar', 'baz'])
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('bazz',))
|
||||
self.assertIn(
|
||||
"error: argument foo: invalid choice: 'bazz' (choose from bar, baz)",
|
||||
excinfo.exception.stderr,
|
||||
)
|
||||
|
||||
def test_wrong_argument_subparsers_with_suggestions(self):
|
||||
parser = ErrorRaisingArgumentParser(suggest_on_error=True)
|
||||
subparsers = parser.add_subparsers(required=True)
|
||||
subparsers.add_parser('foo')
|
||||
subparsers.add_parser('bar')
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('baz',))
|
||||
self.assertIn(
|
||||
"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant"
|
||||
" 'bar'? (choose from foo, bar)",
|
||||
excinfo.exception.stderr,
|
||||
)
|
||||
|
||||
def test_wrong_argument_subparsers_no_suggestions(self):
|
||||
parser = ErrorRaisingArgumentParser(suggest_on_error=False)
|
||||
subparsers = parser.add_subparsers(required=True)
|
||||
subparsers.add_parser('foo')
|
||||
subparsers.add_parser('bar')
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('baz',))
|
||||
self.assertIn(
|
||||
"error: argument {foo,bar}: invalid choice: 'baz' (choose from foo, bar)",
|
||||
excinfo.exception.stderr,
|
||||
)
|
||||
|
||||
def test_wrong_argument_no_suggestion_implicit(self):
|
||||
parser = ErrorRaisingArgumentParser()
|
||||
parser.add_argument('foo', choices=['bar', 'baz'])
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('bazz',))
|
||||
self.assertIn(
|
||||
"error: argument foo: invalid choice: 'bazz' (choose from bar, baz)",
|
||||
excinfo.exception.stderr,
|
||||
)
|
||||
|
||||
def test_suggestions_choices_empty(self):
|
||||
parser = ErrorRaisingArgumentParser(suggest_on_error=True)
|
||||
parser.add_argument('foo', choices=[])
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('bazz',))
|
||||
self.assertIn(
|
||||
"error: argument foo: invalid choice: 'bazz' (choose from )",
|
||||
excinfo.exception.stderr,
|
||||
)
|
||||
|
||||
def test_suggestions_choices_int(self):
|
||||
parser = ErrorRaisingArgumentParser(suggest_on_error=True)
|
||||
parser.add_argument('foo', choices=[1, 2])
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('3',))
|
||||
self.assertIn(
|
||||
"error: argument foo: invalid choice: '3' (choose from 1, 2)",
|
||||
excinfo.exception.stderr,
|
||||
)
|
||||
|
||||
def test_suggestions_choices_mixed_types(self):
|
||||
parser = ErrorRaisingArgumentParser(suggest_on_error=True)
|
||||
parser.add_argument('foo', choices=[1, '2'])
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('3',))
|
||||
self.assertIn(
|
||||
"error: argument foo: invalid choice: '3' (choose from 1, 2)",
|
||||
excinfo.exception.stderr,
|
||||
)
|
||||
|
||||
|
||||
class TestInvalidAction(TestCase):
|
||||
"""Test invalid user defined Action"""
|
||||
|
||||
|
@ -2505,18 +2594,6 @@ class TestAddSubparsers(TestCase):
|
|||
'error: the following arguments are required: {foo,bar}\n$'
|
||||
)
|
||||
|
||||
def test_wrong_argument_subparsers_no_destination_error(self):
|
||||
parser = ErrorRaisingArgumentParser()
|
||||
subparsers = parser.add_subparsers(required=True)
|
||||
subparsers.add_parser('foo')
|
||||
subparsers.add_parser('bar')
|
||||
with self.assertRaises(ArgumentParserError) as excinfo:
|
||||
parser.parse_args(('baz',))
|
||||
self.assertRegex(
|
||||
excinfo.exception.stderr,
|
||||
r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from foo, bar\)\n$"
|
||||
)
|
||||
|
||||
def test_optional_subparsers(self):
|
||||
parser = ErrorRaisingArgumentParser()
|
||||
subparsers = parser.add_subparsers(dest='command', required=False)
|
||||
|
@ -2862,7 +2939,7 @@ class TestParentParsers(TestCase):
|
|||
parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
|
||||
self._test_mutex_ab(parser.parse_args)
|
||||
|
||||
def test_single_granparent_mutex(self):
|
||||
def test_single_grandparent_mutex(self):
|
||||
parents = [self.ab_mutex_parent]
|
||||
parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
|
||||
parser = ErrorRaisingArgumentParser(parents=[parser])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue