diff --git a/Lib/argparse.py b/Lib/argparse.py index b69c5adfa072b9..7a546b1628d3e8 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -396,18 +396,19 @@ def _format_actions_usage(self, actions, groups): if actions[start:end] == group._group_actions: for action in group._group_actions: group_actions.add(action) - if not group.required: - if start in inserts: - inserts[start] += ' [' + if not isinstance(group._container, _MutuallyExclusiveGroup): + if not group.required: + if start in inserts: + inserts[start] += ' [' + else: + inserts[start] = '[' + inserts[end] = ']' else: - inserts[start] = '[' - inserts[end] = ']' - else: - if start in inserts: - inserts[start] += ' (' - else: - inserts[start] = '(' - inserts[end] = ')' + if start in inserts: + inserts[start] += ' (' + else: + inserts[start] = '(' + inserts[end] = ')' for i in range(start + 1, end): inserts[i] = '|' diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index a5c4a8ec97d7ad..6f1fe3c176900b 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2362,6 +2362,26 @@ def test_help(self): ''' self.assertEqual(parser.format_help(), textwrap.dedent(expected)) + def test_help_required(self): + parser = ErrorRaisingArgumentParser(prog='PROG') + group1 = parser.add_mutually_exclusive_group(required=True) + group1.add_argument('--foo', action='store_true') + group1.add_argument('--bar', action='store_false') + group2 = parser.add_mutually_exclusive_group(required=True) + group2.add_argument('--soup', action='store_true') + group2.add_argument('--nuts', action='store_false') + expected = '''\ + usage: PROG [-h] (--foo | --bar) (--soup | --nuts) + + optional arguments: + -h, --help show this help message and exit + --foo + --bar + --soup + --nuts + ''' + self.assertEqual(parser.format_help(), textwrap.dedent(expected)) + class MEMixin(object): def test_failures_when_not_required(self): @@ -2725,6 +2745,44 @@ def get_parser(self, required): -c c help ''' + +class TestMutuallyExclusiveNested(MEMixin, TestCase): + def get_parser(self, required): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_exclusive_group(required=required) + group.add_argument('-a') + group.add_argument('-b') + group2 = group.add_mutually_exclusive_group(required=required) + group2.add_argument('-c') + group2.add_argument('-d') + group3 = group2.add_mutually_exclusive_group(required=required) + group3.add_argument('-e') + group3.add_argument('-f') + return parser + + failures = [] + successes = [] + successes_when_not_required = [] + + usage_when_not_required = '''\ + usage: PROG [-h] [-a A | -b B | -c C | -d D | -e E | -f F] + ''' + usage_when_required = '''\ + usage: PROG [-h] (-a A | -b B | -c C | -d D | -e E | -f F) + ''' + + help = '''\ + + optional arguments: + -h, --help show this help message and exit + -a A + -b B + -c C + -d D + -e E + -f F + ''' + # ================================================= # Mutually exclusive group in parent parser tests # ================================================= diff --git a/Misc/NEWS b/Misc/NEWS index 57e5ab9c20fe71..5837dfe078e3e6 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -252,6 +252,8 @@ Library - bpo-29576: Improve some deprecations in importlib. Some deprecated methods now emit DeprecationWarnings and have better descriptive messages. +- bpo-29553: Fixed ArgumentParses format_usage for mutually exclusive groups. + - bpo-29534: Fixed different behaviour of Decimal.from_float() for _decimal and _pydecimal. Thanks Andrew Nester.