From 129db10d733fb086e1621c5f09d0758ce7f97220 Mon Sep 17 00:00:00 2001 From: paytonward6 <72841140+paytonward6@users.noreply.github.com> Date: Wed, 13 Dec 2023 21:22:43 -0600 Subject: [PATCH 1/6] Correct help output when reversing arguments containing a positional in a mutually exclusive group --- Lib/argparse.py | 8 ++++++-- Lib/test/test_argparse.py | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index a32884db80d1ea..27f691c6dd48c3 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -398,13 +398,17 @@ def _format_actions_usage(self, actions, groups): raise ValueError(f'empty group {group}') try: - start = actions.index(group._group_actions[0]) + start = _sys.maxsize + for item in group._group_actions: + index = actions.index(item) + if index < start: + start = index 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: diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 7c1f5d36999a3d..6bb93ea8538c8f 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -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("-", dest="FOO") + group.add_argument("baz", nargs="?") + expected = '''\ + usage: PROG [-h] (- FOO | baz) + + positional arguments: + baz + + options: + -h, --help show this help message and exit + - FOO + ''' + self.assertEqual(parser.format_help(), textwrap.dedent(expected)) + + parser = ErrorRaisingArgumentParser(prog="PROG") + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("baz", nargs="?") + group.add_argument("-", dest="FOO") + self.assertEqual(parser.format_help(), textwrap.dedent(expected)) + def test_empty_group(self): # See issue 26952 parser = argparse.ArgumentParser() From ce57b2e61c06ab4f1044a034b901b6c93fab5e12 Mon Sep 17 00:00:00 2001 From: paytonward6 <72841140+paytonward6@users.noreply.github.com> Date: Wed, 13 Dec 2023 21:33:40 -0600 Subject: [PATCH 2/6] Change baz to bar in argument names --- Lib/test/test_argparse.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 6bb93ea8538c8f..c787a319f155d1 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2840,12 +2840,12 @@ def test_optional_order(self): parser = ErrorRaisingArgumentParser(prog="PROG") group = parser.add_mutually_exclusive_group(required=True) group.add_argument("-", dest="FOO") - group.add_argument("baz", nargs="?") + group.add_argument("bar", nargs="?") expected = '''\ - usage: PROG [-h] (- FOO | baz) + usage: PROG [-h] (- FOO | bar) positional arguments: - baz + bar options: -h, --help show this help message and exit @@ -2855,7 +2855,7 @@ def test_optional_order(self): parser = ErrorRaisingArgumentParser(prog="PROG") group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("baz", nargs="?") + group.add_argument("bar", nargs="?") group.add_argument("-", dest="FOO") self.assertEqual(parser.format_help(), textwrap.dedent(expected)) From eb32d7171d0fefce9dbdf67a08646057a6e8817d Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 13:43:28 +0000 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst diff --git a/Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst b/Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst new file mode 100644 index 00000000000000..0f2a44299717c0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-14-13-43-27.gh-issue-113008.jWYn8T.rst @@ -0,0 +1 @@ +Correct argparse usage output for required, mutually exclusive groups containing a positional argument From 86deecb0e944b0b8cebc72cfe7f8a22337114d83 Mon Sep 17 00:00:00 2001 From: Payton <72841140+paytonward6@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:36:15 -0500 Subject: [PATCH 4/6] Use min as suggested in code review Co-authored-by: Serhiy Storchaka --- Lib/argparse.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 27f691c6dd48c3..7b4ceed414e292 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -398,11 +398,7 @@ def _format_actions_usage(self, actions, groups): raise ValueError(f'empty group {group}') try: - start = _sys.maxsize - for item in group._group_actions: - index = actions.index(item) - if index < start: - start = index + start = min(actions.index(item) for item in group._group_actions) except ValueError: continue else: From f706ef1df20e37b3181072895c09a89d0e5e8f1c Mon Sep 17 00:00:00 2001 From: paytonward6 Date: Mon, 23 Sep 2024 17:38:33 -0500 Subject: [PATCH 5/6] Use single quotes in test to maintain consistency --- Lib/test/test_argparse.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index c787a319f155d1..9d7c19a61d4a91 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2837,26 +2837,26 @@ def test_help(self): self.assertEqual(parser.format_help(), textwrap.dedent(expected)) def test_optional_order(self): - parser = ErrorRaisingArgumentParser(prog="PROG") + parser = ErrorRaisingArgumentParser(prog='PROG') group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("-", dest="FOO") - group.add_argument("bar", nargs="?") + group.add_argument('--foo') + group.add_argument('bar', nargs='?') expected = '''\ - usage: PROG [-h] (- FOO | bar) + usage: PROG [-h] (--foo FOO | bar) positional arguments: bar options: -h, --help show this help message and exit - - FOO + --foo FOO ''' self.assertEqual(parser.format_help(), textwrap.dedent(expected)) - parser = ErrorRaisingArgumentParser(prog="PROG") + parser = ErrorRaisingArgumentParser(prog='PROG') group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("bar", nargs="?") - group.add_argument("-", dest="FOO") + group.add_argument('bar', nargs='?') + group.add_argument('--foo') self.assertEqual(parser.format_help(), textwrap.dedent(expected)) def test_empty_group(self): From c1c80f4f9e9ab93c3bfdac00109bb1ecddaba64d Mon Sep 17 00:00:00 2001 From: paytonward6 Date: Tue, 24 Sep 2024 07:58:52 -0500 Subject: [PATCH 6/6] Remove unneeded space in test_argparse.py from merging --- Lib/test/test_argparse.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 9ff0c23101c8be..fb7e98f7fe5fa7 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2889,7 +2889,6 @@ def test_help_subparser_all_mutually_exclusive_group_members_suppressed(self): ''' self.assertEqual(cmd_foo.format_help(), textwrap.dedent(expected)) - def test_empty_group(self): # See issue 26952 parser = argparse.ArgumentParser()