FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-138525: Support single-dash long options and prefix_chars in BooleanOptionalAction by serhiy-storchaka · Pull Request #138692 · python/cpython · GitHub

Repository navigation

10 changes: 10 additions & 0 deletions Doc/library/argparse.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -1445,8 +1445,18 @@ this API may be passed as the ``action`` parameter to
>>> parser.parse_args(['--no-foo'])
Namespace(foo=False)

Single-dash long options are also supported.
For example, negative option ``-nofoo`` is automatically added for
positive option ``-foo``.
But no additional options are added for short options such as ``-f``.

.. versionadded:: 3.9

.. versionchanged:: next
Added support for single-dash options.

Added support for alternate prefix_chars_.


The parse_args() method
-----------------------
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.15.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,10 @@ Improved modules
argparse
--------

* The :class:`~argparse.BooleanOptionalAction` action supports now single-dash
long options and alternate prefix characters.
(Contributed by Serhiy Storchaka in :gh:`138525`.)

* Changed the *suggest_on_error* parameter of :class:`argparse.ArgumentParser` to
default to ``True``. This enables suggestions for mistyped arguments by default.
(Contributed by Jakob Schluse in :gh:`140450`.)
Expand Down
20 changes: 16 additions & 4 deletions Lib/argparse.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -932,15 +932,26 @@ def __init__(self,
deprecated=False):

_option_strings = []
neg_option_strings = []
for option_string in option_strings:
_option_strings.append(option_string)

if option_string.startswith('--'):
if option_string.startswith('--no-'):
if len(option_string) > 2 and option_string[0] == option_string[1]:
# two-dash long option: '--foo' -> '--no-foo'
if option_string.startswith('no-', 2):
raise ValueError(f'invalid option name {option_string!r} '
f'for BooleanOptionalAction')
option_string = '--no-' + option_string[2:]
option_string = option_string[:2] + 'no-' + option_string[2:]
_option_strings.append(option_string)
neg_option_strings.append(option_string)
elif len(option_string) > 2 and option_string[0] != option_string[1]:
# single-dash long option: '-foo' -> '-nofoo'
if option_string.startswith('no', 1):
raise ValueError(f'invalid option name {option_string!r} '
f'for BooleanOptionalAction')
option_string = option_string[:1] + 'no' + option_string[1:]
_option_strings.append(option_string)
neg_option_strings.append(option_string)

super().__init__(
option_strings=_option_strings,
Expand All @@ -950,11 +961,12 @@ def __init__(self,
required=required,
help=help,
deprecated=deprecated)
self.neg_option_strings = neg_option_strings


def __call__(self, parser, namespace, values, option_string=None):
if option_string in self.option_strings:
setattr(namespace, self.dest, not option_string.startswith('--no-'))
setattr(namespace, self.dest, option_string not in self.neg_option_strings)

def format_usage(self):
return ' | '.join(self.option_strings)
Expand Down
70 changes: 70 additions & 0 deletions Lib/test/test_argparse.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,76 @@ def test_invalid_name(self):
self.assertEqual(str(cm.exception),
"invalid option name '--no-foo' for BooleanOptionalAction")

class TestBooleanOptionalActionSingleDash(ParserTestCase):
"""Tests BooleanOptionalAction with single dash"""

argument_signatures = [
Sig('-foo', '-x', action=argparse.BooleanOptionalAction),
]
failures = ['--foo', '--no-foo', '-no-foo', '-no-x', '-nox']
successes = [
('', NS(foo=None)),
('-foo', NS(foo=True)),
('-nofoo', NS(foo=False)),
('-x', NS(foo=True)),
]

def test_invalid_name(self):
parser = argparse.ArgumentParser()
with self.assertRaises(ValueError) as cm:
parser.add_argument('-nofoo', action=argparse.BooleanOptionalAction)
self.assertEqual(str(cm.exception),
"invalid option name '-nofoo' for BooleanOptionalAction")

class TestBooleanOptionalActionAlternatePrefixChars(ParserTestCase):
"""Tests BooleanOptionalAction with custom prefixes"""

parser_signature = Sig(prefix_chars='+-', add_help=False)
argument_signatures = [Sig('++foo', action=argparse.BooleanOptionalAction)]
failures = ['--foo', '--no-foo']
successes = [
('', NS(foo=None)),
('++foo', NS(foo=True)),
('++no-foo', NS(foo=False)),
]

def test_invalid_name(self):
parser = argparse.ArgumentParser(prefix_chars='+/')
with self.assertRaisesRegex(ValueError,
'BooleanOptionalAction.*is not valid for positional arguments'):
parser.add_argument('--foo', action=argparse.BooleanOptionalAction)
with self.assertRaises(ValueError) as cm:
parser.add_argument('++no-foo', action=argparse.BooleanOptionalAction)
self.assertEqual(str(cm.exception),
"invalid option name '++no-foo' for BooleanOptionalAction")

class TestBooleanOptionalActionSingleAlternatePrefixChar(ParserTestCase):
"""Tests BooleanOptionalAction with single alternate prefix char"""

parser_signature = Sig(prefix_chars='+/', add_help=False)
argument_signatures = [
Sig('+foo', '+x', action=argparse.BooleanOptionalAction),
]
failures = ['++foo', '++no-foo', '++nofoo',
'-no-foo', '-nofoo', '+no-foo', '-nofoo',
'+no-x', '+nox', '-no-x', '-nox']
successes = [
('', NS(foo=None)),
('+foo', NS(foo=True)),
('+nofoo', NS(foo=False)),
('+x', NS(foo=True)),
]

def test_invalid_name(self):
parser = argparse.ArgumentParser(prefix_chars='+/')
with self.assertRaisesRegex(ValueError,
'BooleanOptionalAction.*is not valid for positional arguments'):
parser.add_argument('-foo', action=argparse.BooleanOptionalAction)
with self.assertRaises(ValueError) as cm:
parser.add_argument('+nofoo', action=argparse.BooleanOptionalAction)
self.assertEqual(str(cm.exception),
"invalid option name '+nofoo' for BooleanOptionalAction")

class TestBooleanOptionalActionRequired(ParserTestCase):
"""Tests BooleanOptionalAction required"""

Expand Down
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add support for single-dash long options and alternate prefix characters in
:class:`argparse.BooleanOptionalAction`.
Loading

Back | FazBrowse Home | New Git URL