Skip to content
4 changes: 2 additions & 2 deletions Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,13 +398,13 @@ def _format_actions_usage(self, actions, groups):
raise ValueError(f'empty group {group}')

try:
start = actions.index(group._group_actions[0])
start = min(actions.index(item) for item in group._group_actions)
except ValueError:
continue
else:
group_action_count = len(group._group_actions)
end = start + group_action_count
if actions[start:end] == group._group_actions:
if set(actions[start:end]) == set(group._group_actions):

suppressed_actions_count = 0
for action in group._group_actions:
Expand Down
23 changes: 23 additions & 0 deletions Lib/test/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -2836,6 +2836,29 @@ def test_help(self):
'''
self.assertEqual(parser.format_help(), textwrap.dedent(expected))

def test_optional_order(self):
parser = ErrorRaisingArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--foo')
group.add_argument('bar', nargs='?')
expected = '''\
usage: PROG [-h] (--foo FOO | bar)

positional arguments:
bar

options:
-h, --help show this help message and exit
--foo FOO
'''
self.assertEqual(parser.format_help(), textwrap.dedent(expected))

parser = ErrorRaisingArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('bar', nargs='?')
group.add_argument('--foo')
self.assertEqual(parser.format_help(), textwrap.dedent(expected))

def test_empty_group(self):
# See issue 26952
parser = argparse.ArgumentParser()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Correct argparse usage output for required, mutually exclusive groups containing a positional argument