]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-61181: Fix support of choices with string value in argparse (GH-124578)
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 29 Sep 2024 07:57:21 +0000 (10:57 +0300)
committerGitHub <noreply@github.com>
Sun, 29 Sep 2024 07:57:21 +0000 (10:57 +0300)
Substrings of the specified string no longer considered valid values.

Doc/library/argparse.rst
Lib/argparse.py
Lib/test/test_argparse.py
Misc/NEWS.d/next/Library/2024-09-26-09-18-09.gh-issue-61181.dwjmch.rst [new file with mode: 0644]

index d5a21899ae4f9900295e9ed7154d9b1ad6cafdb4..a4683bccf651cdf2382532042a8afd8062ea969a 100644 (file)
@@ -1823,7 +1823,7 @@ Sub-commands
      >>>
      >>> # create the parser for the "b" command
      >>> parser_b = subparsers.add_parser('b', help='b help')
-     >>> parser_b.add_argument('--baz', choices='XYZ', help='baz help')
+     >>> parser_b.add_argument('--baz', choices=('X', 'Y', 'Z'), help='baz help')
      >>>
      >>> # parse some argument lists
      >>> parser.parse_args(['a', '12'])
index f428512d4007ef66841b36e759eb9790459c8e91..a671c8b56b55bbfcd569cb2178afa24b1e09826a 100644 (file)
@@ -2552,11 +2552,15 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
 
     def _check_value(self, action, value):
         # converted value must be one of the choices (if specified)
-        if action.choices is not None and value not in action.choices:
-            args = {'value': value,
-                    'choices': ', '.join(map(repr, action.choices))}
-            msg = _('invalid choice: %(value)r (choose from %(choices)s)')
-            raise ArgumentError(action, msg % args)
+        choices = action.choices
+        if choices is not None:
+            if isinstance(choices, str):
+                choices = iter(choices)
+            if value not in choices:
+                args = {'value': value,
+                        'choices': ', '.join(map(repr, action.choices))}
+                msg = _('invalid choice: %(value)r (choose from %(choices)s)')
+                raise ArgumentError(action, msg % args)
 
     # =======================
     # Help-formatting methods
index 5c8f0ec0b58e9a0ae7173bc0ac70402c2555d94b..91f04fa1358a9d81808f847a60f8b28c9ab85985 100644 (file)
@@ -686,7 +686,7 @@ class TestOptionalsChoices(ParserTestCase):
     argument_signatures = [
         Sig('-f', choices='abc'),
         Sig('-g', type=int, choices=range(5))]
-    failures = ['a', '-f d', '-fad', '-ga', '-g 6']
+    failures = ['a', '-f d', '-f ab', '-fad', '-ga', '-g 6']
     successes = [
         ('', NS(f=None, g=None)),
         ('-f a', NS(f='a', g=None)),
@@ -2270,14 +2270,14 @@ class TestAddSubparsers(TestCase):
             parser1_kwargs['aliases'] = ['1alias1', '1alias2']
         parser1 = subparsers.add_parser('1', **parser1_kwargs)
         parser1.add_argument('-w', type=int, help='w help')
-        parser1.add_argument('x', choices='abc', help='x help')
+        parser1.add_argument('x', choices=['a', 'b', 'c'], help='x help')
 
         # add second sub-parser
         parser2_kwargs = dict(description='2 description')
         if subparser_help:
             parser2_kwargs['help'] = '2 help'
         parser2 = subparsers.add_parser('2', **parser2_kwargs)
-        parser2.add_argument('-y', choices='123', help='y help')
+        parser2.add_argument('-y', choices=['1', '2', '3'], help='y help')
         parser2.add_argument('z', type=complex, nargs='*', help='z help')
 
         # add third sub-parser
@@ -4618,7 +4618,7 @@ class TestHelpVariableExpansion(HelpTestCase):
             help='x %(prog)s %(default)s %(type)s %%'),
         Sig('-y', action='store_const', default=42, const='XXX',
             help='y %(prog)s %(default)s %(const)s'),
-        Sig('--foo', choices='abc',
+        Sig('--foo', choices=['a', 'b', 'c'],
             help='foo %(prog)s %(default)s %(choices)s'),
         Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
             help='bar %(prog)s %(default)s %(dest)s'),
@@ -5281,7 +5281,7 @@ class TestInvalidArgumentConstructors(TestCase):
         for action in ['store_const', 'store_true', 'store_false',
                        'append_const', 'count']:
             for attrs in [dict(type=int), dict(nargs='+'),
-                          dict(choices='ab')]:
+                          dict(choices=['a', 'b'])]:
                 self.assertTypeError('-x', action=action, **attrs)
 
     def test_no_argument_no_const_actions(self):
diff --git a/Misc/NEWS.d/next/Library/2024-09-26-09-18-09.gh-issue-61181.dwjmch.rst b/Misc/NEWS.d/next/Library/2024-09-26-09-18-09.gh-issue-61181.dwjmch.rst
new file mode 100644 (file)
index 0000000..801a5fd
--- /dev/null
@@ -0,0 +1,2 @@
+Fix support of :ref:`choices` with string value in :mod:`argparse`. Substrings
+of the specified string no longer considered valid values.