| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1428,8 +1428,18 @@ this API may be passed as the ``action`` parameter to | |||
| 1428 | 1428 | >>> parser.parse_args(['--no-foo']) | |
| 1429 | 1429 | Namespace(foo=False) | |
| 1430 | 1430 | ||
| 1431 | + Single-dash long options are also supported. | ||
| 1432 | + For example, negative option ``-no-foo`` is automatically added for | ||
| 1433 | + positive option``-foo``. | ||
| 1434 | + But no additional options are added for short options such as ``-f``. | ||
| 1435 | + | ||
| 1431 | 1436 | .. versionadded:: 3.9 | |
| 1432 | 1437 | ||
| 1438 | + .. versionchanged:: next | ||
| 1439 | + Added support for single-dash options. | ||
| 1440 | + | ||
| 1441 | + Added support for alternate prefix_chars_. | ||
| 1442 | + | ||
| 1433 | 1443 | ||
| 1434 | 1444 | The parse_args() method | |
| 1435 | 1445 | ----------------------- | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -283,6 +283,14 @@ New modules | |||
| 283 | 283 | Improved modules | |
| 284 | 284 | ================ | |
| 285 | 285 | ||
| 286 | + argparse | ||
| 287 | + -------- | ||
| 288 | + | ||
| 289 | + * The :class:`~argparse.BooleanOptionalAction` action supports now single-dash | ||
| 290 | + long options and alternate prefix_chars_. | ||
| 291 | + (Contributed by Serhiy Storchaka in :gh:`138525`.) | ||
| 292 | + | ||
| 293 | + | ||
| 286 | 294 | dbm | |
| 287 | 295 | --- | |
| 288 | 296 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -933,15 +933,24 @@ def __init__(self, | |||
| 933 | 933 | deprecated=False): | |
| 934 | 934 | ||
| 935 | 935 | _option_strings = [] | |
| 936 | + neg_option_strings = [] | ||
| 936 | 937 | for option_string in option_strings: | |
| 937 | 938 | _option_strings.append(option_string) | |
| 938 | 939 | ||
| 939 | - if option_string.startswith('--'): | ||
| 940 | - if option_string.startswith('--no-'): | ||
| 940 | + if len(option_string) > 2 and option_string[0] == option_string[1]: | ||
| 941 | + if option_string.startswith('no-', 2): | ||
| 941 | 942 | raise ValueError(f'invalid option name {option_string!r} ' | |
| 942 | 943 | f'for BooleanOptionalAction') | |
| 943 | - option_string = '--no-' + option_string[2:] | ||
| 944 | + option_string = option_string[:2] + 'no-' + option_string[2:] | ||
| 944 | 945 | _option_strings.append(option_string) | |
| 946 | + neg_option_strings.append(option_string) | ||
| 947 | + elif len(option_string) > 2 and option_string[0] != option_string[1]: | ||
| 948 | + if option_string.startswith('no-', 1): | ||
| 949 | + raise ValueError(f'invalid option name {option_string!r} ' | ||
| 950 | + f'for BooleanOptionalAction') | ||
| 951 | + option_string = option_string[:1] + 'no-' + option_string[1:] | ||
| 952 | + _option_strings.append(option_string) | ||
| 953 | + neg_option_strings.append(option_string) | ||
| 945 | 954 | ||
| 946 | 955 | super().__init__( | |
| 947 | 956 | option_strings=_option_strings, | |
@@ -951,11 +960,12 @@ def __init__(self, | |||
| 951 | 960 | required=required, | |
| 952 | 961 | help=help, | |
| 953 | 962 | deprecated=deprecated) | |
| 963 | + self.neg_option_strings = neg_option_strings | ||
| 954 | 964 | ||
| 955 | 965 | ||
| 956 | 966 | def __call__(self, parser, namespace, values, option_string=None): | |
| 957 | 967 | if option_string in self.option_strings: | |
| 958 | - setattr(namespace, self.dest, not option_string.startswith('--no-')) | ||
| 968 | + setattr(namespace, self.dest, option_string not in self.neg_option_strings) | ||
| 959 | 969 | ||
| 960 | 970 | def format_usage(self): | |
| 961 | 971 | return ' | '.join(self.option_strings) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -795,6 +795,74 @@ def test_invalid_name(self): | |||
| 795 | 795 | self.assertEqual(str(cm.exception), | |
| 796 | 796 | "invalid option name '--no-foo' for BooleanOptionalAction") | |
| 797 | 797 | ||
| 798 | + class TestBooleanOptionalActionSingleDash(ParserTestCase): | ||
| 799 | + """Tests BooleanOptionalAction with single dash""" | ||
| 800 | + | ||
| 801 | + argument_signatures = [ | ||
| 802 | + Sig('-foo', '-x', action=argparse.BooleanOptionalAction), | ||
| 803 | + ] | ||
| 804 | + failures = ['--foo', '--no-foo', '-no-x'] | ||
| 805 | + successes = [ | ||
| 806 | + ('', NS(foo=None)), | ||
| 807 | + ('-foo', NS(foo=True)), | ||
| 808 | + ('-no-foo', NS(foo=False)), | ||
| 809 | + ('-x', NS(foo=True)), | ||
| 810 | + ] | ||
| 811 | + | ||
| 812 | + def test_invalid_name(self): | ||
| 813 | + parser = argparse.ArgumentParser() | ||
| 814 | + with self.assertRaises(ValueError) as cm: | ||
| 815 | + parser.add_argument('-no-foo', action=argparse.BooleanOptionalAction) | ||
| 816 | + self.assertEqual(str(cm.exception), | ||
| 817 | + "invalid option name '-no-foo' for BooleanOptionalAction") | ||
| 818 | + | ||
| 819 | + class TestBooleanOptionalActionAlternatePrefixChars(ParserTestCase): | ||
| 820 | + """Tests BooleanOptionalAction with custom prefixes""" | ||
| 821 | + | ||
| 822 | + parser_signature = Sig(prefix_chars='+-', add_help=False) | ||
| 823 | + argument_signatures = [Sig('++foo', action=argparse.BooleanOptionalAction)] | ||
| 824 | + failures = ['--foo', '--no-foo'] | ||
| 825 | + successes = [ | ||
| 826 | + ('', NS(foo=None)), | ||
| 827 | + ('++foo', NS(foo=True)), | ||
| 828 | + ('++no-foo', NS(foo=False)), | ||
| 829 | + ] | ||
| 830 | + | ||
| 831 | + def test_invalid_name(self): | ||
| 832 | + parser = argparse.ArgumentParser(prefix_chars='+/') | ||
| 833 | + with self.assertRaisesRegex(ValueError, | ||
| 834 | + 'BooleanOptionalAction.*is not valid for positional arguments'): | ||
| 835 | + parser.add_argument('--foo', action=argparse.BooleanOptionalAction) | ||
| 836 | + with self.assertRaises(ValueError) as cm: | ||
| 837 | + parser.add_argument('++no-foo', action=argparse.BooleanOptionalAction) | ||
| 838 | + self.assertEqual(str(cm.exception), | ||
| 839 | + "invalid option name '++no-foo' for BooleanOptionalAction") | ||
| 840 | + | ||
| 841 | + class TestBooleanOptionalActionSingleAlternatePrefixChar(ParserTestCase): | ||
| 842 | + """Tests BooleanOptionalAction with single alternate prefix char""" | ||
| 843 | + | ||
| 844 | + parser_signature = Sig(prefix_chars='+/', add_help=False) | ||
| 845 | + argument_signatures = [ | ||
| 846 | + Sig('+foo', '+x', action=argparse.BooleanOptionalAction), | ||
| 847 | + ] | ||
| 848 | + failures = ['++foo', '++no-foo', '-no-foo', '+no-x', '-no-x'] | ||
| 849 | + successes = [ | ||
| 850 | + ('', NS(foo=None)), | ||
| 851 | + ('+foo', NS(foo=True)), | ||
| 852 | + ('+no-foo', NS(foo=False)), | ||
| 853 | + ('+x', NS(foo=True)), | ||
| 854 | + ] | ||
| 855 | + | ||
| 856 | + def test_invalid_name(self): | ||
| 857 | + parser = argparse.ArgumentParser(prefix_chars='+/') | ||
| 858 | + with self.assertRaisesRegex(ValueError, | ||
| 859 | + 'BooleanOptionalAction.*is not valid for positional arguments'): | ||
| 860 | + parser.add_argument('-foo', action=argparse.BooleanOptionalAction) | ||
| 861 | + with self.assertRaises(ValueError) as cm: | ||
| 862 | + parser.add_argument('+no-foo', action=argparse.BooleanOptionalAction) | ||
| 863 | + self.assertEqual(str(cm.exception), | ||
| 864 | + "invalid option name '+no-foo' for BooleanOptionalAction") | ||
| 865 | + | ||
| 798 | 866 | class TestBooleanOptionalActionRequired(ParserTestCase): | |
| 799 | 867 | """Tests BooleanOptionalAction required""" | |
| 800 | 868 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Add support for single-dash long options and alternate prefix_chars_ in | ||
| 2 | + :class:`argparse.BooleanOptionalAction`. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments