gh-140448: Default suggest_on_error to True in argparse.ArgumentParser (#140450)

This commit is contained in:
Jakob 2025-10-22 18:15:26 +02:00 committed by GitHub
parent d51be28876
commit d2f3cfd384
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 36 additions and 26 deletions

View file

@ -74,7 +74,7 @@ ArgumentParser objects
prefix_chars='-', fromfile_prefix_chars=None, \ prefix_chars='-', fromfile_prefix_chars=None, \
argument_default=None, conflict_handler='error', \ argument_default=None, conflict_handler='error', \
add_help=True, allow_abbrev=True, exit_on_error=True, \ add_help=True, allow_abbrev=True, exit_on_error=True, \
*, suggest_on_error=False, color=True) *, suggest_on_error=True, color=True)
Create a new :class:`ArgumentParser` object. All parameters should be passed Create a new :class:`ArgumentParser` object. All parameters should be passed
as keyword arguments. Each parameter has its own more detailed description as keyword arguments. Each parameter has its own more detailed description
@ -117,7 +117,7 @@ ArgumentParser objects
error info when an error occurs. (default: ``True``) error info when an error occurs. (default: ``True``)
* suggest_on_error_ - Enables suggestions for mistyped argument choices * suggest_on_error_ - Enables suggestions for mistyped argument choices
and subparser names (default: ``False``) and subparser names (default: ``True``)
* color_ - Allow color output (default: ``True``) * color_ - Allow color output (default: ``True``)
@ -134,6 +134,9 @@ ArgumentParser objects
.. versionchanged:: 3.14 .. versionchanged:: 3.14
*suggest_on_error* and *color* parameters were added. *suggest_on_error* and *color* parameters were added.
.. versionchanged:: 3.15
*suggest_on_error* default changed to ``True``.
The following sections describe how each of these are used. The following sections describe how each of these are used.
@ -596,13 +599,11 @@ suggest_on_error
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
By default, when a user passes an invalid argument choice or subparser name, By default, when a user passes an invalid argument choice or subparser name,
:class:`ArgumentParser` will exit with error info and list the permissible :class:`ArgumentParser` will exit with error info and provide suggestions for
argument choices (if specified) or subparser names as part of the error message. mistyped arguments. The error message will list the permissible argument
choices (if specified) or subparser names, along with a "maybe you meant"
If the user would like to enable suggestions for mistyped argument choices and suggestion if a close match is found. Note that this only applies for arguments
subparser names, the feature can be enabled by setting ``suggest_on_error`` to when the choices specified are strings::
``True``. Note that this only applies for arguments when the choices specified
are strings::
>>> parser = argparse.ArgumentParser(description='Process some integers.', >>> parser = argparse.ArgumentParser(description='Process some integers.',
suggest_on_error=True) suggest_on_error=True)
@ -612,16 +613,14 @@ are strings::
>>> parser.parse_args(['--action', 'sumn', 1, 2, 3]) >>> parser.parse_args(['--action', 'sumn', 1, 2, 3])
tester.py: error: argument --action: invalid choice: 'sumn', maybe you meant 'sum'? (choose from 'sum', 'max') tester.py: error: argument --action: invalid choice: 'sumn', maybe you meant 'sum'? (choose from 'sum', 'max')
If you're writing code that needs to be compatible with older Python versions You can disable suggestions by setting ``suggest_on_error`` to ``False``::
and want to opportunistically use ``suggest_on_error`` when it's available, you
can set it as an attribute after initializing the parser instead of using the
keyword argument::
>>> parser = argparse.ArgumentParser(description='Process some integers.') >>> parser = argparse.ArgumentParser(description='Process some integers.',
>>> parser.suggest_on_error = True suggest_on_error=False)
.. versionadded:: 3.14 .. versionadded:: 3.14
.. versionchanged:: 3.15
Changed default value of ``suggest_on_error`` from ``False`` to ``True``.
color color
^^^^^ ^^^^^

View file

@ -317,6 +317,13 @@ New modules
Improved modules Improved modules
================ ================
argparse
--------
* Changed the *suggest_on_error* parameter of :class:`argparse.ArgumentParser` to
default to ``True``. This enables suggestions for mistyped arguments by default.
(Contributed by Jakob Schluse in :gh:`140450`.)
calendar calendar
-------- --------

View file

@ -1857,7 +1857,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
- exit_on_error -- Determines whether or not ArgumentParser exits with - exit_on_error -- Determines whether or not ArgumentParser exits with
error info when an error occurs error info when an error occurs
- suggest_on_error - Enables suggestions for mistyped argument choices - suggest_on_error - Enables suggestions for mistyped argument choices
and subparser names (default: ``False``) and subparser names (default: ``True``)
- color - Allow color output in help messages (default: ``False``) - color - Allow color output in help messages (default: ``False``)
""" """
@ -1876,7 +1876,7 @@ def __init__(self,
allow_abbrev=True, allow_abbrev=True,
exit_on_error=True, exit_on_error=True,
*, *,
suggest_on_error=False, suggest_on_error=True,
color=True, color=True,
): ):
superinit = super(ArgumentParser, self).__init__ superinit = super(ArgumentParser, self).__init__

