diff options
author | Savannah Ostrowski <savannahostrowski@gmail.com> | 2024-10-17 07:07:37 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-17 07:07:37 (GMT) |
commit | 624be8699aec22bef137041478078c6fafaf032e (patch) | |
tree | 9527b230b7e991a25536b6ce66b63b82d827f810 /Lib/argparse.py | |
parent | a5a7f5e16d8c3938d266703ea8fba8ffee3e3ae5 (diff) | |
download | cpython-624be8699aec22bef137041478078c6fafaf032e.zip cpython-624be8699aec22bef137041478078c6fafaf032e.tar.gz cpython-624be8699aec22bef137041478078c6fafaf032e.tar.bz2 |
GH-99749: Add optional feature to suggest correct names (ArgumentParser) (GH-124456)
Diffstat (limited to 'Lib/argparse.py')
-rw-r--r-- | Lib/argparse.py | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/Lib/argparse.py b/Lib/argparse.py index fa9f521..ece6f2e 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1773,6 +1773,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): - allow_abbrev -- Allow long options to be abbreviated unambiguously - exit_on_error -- Determines whether or not ArgumentParser exits with error info when an error occurs + - suggest_on_error - Enables suggestions for mistyped argument choices + and subparser names. (default: ``False``) """ def __init__(self, @@ -1788,7 +1790,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): conflict_handler='error', add_help=True, allow_abbrev=True, - exit_on_error=True): + exit_on_error=True, + suggest_on_error=False): superinit = super(ArgumentParser, self).__init__ superinit(description=description, @@ -1804,6 +1807,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): self.add_help = add_help self.allow_abbrev = allow_abbrev self.exit_on_error = exit_on_error + self.suggest_on_error = suggest_on_error add_group = self.add_argument_group self._positionals = add_group(_('positional arguments')) @@ -2601,14 +2605,27 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def _check_value(self, action, value): # converted value must be one of the choices (if specified) choices = action.choices - if choices is not None: - if isinstance(choices, str): - choices = iter(choices) - if value not in choices: - args = {'value': str(value), - 'choices': ', '.join(map(str, action.choices))} - msg = _('invalid choice: %(value)r (choose from %(choices)s)') - raise ArgumentError(action, msg % args) + if choices is None: + return + + if isinstance(choices, str): + choices = iter(choices) + + if value not in choices: + args = {'value': str(value), + 'choices': ', '.join(map(str, action.choices))} + msg = _('invalid choice: %(value)r (choose from %(choices)s)') + + if self.suggest_on_error and isinstance(value, str): + if all(isinstance(choice, str) for choice in action.choices): + import difflib + suggestions = difflib.get_close_matches(value, action.choices, 1) + if suggestions: + args['closest'] = suggestions[0] + msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' + '(choose from %(choices)s)') + + raise ArgumentError(action, msg % args) # ======================= # Help-formatting methods |