Skip to content

Commit b3b4a9e

Browse files
committed
fixed
1 parent bfc9262 commit b3b4a9e

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

Lib/argparse.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
'ZERO_OR_MORE',
8585
]
8686

87-
87+
import difflib as _difflib
8888
import os as _os
8989
import re as _re
9090
import sys as _sys
@@ -2543,9 +2543,18 @@ def _get_value(self, action, arg_string):
25432543
def _check_value(self, action, value):
25442544
# converted value must be one of the choices (if specified)
25452545
if action.choices is not None and value not in action.choices:
2546-
args = {'value': value,
2547-
'choices': ', '.join(map(repr, action.choices))}
2548-
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
2546+
closest_choice = _difflib.get_close_matches(value, action.choices)
2547+
args = {
2548+
'value': value,
2549+
'choices': ', '.join(map(repr, action.choices)),
2550+
}
2551+
if closest_choice := closest_choice and closest_choice[0] or None:
2552+
args['closest'] = closest_choice
2553+
msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? '
2554+
'(choose from %(choices)s)')
2555+
else:
2556+
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
2557+
25492558
raise ArgumentError(action, msg % args)
25502559

25512560
# =======================

Lib/test/test_argparse.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2187,6 +2187,18 @@ def test_required_subparsers_no_destination_error(self):
21872187
)
21882188

21892189
def test_wrong_argument_subparsers_no_destination_error(self):
2190+
parser = ErrorRaisingArgumentParser()
2191+
subparsers = parser.add_subparsers(required=True)
2192+
subparsers.add_parser('foo')
2193+
subparsers.add_parser('bar')
2194+
with self.assertRaises(ArgumentParserError) as excinfo:
2195+
parser.parse_args(('test',))
2196+
self.assertRegex(
2197+
excinfo.exception.stderr,
2198+
r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$"
2199+
)
2200+
2201+
def test_wrong_argument_subparsers_no_destination_error_with_closest_choice_input(self):
21902202
parser = ErrorRaisingArgumentParser()
21912203
subparsers = parser.add_subparsers(required=True)
21922204
subparsers.add_parser('foo')
@@ -2195,7 +2207,7 @@ def test_wrong_argument_subparsers_no_destination_error(self):
21952207
parser.parse_args(('baz',))
21962208
self.assertRegex(
21972209
excinfo.exception.stderr,
2198-
r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$",
2210+
r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant bar? \(choose from 'foo', 'bar'\)\n$",
21992211
)
22002212

22012213
def test_optional_subparsers(self):

0 commit comments

Comments
 (0)