From 01d750ad937f8a1861c9b0b4217e0e1c2535f675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Batuhan=20Ta=C5=9Fkaya?= Date: Tue, 14 May 2019 05:39:05 +0300 Subject: [PATCH 1/2] bpo-23378: Add an extend action to argparse --- Doc/library/argparse.rst | 9 +++++++++ Lib/argparse.py | 7 +++++++ Lib/test/test_argparse.py | 9 +++++++++ .../Library/2019-05-14-05-38-22.bpo-23378.R25teI.rst | 1 + 4 files changed, 26 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-05-14-05-38-22.bpo-23378.R25teI.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index cef197f3055581..1513d5a2cc1303 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -797,6 +797,15 @@ how the command-line arguments should be handled. The supplied actions are: >>> parser.parse_args(['--version']) PROG 2.0 +* ``'extend'`` - This stores a list, and extends each argument value to the + list. + Example usage:: + + >>> parser = argparse.ArgumentParser() + >>> parser.add_argument("--foo", action="extend", nargs="+", type=str) + >>> parser.parse_args("--foo f1 --foo f2 f3 f4".split()) + Namespace(foo=['f1', 'f2', 'f3', 'f4']) + You may also specify an arbitrary action by passing an Action subclass or other object that implements the same interface. The recommended way to do this is to extend :class:`Action`, overriding the ``__call__`` method diff --git a/Lib/argparse.py b/Lib/argparse.py index 798766f6c4086a..ef888f063b3286 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1154,6 +1154,12 @@ def __call__(self, parser, namespace, values, option_string=None): vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, []) getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) +class _ExtendAction(_AppendAction): + def __call__(self, parser, namespace, values, option_string=None): + items = getattr(namespace, self.dest, None) + items = _copy_items(items) + items.extend(values) + setattr(namespace, self.dest, items) # ============== # Type classes @@ -1262,6 +1268,7 @@ def __init__(self, self.register('action', 'help', _HelpAction) self.register('action', 'version', _VersionAction) self.register('action', 'parsers', _SubParsersAction) + self.register('action', 'extend', _ExtendAction) # raise an exception if the conflict handler is invalid self._get_handler() diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index e849c7ba49bcd2..9d68f40571fe6f 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1786,6 +1786,15 @@ def test(self): self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]')) +class TestActionExtend(ParserTestCase): + argument_signatures = [ + Sig('--foo', action="extend", nargs="+", type=str), + ] + failures = () + successes = [ + ('--foo f1 --foo f2 f3 f4', NS(foo=['f1', 'f2', 'f3', 'f4'])), + ] + # ================ # Subparsers tests # ================ diff --git a/Misc/NEWS.d/next/Library/2019-05-14-05-38-22.bpo-23378.R25teI.rst b/Misc/NEWS.d/next/Library/2019-05-14-05-38-22.bpo-23378.R25teI.rst new file mode 100644 index 00000000000000..c7c3f174d637e4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-05-14-05-38-22.bpo-23378.R25teI.rst @@ -0,0 +1 @@ +Add an extend action to argparser. From 85c1bccddcaab9ce43390999a081de6f97c9acd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Batuhan=20Ta=C5=9Fkaya?= Date: Tue, 21 May 2019 20:28:30 +0300 Subject: [PATCH 2/2] improve doc --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 1513d5a2cc1303..b77a38ccd48577 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -803,7 +803,7 @@ how the command-line arguments should be handled. The supplied actions are: >>> parser = argparse.ArgumentParser() >>> parser.add_argument("--foo", action="extend", nargs="+", type=str) - >>> parser.parse_args("--foo f1 --foo f2 f3 f4".split()) + >>> parser.parse_args(["--foo", "f1", "--foo", "f2", "f3", "f4"]) Namespace(foo=['f1', 'f2', 'f3', 'f4']) You may also specify an arbitrary action by passing an Action subclass or