From 20490d5018cff4c604b37142323c531f8512b9aa Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Tue, 3 May 2022 09:38:18 -0700 Subject: [PATCH] gh-88753: Make BooleanOptionalAction's addition of default to help more similar to other actions (#27808) Help for other actions omit the default value if default is SUPPRESS or already contains the special format string '%(default)'. Add those special cases to BooleanOptionalAction's help formatting too. Fixes https://bugs.python.org/issue44587 so that default=SUPPRESS is not emitted. Fixes https://bugs.python.org/issue38956 as this code will detect whether '%(default)s' has already been specified in the help string. Signed-off-by: Micky Yun Chan (michiboo): Co-authored-by: Micky Yun Chan --- Lib/argparse.py | 20 ++++++++++---- Lib/test/test_argparse.py | 26 +++++++++++-------- .../2021-08-17-21-41-39.bpo-44587.57OKSz.rst | 2 ++ 3 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-08-17-21-41-39.bpo-44587.57OKSz.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index c47aeffc2c3f6c..8d1a00ad2207e5 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -153,6 +153,7 @@ def _copy_items(items): # Formatting Help # =============== + class HelpFormatter(object): """Formatter for generating usage messages and argument help strings. @@ -695,8 +696,19 @@ class ArgumentDefaultsHelpFormatter(HelpFormatter): """ def _get_help_string(self, action): + """ + Add the default value to the option help message. + + ArgumentDefaultsHelpFormatter and BooleanOptionalAction when it isn't + already present. This code will do that, detecting cornercases to + prevent duplicates or cases where it wouldn't make sense to the end + user. + """ help = action.help - if '%(default)' not in action.help: + if help is None: + help = '' + + if '%(default)' not in help: if action.default is not SUPPRESS: defaulting_nargs = [OPTIONAL, ZERO_OR_MORE] if action.option_strings or action.nargs in defaulting_nargs: @@ -704,6 +716,7 @@ def _get_help_string(self, action): return help + class MetavarTypeHelpFormatter(HelpFormatter): """Help message formatter which uses the argument 'type' as the default metavar value (instead of the argument 'dest') @@ -719,7 +732,6 @@ def _get_default_metavar_for_positional(self, action): return action.type.__name__ - # ===================== # Options and Arguments # ===================== @@ -882,9 +894,6 @@ def __init__(self, option_string = '--no-' + option_string[2:] _option_strings.append(option_string) - if help is not None and default is not None and default is not SUPPRESS: - help += " (default: %(default)s)" - super().__init__( option_strings=_option_strings, dest=dest, @@ -896,6 +905,7 @@ def __init__(self, help=help, metavar=metavar) + def __call__(self, parser, namespace, values, option_string=None): if option_string in self.option_strings: setattr(namespace, self.dest, not option_string.startswith('--no-')) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 794b9df3796df4..8509deb93f1e23 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -3348,6 +3348,7 @@ def _get_parser(self, tester): def _test(self, tester, parser_text): expected_text = getattr(tester, self.func_suffix) expected_text = textwrap.dedent(expected_text) + tester.maxDiff = None tester.assertEqual(expected_text, parser_text) def test_format(self, tester): @@ -3743,7 +3744,7 @@ class TestHelpUsage(HelpTestCase): -w W [W ...] w -x [X ...] x --foo, --no-foo Whether to foo - --bar, --no-bar Whether to bar (default: True) + --bar, --no-bar Whether to bar -f, --foobar, --no-foobar, --barfoo, --no-barfoo --bazz, --no-bazz Bazz! @@ -4423,6 +4424,8 @@ class TestHelpArgumentDefaults(HelpTestCase): Sig('--bar', action='store_true', help='bar help'), Sig('--taz', action=argparse.BooleanOptionalAction, help='Whether to taz it', default=True), + Sig('--corge', action=argparse.BooleanOptionalAction, + help='Whether to corge it', default=argparse.SUPPRESS), Sig('--quux', help="Set the quux", default=42), Sig('spam', help='spam help'), Sig('badger', nargs='?', default='wooden', help='badger help'), @@ -4432,8 +4435,8 @@ class TestHelpArgumentDefaults(HelpTestCase): [Sig('--baz', type=int, default=42, help='baz help')]), ] usage = '''\ - usage: PROG [-h] [--foo FOO] [--bar] [--taz | --no-taz] [--quux QUUX] - [--baz BAZ] + usage: PROG [-h] [--foo FOO] [--bar] [--taz | --no-taz] [--corge | --no-corge] + [--quux QUUX] [--baz BAZ] spam [badger] ''' help = usage + '''\ @@ -4441,20 +4444,21 @@ class TestHelpArgumentDefaults(HelpTestCase): description positional arguments: - spam spam help - badger badger help (default: wooden) + spam spam help + badger badger help (default: wooden) options: - -h, --help show this help message and exit - --foo FOO foo help - oh and by the way, None - --bar bar help (default: False) - --taz, --no-taz Whether to taz it (default: True) - --quux QUUX Set the quux (default: 42) + -h, --help show this help message and exit + --foo FOO foo help - oh and by the way, None + --bar bar help (default: False) + --taz, --no-taz Whether to taz it (default: True) + --corge, --no-corge Whether to corge it + --quux QUUX Set the quux (default: 42) title: description - --baz BAZ baz help (default: 42) + --baz BAZ baz help (default: 42) ''' version = '' diff --git a/Misc/NEWS.d/next/Library/2021-08-17-21-41-39.bpo-44587.57OKSz.rst b/Misc/NEWS.d/next/Library/2021-08-17-21-41-39.bpo-44587.57OKSz.rst new file mode 100644 index 00000000000000..ce9b3a04bc62f1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-08-17-21-41-39.bpo-44587.57OKSz.rst @@ -0,0 +1,2 @@ +Fix BooleanOptionalAction to not automatically add a default string. If a +default string is desired, use a formatter to add it.