View file

@ -2287,7 +2287,7 @@ class TestArgumentAndSubparserSuggestions(TestCase):
"""Test error handling and suggestion when a user makes a typo""" """Test error handling and suggestion when a user makes a typo"""
def test_wrong_argument_error_with_suggestions(self): def test_wrong_argument_error_with_suggestions(self):
parser = ErrorRaisingArgumentParser(suggest_on_error=True) parser = ErrorRaisingArgumentParser()
parser.add_argument('foo', choices=['bar', 'baz']) parser.add_argument('foo', choices=['bar', 'baz'])
with self.assertRaises(ArgumentParserError) as excinfo: with self.assertRaises(ArgumentParserError) as excinfo:
parser.parse_args(('bazz',)) parser.parse_args(('bazz',))
@ -2307,7 +2307,7 @@ def test_wrong_argument_error_no_suggestions(self):
) )
def test_wrong_argument_subparsers_with_suggestions(self): def test_wrong_argument_subparsers_with_suggestions(self):
parser = ErrorRaisingArgumentParser(suggest_on_error=True) parser = ErrorRaisingArgumentParser()
subparsers = parser.add_subparsers(required=True) subparsers = parser.add_subparsers(required=True)
subparsers.add_parser('foo') subparsers.add_parser('foo')
subparsers.add_parser('bar') subparsers.add_parser('bar')
@ -2331,18 +2331,19 @@ def test_wrong_argument_subparsers_no_suggestions(self):
excinfo.exception.stderr, excinfo.exception.stderr,
) )
def test_wrong_argument_no_suggestion_implicit(self): def test_wrong_argument_with_suggestion_explicit(self):
parser = ErrorRaisingArgumentParser() parser = ErrorRaisingArgumentParser(suggest_on_error=True)
parser.add_argument('foo', choices=['bar', 'baz']) parser.add_argument('foo', choices=['bar', 'baz'])
with self.assertRaises(ArgumentParserError) as excinfo: with self.assertRaises(ArgumentParserError) as excinfo:
parser.parse_args(('bazz',)) parser.parse_args(('bazz',))
self.assertIn( self.assertIn(
"error: argument foo: invalid choice: 'bazz' (choose from bar, baz)", "error: argument foo: invalid choice: 'bazz', maybe you meant"
" 'baz'? (choose from bar, baz)",
excinfo.exception.stderr, excinfo.exception.stderr,
) )
def test_suggestions_choices_empty(self): def test_suggestions_choices_empty(self):
parser = ErrorRaisingArgumentParser(suggest_on_error=True) parser = ErrorRaisingArgumentParser()
parser.add_argument('foo', choices=[]) parser.add_argument('foo', choices=[])
with self.assertRaises(ArgumentParserError) as excinfo: with self.assertRaises(ArgumentParserError) as excinfo:
parser.parse_args(('bazz',)) parser.parse_args(('bazz',))
@ -2352,7 +2353,7 @@ def test_suggestions_choices_empty(self):
) )
def test_suggestions_choices_int(self): def test_suggestions_choices_int(self):
parser = ErrorRaisingArgumentParser(suggest_on_error=True) parser = ErrorRaisingArgumentParser()
parser.add_argument('foo', choices=[1, 2]) parser.add_argument('foo', choices=[1, 2])
with self.assertRaises(ArgumentParserError) as excinfo: with self.assertRaises(ArgumentParserError) as excinfo:
parser.parse_args(('3',)) parser.parse_args(('3',))
@ -2362,7 +2363,7 @@ def test_suggestions_choices_int(self):
) )
def test_suggestions_choices_mixed_types(self): def test_suggestions_choices_mixed_types(self):
parser = ErrorRaisingArgumentParser(suggest_on_error=True) parser = ErrorRaisingArgumentParser()
parser.add_argument('foo', choices=[1, '2']) parser.add_argument('foo', choices=[1, '2'])
with self.assertRaises(ArgumentParserError) as excinfo: with self.assertRaises(ArgumentParserError) as excinfo:
parser.parse_args(('3',)) parser.parse_args(('3',))

View file

@ -1681,6 +1681,7 @@ David Scherer
Wolfgang Scherer Wolfgang Scherer
Felix Scherz Felix Scherz
Hynek Schlawack Hynek Schlawack
Jakob Schluse
Bob Schmertz Bob Schmertz
Gregor Schmid Gregor Schmid
Ralf Schmitt Ralf Schmitt

View file

@ -0,0 +1,2 @@
Change the default of ``suggest_on_error`` to ``True`` in
``argparse.ArgumentParser``.