diff --git a/Lib/argparse.py b/Lib/argparse.py index 240625ff01084e..3e1c62714a2a78 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -84,7 +84,7 @@ 'ZERO_OR_MORE', ] - +import difflib as _difflib import os as _os import re as _re import sys as _sys @@ -2541,11 +2541,29 @@ def _get_value(self, action, arg_string): return result def _check_value(self, action, value): + if not action.choices and isinstance(action.choices, list): + msg = 'Either add options in choices array or remove it' + raise ArgumentError(action, msg) + # converted value must be one of the choices (if specified) if action.choices is not None and value not in action.choices: - args = {'value': value, - 'choices': ', '.join(map(repr, action.choices))} - msg = _('invalid choice: %(value)r (choose from %(choices)s)') + try: + closest_choice = _difflib.get_close_matches(value, action.choices, 1) + except TypeError: + closest_choice = [] + + args = { + 'value': value, + 'choices': ', '.join(map(repr, action.choices)), + } + if closest_choice: + closest_choice = closest_choice[0] + args['closest'] = closest_choice + msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' + '(choose from %(choices)s)') + else: + msg = _('invalid choice: %(value)r (choose from %(choices)s)') + raise ArgumentError(action, msg % args) # ======================= diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index cabb2f837693ff..ec289310367db3 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2193,9 +2193,9 @@ def test_wrong_argument_subparsers_no_destination_error(self): subparsers.add_parser('bar') with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('baz',)) - self.assertRegex( + self.assertIn( + "error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? (choose from 'foo', 'bar')", excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" ) def test_optional_subparsers(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst new file mode 100644 index 00000000000000..479d5e45f56fc1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst @@ -0,0 +1 @@ +Add closest choice if exists in Argparser if wrong choice picked.