From 45ac2a7420f2c424e179aab3a458b1b242378f6b Mon Sep 17 00:00:00 2001 From: joshmeranda Date: Thu, 22 Jul 2021 17:06:16 -0400 Subject: [PATCH 1/3] bpo-41255: unify hanling of exit_on_error --- Doc/library/argparse.rst | 5 +++-- Lib/argparse.py | 19 ++++++++++--------- Lib/test/test_argparse.py | 10 +++++++++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index a1b4bd0fcfd170..2aeb6029cf707a 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -2072,8 +2072,9 @@ Exiting methods .. method:: ArgumentParser.error(message) - This method prints a usage message including the *message* to the - standard error and terminates the program with a status code of 2. + When exit on error is `True` this method prints a usage message including + the *message* to the standard error and terminates the program with a status + code of 2, otherwise raises an ArgumentError. Intermixed parsing diff --git a/Lib/argparse.py b/Lib/argparse.py index 8a12dea7668799..591d22cf77910f 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1846,14 +1846,11 @@ 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 - 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: + try: namespace, args = self._parse_known_args(args, namespace) + except ArgumentError: + err = _sys.exc_info()[1] + self.error(str(err)) if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR): args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) @@ -2564,12 +2561,16 @@ def exit(self, status=0, message=None): def error(self, message): """error(message: string) - Prints a usage message incorporating the message to stderr and - exits. + When exit_on_error is true prints a usage message + incorporating the message to stderr and exits, otherwise raises + an ArgumentError. If you override this in a subclass, it should not return -- it should either exit or raise an exception. """ + if not self.exit_on_error: + raise ArgumentError(None, message) + self.print_usage(_sys.stderr) args = {'prog': self.prog, 'message': message} self.exit(2, _('%(prog)s: error: %(message)s\n') % args) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 4d0316f73edcd2..e0027e7420a20e 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5349,7 +5349,7 @@ class TestExitOnError(TestCase): def setUp(self): self.parser = argparse.ArgumentParser(exit_on_error=False) - self.parser.add_argument('--integers', metavar='N', type=int) + self.parser.add_argument('--integers', metavar='N', type=int, required=True) def test_exit_on_error_with_good_args(self): ns = self.parser.parse_args('--integers 4'.split()) @@ -5359,6 +5359,14 @@ def test_exit_on_error_with_bad_args(self): with self.assertRaises(argparse.ArgumentError): self.parser.parse_args('--integers a'.split()) + def test_exit_on_error_missing_required_args(self): + with self.assertRaises(argparse.ArgumentError): + self.parser.parse_args([]) + + def test_exit_on_error_unknown_args(self): + with self.assertRaises(argparse.ArgumentError): + self.parser.parse_args("--integers 1 --unknown-arg".split()) + def test_main(): support.run_unittest(__name__) From c846f72e5d4dbd95c4af0a42c708cd5f250bcecb Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 22 Jul 2021 21:56:35 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2021-07-22-21-56-34.bpo-41255.tbSAVo.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2021-07-22-21-56-34.bpo-41255.tbSAVo.rst diff --git a/Misc/NEWS.d/next/Library/2021-07-22-21-56-34.bpo-41255.tbSAVo.rst b/Misc/NEWS.d/next/Library/2021-07-22-21-56-34.bpo-41255.tbSAVo.rst new file mode 100644 index 00000000000000..aad7cf303a8903 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-07-22-21-56-34.bpo-41255.tbSAVo.rst @@ -0,0 +1 @@ +fixed errors with argparse exit_on_error causing unexpected behavior \ No newline at end of file From bca0bf55d5560b92099071ce480c7399ed0b8231 Mon Sep 17 00:00:00 2001 From: joshmeranda Date: Fri, 23 Jul 2021 00:38:32 -0400 Subject: [PATCH 3/3] bpo-41255: resolve suspicious reST construct in modified docs --- 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 2aeb6029cf707a..46bfe788c80e50 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -2072,7 +2072,7 @@ Exiting methods .. method:: ArgumentParser.error(message) - When exit on error is `True` this method prints a usage message including + When exit on error is ``True`` this method prints a usage message including the *message* to the standard error and terminates the program with a status code of 2, otherwise raises an ArgumentError.