diff --git a/Lib/argparse.py b/Lib/argparse.py index 240625ff01084e..dd25d6e410e2d2 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -85,6 +85,7 @@ ] +import difflib as _difflib import os as _os import re as _re import sys as _sys @@ -2541,11 +2542,28 @@ 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 and closest_choice[0] or None: + args['closest_choice'] = closest_choice + msg = _('invalid choice: %(value)r, maybe you meant' + ' %(closest_choice)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..721203a4c2fd97 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2193,9 +2193,10 @@ 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/Library/2022-11-28-06-46-19.gh-issue-99749.MZhWOX.rst b/Misc/NEWS.d/next/Library/2022-11-28-06-46-19.gh-issue-99749.MZhWOX.rst new file mode 100644 index 00000000000000..99932336901bb7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-11-28-06-46-19.gh-issue-99749.MZhWOX.rst @@ -0,0 +1 @@ +Add closest choice if exists in Argparser if wrong choice picked.