Skip to content

Commit 66b3922

Browse files
authored
gh-86357: argparse: use str() consistently and explicitly to print choices (GH-117766)
Signed-off-by: Jan Chren ~rindeal <[email protected]>
1 parent cfc27bc commit 66b3922

File tree

3 files changed

+36
-8
lines changed

3 files changed

+36
-8
lines changed

Lib/argparse.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,7 @@ def _metavar_formatter(self, action, default_metavar):
547547
if action.metavar is not None:
548548
result = action.metavar
549549
elif action.choices is not None:
550-
choice_strs = [str(choice) for choice in action.choices]
551-
result = '{%s}' % ','.join(choice_strs)
550+
result = '{%s}' % ','.join(map(str, action.choices))
552551
else:
553552
result = default_metavar
554553

@@ -599,8 +598,7 @@ def _expand_help(self, action):
599598
elif hasattr(value, '__name__'):
600599
params[name] = value.__name__
601600
if params.get('choices') is not None:
602-
choices_str = ', '.join([str(c) for c in params['choices']])
603-
params['choices'] = choices_str
601+
params['choices'] = ', '.join(map(str, params['choices']))
604602
return help_string % params
605603

606604
def _iter_indented_subactions(self, action):
@@ -717,7 +715,7 @@ def _get_action_name(argument):
717715
elif argument.dest not in (None, SUPPRESS):
718716
return argument.dest
719717
elif argument.choices:
720-
return '{' + ','.join(argument.choices) + '}'
718+
return '{%s}' % ','.join(map(str, argument.choices))
721719
else:
722720
return None
723721

@@ -2607,8 +2605,8 @@ def _check_value(self, action, value):
26072605
if isinstance(choices, str):
26082606
choices = iter(choices)
26092607
if value not in choices:
2610-
args = {'value': value,
2611-
'choices': ', '.join(map(repr, action.choices))}
2608+
args = {'value': str(value),
2609+
'choices': ', '.join(map(str, action.choices))}
26122610
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
26132611
raise ArgumentError(action, msg % args)
26142612

Lib/test/test_argparse.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import argparse
1717
import warnings
1818

19+
from enum import StrEnum
1920
from test.support import captured_stderr
2021
from test.support import import_helper
2122
from test.support import os_helper
@@ -985,6 +986,34 @@ class TestDisallowLongAbbreviationAllowsShortGroupingPrefix(ParserTestCase):
985986
]
986987

987988

989+
class TestStrEnumChoices(TestCase):
990+
class Color(StrEnum):
991+
RED = "red"
992+
GREEN = "green"
993+
BLUE = "blue"
994+
995+
def test_parse_enum_value(self):
996+
parser = argparse.ArgumentParser()
997+
parser.add_argument('--color', choices=self.Color)
998+
args = parser.parse_args(['--color', 'red'])
999+
self.assertEqual(args.color, self.Color.RED)
1000+
1001+
def test_help_message_contains_enum_choices(self):
1002+
parser = argparse.ArgumentParser()
1003+
parser.add_argument('--color', choices=self.Color, help='Choose a color')
1004+
self.assertIn('[--color {red,green,blue}]', parser.format_usage())
1005+
self.assertIn(' --color {red,green,blue}', parser.format_help())
1006+
1007+
def test_invalid_enum_value_raises_error(self):
1008+
parser = argparse.ArgumentParser(exit_on_error=False)
1009+
parser.add_argument('--color', choices=self.Color)
1010+
self.assertRaisesRegex(
1011+
argparse.ArgumentError,
1012+
r"invalid choice: 'yellow' \(choose from red, green, blue\)",
1013+
parser.parse_args,
1014+
['--color', 'yellow'],
1015+
)
1016+
9881017
# ================
9891018
# Positional tests
9901019
# ================
@@ -2485,7 +2514,7 @@ def test_wrong_argument_subparsers_no_destination_error(self):
24852514
parser.parse_args(('baz',))
24862515
self.assertRegex(
24872516
excinfo.exception.stderr,
2488-
r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$"
2517+
r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from foo, bar\)\n$"
24892518
)
24902519

24912520
def test_optional_subparsers(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Always use :func:`str` to print ``choices`` in :mod:`argparse`.

0 commit comments

Comments
 (0)