From c1c85e1331065d26cbdf9d924231440bd17ad706 Mon Sep 17 00:00:00 2001 From: hai shi Date: Thu, 22 Aug 2019 00:13:06 +0800 Subject: [PATCH 01/11] Improving interactive use of argparse --- Lib/argparse.py | 24 +++++++++++++++--------- Lib/test/test_argparse.py | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index a300828f9e3d2e..d294eed48dd6ba 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1637,7 +1637,8 @@ def __init__(self, argument_default=None, conflict_handler='error', add_help=True, - allow_abbrev=True): + allow_abbrev=True, + exit_on_error=True): superinit = super(ArgumentParser, self).__init__ superinit(description=description, @@ -1656,6 +1657,7 @@ def __init__(self, self.fromfile_prefix_chars = fromfile_prefix_chars self.add_help = add_help self.allow_abbrev = allow_abbrev + self.exit_on_error = exit_on_error add_group = self.add_argument_group self._positionals = add_group(_('positional arguments')) @@ -1786,15 +1788,19 @@ def parse_known_args(self, args=None, namespace=None): setattr(namespace, dest, self._defaults[dest]) # parse the arguments and exit if there are any errors - try: + if self.exit_on_error: + try: + namespace, args = self._parse_known_args(args, namespace) + except ArgumentError: + err = _sys.exc_info()[1] + self.error(str(err)) + else: namespace, args = self._parse_known_args(args, namespace) - if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR): - args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) - delattr(namespace, _UNRECOGNIZED_ARGS_ATTR) - return namespace, args - except ArgumentError: - err = _sys.exc_info()[1] - self.error(str(err)) + + if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR): + args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) + delattr(namespace, _UNRECOGNIZED_ARGS_ATTR) + return namespace, args def _parse_known_args(self, arg_strings, namespace): # replace arg strings that are file references diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index d6d16090eb0260..e5249b7db2c912 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5222,6 +5222,21 @@ def test_help_with_metavar(self): ''')) +class TestExitOnError(TestCase): + + def setUp(self): + self.parser = argparse.ArgumentParser(exit_on_error=False) + self.parser.add_argument('--integers', metavar='N', type=int) + + def test_exit_on_error_with_good_args(self): + ns = self.parser.parse_args('--integers 4'.split()) + self.assertEqual(ns, argparse.Namespace(integers=4)) + + def test_exit_on_error_with_bad_args(self): + with self.assertRaises(argparse.ArgumentError): + self.parser.parse_args('--integers a'.split()) + + def test_main(): support.run_unittest(__name__) # Remove global references to avoid looking like we have refleaks. From 948e135d4172307e679846cf8ee2d0121c7caf1f Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2019 16:38:58 +0000 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst diff --git a/Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst b/Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst new file mode 100644 index 00000000000000..9c664584cc4c0e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst @@ -0,0 +1 @@ +Add ``exit_on_error`` in :class:`ArgumentParser`. \ No newline at end of file From 07336d58d31f7c23fd3557d57e949cad9857d1e8 Mon Sep 17 00:00:00 2001 From: hai shi Date: Fri, 23 Aug 2019 01:04:38 +0800 Subject: [PATCH 03/11] update desc --- Doc/library/argparse.rst | 8 +++++++- Lib/argparse.py | 2 ++ Lib/test/test_argparse.py | 2 +- .../next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index ef2fd42783c877..3b8e731cafb3e0 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -142,7 +142,7 @@ ArgumentParser objects formatter_class=argparse.HelpFormatter, \ prefix_chars='-', fromfile_prefix_chars=None, \ argument_default=None, conflict_handler='error', \ - add_help=True, allow_abbrev=True) + add_help=True, allow_abbrev=True, exit_on_error=True) Create a new :class:`ArgumentParser` object. All parameters should be passed as keyword arguments. Each parameter has its own more detailed description @@ -179,6 +179,9 @@ ArgumentParser objects * allow_abbrev_ - Allows long options to be abbreviated if the abbreviation is unambiguous. (default: ``True``) + * exit_on_error_ - Determines whether or not argparser exits with error + when an error occur. (default: ``True``) + .. versionchanged:: 3.5 *allow_abbrev* parameter was added. @@ -186,6 +189,9 @@ ArgumentParser objects In previous versions, *allow_abbrev* also disabled grouping of short flags such as ``-vv`` to mean ``-v -v``. + .. versionchanged:: 3.9 + *exit_on_error* parameter was added. + The following sections describe how each of these are used. diff --git a/Lib/argparse.py b/Lib/argparse.py index d294eed48dd6ba..ed5492519a5468 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1623,6 +1623,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): - conflict_handler -- String indicating how to handle conflicts - add_help -- Add a -h/-help option - allow_abbrev -- Allow long options to be abbreviated unambiguously + - exit_on_error -- Determines whether or not argparser exits with + error when an error occurs """ def __init__(self, diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index e5249b7db2c912..2af3c05da19e71 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5230,7 +5230,7 @@ def setUp(self): def test_exit_on_error_with_good_args(self): ns = self.parser.parse_args('--integers 4'.split()) - self.assertEqual(ns, argparse.Namespace(integers=4)) + self.assertEqual(ns, argparse.Namespace(integers=4)) def test_exit_on_error_with_bad_args(self): with self.assertRaises(argparse.ArgumentError): diff --git a/Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst b/Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst index 9c664584cc4c0e..4cb89893159e50 100644 --- a/Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst +++ b/Misc/NEWS.d/next/Library/2019-08-21-16-38-56.bpo-9938.t3G7N9.rst @@ -1 +1 @@ -Add ``exit_on_error`` in :class:`ArgumentParser`. \ No newline at end of file +Add optional keyword argument ``exit_on_error`` for :class:`ArgumentParser`. From 8cb0b262f8a82fa473a6d55288e538b04a28077d Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Fri, 23 Aug 2019 12:49:54 +0800 Subject: [PATCH 04/11] Update Lib/argparse.py Co-Authored-By: Kyle Stanley --- Lib/argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index ed5492519a5468..0865301afdd40b 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1623,7 +1623,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): - conflict_handler -- String indicating how to handle conflicts - add_help -- Add a -h/-help option - allow_abbrev -- Allow long options to be abbreviated unambiguously - - exit_on_error -- Determines whether or not argparser exits with + - exit_on_error -- Determines whether or not argparser exits with an error when an error occurs """ From a163c4a0a88048ec77f0483f0149ddc664728769 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Fri, 23 Aug 2019 12:50:40 +0800 Subject: [PATCH 05/11] Update Doc/library/argparse.rst Co-Authored-By: Kyle Stanley --- 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 3b8e731cafb3e0..d539ec0cf60fcc 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -179,7 +179,7 @@ ArgumentParser objects * allow_abbrev_ - Allows long options to be abbreviated if the abbreviation is unambiguous. (default: ``True``) - * exit_on_error_ - Determines whether or not argparser exits with error + * exit_on_error_ - Determines whether or not argparser exits with an error when an error occur. (default: ``True``) .. versionchanged:: 3.5 From bdecd7955b8e9fcef3fd2841e71e9178e552439d Mon Sep 17 00:00:00 2001 From: hai shi Date: Sat, 24 Aug 2019 00:58:57 +0800 Subject: [PATCH 06/11] add argument examples --- Doc/library/argparse.rst | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 3b8e731cafb3e0..0c21ec47ab6c67 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -179,7 +179,7 @@ ArgumentParser objects * allow_abbrev_ - Allows long options to be abbreviated if the abbreviation is unambiguous. (default: ``True``) - * exit_on_error_ - Determines whether or not argparser exits with error + * exit_on_error_ - Determines whether or not argparser exits with error info when an error occur. (default: ``True``) .. versionchanged:: 3.5 @@ -653,6 +653,28 @@ the help options:: +h, ++help show this help message and exit +exit_on_error +^^^^^^^^^^^^^ + +Normally, when you pass an wrong argument list to the :meth:`~ArgumentParser.parse_args` +method of an :class:`ArgumentParser`, it will exit with error info. + +If user would like catch error by themselves, they can enable this feature by setting +``exit_on_error`` to ``False``: + + >>> parser = argparse.ArgumentParser(exit_on_error=False) + >>> parser.add_argument('--integers', type=int) + _StoreAction(option_strings=['--integers'], dest='integers', nargs=None, const=None, default=None, type=, choices=None, help=None, metavar=None) + >>> try: + ... parser.parse_args('--integers a'.split()) + ... except argparse.ArgumentError: + ... print('Catching an argumentError') + ... + Catching an argumentError + +.. versionadded:: 3.9 + + The add_argument() method ------------------------- From 25924d1501fb61d139bf9c749df7d5b173e61312 Mon Sep 17 00:00:00 2001 From: hai shi Date: Sat, 24 Aug 2019 01:43:28 +0800 Subject: [PATCH 07/11] update detail of colon --- 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 0c21ec47ab6c67..6ecee368ca4a4a 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -660,7 +660,7 @@ Normally, when you pass an wrong argument list to the :meth:`~ArgumentParser.par method of an :class:`ArgumentParser`, it will exit with error info. If user would like catch error by themselves, they can enable this feature by setting -``exit_on_error`` to ``False``: +``exit_on_error`` to ``False``:: >>> parser = argparse.ArgumentParser(exit_on_error=False) >>> parser.add_argument('--integers', type=int) From 872b47a44317edc087c4832efc4f0978560a64cb Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Sat, 24 Aug 2019 10:23:41 +0800 Subject: [PATCH 08/11] Update Doc/library/argparse.rst Co-Authored-By: Kyle Stanley --- 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 6ecee368ca4a4a..e281086893b118 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -659,7 +659,7 @@ exit_on_error Normally, when you pass an wrong argument list to the :meth:`~ArgumentParser.parse_args` method of an :class:`ArgumentParser`, it will exit with error info. -If user would like catch error by themselves, they can enable this feature by setting +If the user would like catch errors manually, they can enable this feature by setting ``exit_on_error`` to ``False``:: >>> parser = argparse.ArgumentParser(exit_on_error=False) From facfb4cce127b996803e06f5c3368daded2ae483 Mon Sep 17 00:00:00 2001 From: Hai Shi Date: Sat, 24 Aug 2019 10:24:21 +0800 Subject: [PATCH 09/11] Update Doc/library/argparse.rst Co-Authored-By: Kyle Stanley --- 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 e281086893b118..b10fc94663c6f6 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -656,7 +656,7 @@ the help options:: exit_on_error ^^^^^^^^^^^^^ -Normally, when you pass an wrong argument list to the :meth:`~ArgumentParser.parse_args` +Normally, when you pass an invalid argument list to the :meth:`~ArgumentParser.parse_args` method of an :class:`ArgumentParser`, it will exit with error info. If the user would like catch errors manually, they can enable this feature by setting From aee9372f4deec3b0eb6313443a45f51c568f4eb0 Mon Sep 17 00:00:00 2001 From: hai shi Date: Thu, 12 Sep 2019 08:29:28 +0800 Subject: [PATCH 10/11] update desc of exit_on_error in argparse --- Doc/library/argparse.rst | 6 +++--- Lib/argparse.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index b10fc94663c6f6..f9f8f8abc418e6 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -179,8 +179,8 @@ ArgumentParser objects * allow_abbrev_ - Allows long options to be abbreviated if the abbreviation is unambiguous. (default: ``True``) - * exit_on_error_ - Determines whether or not argparser exits with error info - when an error occur. (default: ``True``) + * exit_on_error_ - Determines whether or not ArgumentParser exits with + error info when an error occur. (default: ``True``) .. versionchanged:: 3.5 *allow_abbrev* parameter was added. @@ -659,7 +659,7 @@ exit_on_error Normally, when you pass an invalid argument list to the :meth:`~ArgumentParser.parse_args` method of an :class:`ArgumentParser`, it will exit with error info. -If the user would like catch errors manually, they can enable this feature by setting +If the user would like catch errors manually, the feature can be enable by setting ``exit_on_error`` to ``False``:: >>> parser = argparse.ArgumentParser(exit_on_error=False) diff --git a/Lib/argparse.py b/Lib/argparse.py index c7ec907aee2176..370632232946a0 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1623,7 +1623,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): - conflict_handler -- String indicating how to handle conflicts - add_help -- Add a -h/-help option - allow_abbrev -- Allow long options to be abbreviated unambiguously - - exit_on_error -- Determines whether or not argparser exits with + - exit_on_error -- Determines whether or not ArgumentParser exits with error info when an error occurs """ From 03451ed51a544110e3abf0a2e4f41abaa1949728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 12 Sep 2019 12:36:36 +0200 Subject: [PATCH 11/11] Fix typo --- 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 f9f8f8abc418e6..290e5d28073f3d 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -180,7 +180,7 @@ ArgumentParser objects abbreviation is unambiguous. (default: ``True``) * exit_on_error_ - Determines whether or not ArgumentParser exits with - error info when an error occur. (default: ``True``) + error info when an error occurs. (default: ``True``) .. versionchanged:: 3.5 *allow_abbrev* parameter was added.