From ef8e4fc483f28890bbc52235c5b08499bee93d39 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 17:07:43 +0500 Subject: [PATCH 01/24] Add closet choice if exists in argparser if wrong choice picked --- Lib/argparse.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 240625ff01084e..5fec46730745a6 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -85,6 +85,7 @@ ] +import difflib as _difflib import os as _os import re as _re import sys as _sys @@ -2543,9 +2544,17 @@ def _get_value(self, action, arg_string): def _check_value(self, action, value): # converted value must be one of the choices (if specified) if action.choices is not None and value not in action.choices: + closet_choice = _difflib.get_close_matches(value, action.choices) args = {'value': value, 'choices': ', '.join(map(repr, action.choices))} - msg = _('invalid choice: %(value)r (choose from %(choices)s)') + + if closet_choice := closet_choice and closet_choice[0] or '': + args['closet'] = closet_choice + msg = _('invalid choice: %(value)r, maybe you meant %(closet)r? ' + '(choose from %(choices)s)') + else: + msg = _('invalid choice: %(value)r (choose from %(choices)s)') + raise ArgumentError(action, msg % args) # ======================= From 7e8dcf87908e012a64cc56ff3275893d87cf9307 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 25 Nov 2022 12:23:57 +0000 Subject: [PATCH 02/24] =?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 --- ...022-11-25-12-23-56.gh-issue-99749.-S_guS.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst new file mode 100644 index 00000000000000..fc6aeb72223aa1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst @@ -0,0 +1,17 @@ +Add closet choice if exists in Argparser if wrong choice picked. + + +``` +import argparser + +arg_parser = argparse.ArgumentParser() +arg_parser.add_argument('family', type=str.casefold, help='Font family', choices=['apple', 'mango']) + +args = arg_parser.parse_args(['mangeo']) +``` + +Current behaviour of the above statement: +error: argument family: invalid choice: 'mangeo' (choose from 'apple', 'mango') + +After this PR behaviour would be: +error: argument family: invalid choice: 'mangeo', maybe you meant 'mango'? (choose from 'apple', 'mango') From 8c754cd701eadd65ac7a92d4d917644acd42563d Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 17:33:02 +0500 Subject: [PATCH 03/24] Fix documentation --- ...22-11-25-12-23-56.gh-issue-99749.-S_guS.rst | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst index fc6aeb72223aa1..762dc4cc45d99c 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst @@ -1,17 +1 @@ -Add closet choice if exists in Argparser if wrong choice picked. - - -``` -import argparser - -arg_parser = argparse.ArgumentParser() -arg_parser.add_argument('family', type=str.casefold, help='Font family', choices=['apple', 'mango']) - -args = arg_parser.parse_args(['mangeo']) -``` - -Current behaviour of the above statement: -error: argument family: invalid choice: 'mangeo' (choose from 'apple', 'mango') - -After this PR behaviour would be: -error: argument family: invalid choice: 'mangeo', maybe you meant 'mango'? (choose from 'apple', 'mango') +Add closet choice if exists in Argparser if wrong choice picked. \ No newline at end of file From 4fb8ce670e23962abf459dbfef554ee2aa3d7460 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 17:34:57 +0500 Subject: [PATCH 04/24] Added EOL :hammer: --- .../2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst index 762dc4cc45d99c..327fbbb82356a6 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst @@ -1 +1 @@ -Add closet choice if exists in Argparser if wrong choice picked. \ No newline at end of file +Add closet choice if exists in Argparser if wrong choice picked. From 2f197b37c5b57942a78fa74eb1c659d11b7b9974 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 18:15:15 +0500 Subject: [PATCH 05/24] Test cases updated for argparser --- Lib/test/test_argparse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index cabb2f837693ff..4632c0ab566c05 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2195,7 +2195,8 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" + r"error: argument family: invalid choice: 'baz', maybe you meant 'bar'?\ + \(choose from 'foo', 'bar'\)\n$" ) def test_optional_subparsers(self): From 940a66ed25b22cec7a281e86e09a7690fc7d60bd Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 18:20:58 +0500 Subject: [PATCH 06/24] Fixed typo errors :hammer: --- Lib/argparse.py | 8 ++++---- .../2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 5fec46730745a6..4d4c4a5d72c6f6 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2544,13 +2544,13 @@ def _get_value(self, action, arg_string): def _check_value(self, action, value): # converted value must be one of the choices (if specified) if action.choices is not None and value not in action.choices: - closet_choice = _difflib.get_close_matches(value, action.choices) + closest_choice = _difflib.get_close_matches(value, action.choices) args = {'value': value, 'choices': ', '.join(map(repr, action.choices))} - if closet_choice := closet_choice and closet_choice[0] or '': - args['closet'] = closet_choice - msg = _('invalid choice: %(value)r, maybe you meant %(closet)r? ' + if closest_choice := closest_choice and closest_choice[0] or '': + args['closest'] = closest_choice + msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' '(choose from %(choices)s)') else: msg = _('invalid choice: %(value)r (choose from %(choices)s)') diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst index 327fbbb82356a6..479d5e45f56fc1 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-25-12-23-56.gh-issue-99749.-S_guS.rst @@ -1 +1 @@ -Add closet choice if exists in Argparser if wrong choice picked. +Add closest choice if exists in Argparser if wrong choice picked. From badc5ed65e5d2aac27676968f54efa53c32c26db Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 19:16:37 +0500 Subject: [PATCH 07/24] Test case fix :hammer: --- Lib/test/test_argparse.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 4632c0ab566c05..9d97113ac71d03 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -13,6 +13,7 @@ import argparse import warnings +from gettext import gettext as _ from test.support import os_helper from unittest import mock @@ -2195,8 +2196,8 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument family: invalid choice: 'baz', maybe you meant 'bar'?\ - \(choose from 'foo', 'bar'\)\n$" + _("error: argument family: invalid choice: 'baz', maybe you meant" + r" 'bar'? \(choose from 'foo', 'bar'\)\n$") ) def test_optional_subparsers(self): From 2588ef10fc193f28b19b584e011daaefc92203ab Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 19:40:13 +0500 Subject: [PATCH 08/24] Fixed test cse error msg :hammer: --- Lib/test/test_argparse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 9d97113ac71d03..2b1568ab11dd52 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2196,8 +2196,8 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - _("error: argument family: invalid choice: 'baz', maybe you meant" - r" 'bar'? \(choose from 'foo', 'bar'\)\n$") + "error: argument {foo,bar}: invalid choice: 'baz', maybe you meant" + r" 'bar'? \(choose from 'foo', 'bar'\)\n$" ) def test_optional_subparsers(self): From ee05c1eae9b20b99a6d3940aee932f25b0c778b5 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 20:03:34 +0500 Subject: [PATCH 09/24] Fixed error test case assert msg :hammer: --- Lib/test/test_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 2b1568ab11dd52..8bb0594b725c18 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2197,7 +2197,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): self.assertRegex( excinfo.exception.stderr, "error: argument {foo,bar}: invalid choice: 'baz', maybe you meant" - r" 'bar'? \(choose from 'foo', 'bar'\)\n$" + " 'bar'? (choose from 'foo', 'bar'\)\\n" ) def test_optional_subparsers(self): From 4a364068c21f84e4629b24b65a0e0f2163d27f5f Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 20:38:01 +0500 Subject: [PATCH 10/24] assertion fix :hammer: --- Lib/test/test_argparse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 8bb0594b725c18..232dc204a2ac1c 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2196,8 +2196,8 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - "error: argument {foo,bar}: invalid choice: 'baz', maybe you meant" - " 'bar'? (choose from 'foo', 'bar'\)\\n" + r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant" + " 'bar'? (choose from 'foo', 'bar')" ) def test_optional_subparsers(self): From fe169bc396481ac318d40b2d95fa0e7b4108e577 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 21:04:49 +0500 Subject: [PATCH 11/24] assertion test case fix --- Lib/test/test_argparse.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 232dc204a2ac1c..fb3bcae3b9f01b 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2194,10 +2194,11 @@ def test_wrong_argument_subparsers_no_destination_error(self): subparsers.add_parser('bar') with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('baz',)) - self.assertRegex( + self.assertEqual( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant" - " 'bar'? (choose from 'foo', 'bar')" + "usage: __main__.py [-h] {foo,bar} ...\n__main__.py: error:" + "argument {foo,bar}: invalid choice: 'baz', maybe you meant" + " 'bar'? (choose from 'foo', 'bar')\n" ) def test_optional_subparsers(self): From 9fe0d95ff5014ed84cdf354a5367f5b3fd23b2c1 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 21:23:57 +0500 Subject: [PATCH 12/24] Test Case fix --- Lib/test/test_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index fb3bcae3b9f01b..767e14201abb71 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2197,7 +2197,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): self.assertEqual( excinfo.exception.stderr, "usage: __main__.py [-h] {foo,bar} ...\n__main__.py: error:" - "argument {foo,bar}: invalid choice: 'baz', maybe you meant" + " argument {foo,bar}: invalid choice: 'baz', maybe you meant" " 'bar'? (choose from 'foo', 'bar')\n" ) From d12e1c4fe64d3ea2ebb2b32a14652b78de4f8edd Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 22:06:48 +0500 Subject: [PATCH 13/24] Reveet to assertRegex from assertEqual --- Lib/test/test_argparse.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 767e14201abb71..beb17a27ec0f50 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2194,11 +2194,9 @@ def test_wrong_argument_subparsers_no_destination_error(self): subparsers.add_parser('bar') with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('baz',)) - self.assertEqual( + self.assertRegex( excinfo.exception.stderr, - "usage: __main__.py [-h] {foo,bar} ...\n__main__.py: error:" - " argument {foo,bar}: invalid choice: 'baz', maybe you meant" - " 'bar'? (choose from 'foo', 'bar')\n" + r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? \(choose from 'foo', 'bar'\)\n$" ) def test_optional_subparsers(self): From 35f09613333de90602eb1e91034a2ef5799bfa4d Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 22:25:05 +0500 Subject: [PATCH 14/24] Remove unused imports :hammer: --- Lib/test/test_argparse.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index beb17a27ec0f50..43ebe25f573e06 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -13,7 +13,6 @@ import argparse import warnings -from gettext import gettext as _ from test.support import os_helper from unittest import mock @@ -2196,7 +2195,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? \(choose from 'foo', 'bar'\)\n$" + r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? (choose from 'foo', 'bar')" ) def test_optional_subparsers(self): From 087895c645157587d53f1069fa9658008f65af3a Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 22:58:36 +0500 Subject: [PATCH 15/24] assertion msg fixed :hammer: --- Lib/test/test_argparse.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 43ebe25f573e06..100a2da0164fdf 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2193,9 +2193,11 @@ def test_wrong_argument_subparsers_no_destination_error(self): subparsers.add_parser('bar') with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('baz',)) - self.assertRegex( + self.assertEqual( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? (choose from 'foo', 'bar')" + "usage: __main__.py [-h] {foo,bar} ...\\n__main__.py: error: argument" + " {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'?" + " (choose from 'foo', 'bar')\\n" ) def test_optional_subparsers(self): From 6eeae5cd964da52025e0ad95c726c9a60bef67bb Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Fri, 25 Nov 2022 23:37:06 +0500 Subject: [PATCH 16/24] test cases fixed :hammer: --- Lib/argparse.py | 2 +- Lib/test/test_argparse.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 4d4c4a5d72c6f6..7437faa4fb4547 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2548,7 +2548,7 @@ def _check_value(self, action, value): args = {'value': value, 'choices': ', '.join(map(repr, action.choices))} - if closest_choice := closest_choice and closest_choice[0] or '': + if closest_choice := closest_choice and closest_choice[0] or '': args['closest'] = closest_choice msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' '(choose from %(choices)s)') diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 100a2da0164fdf..97d48d151b43be 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2192,12 +2192,10 @@ def test_wrong_argument_subparsers_no_destination_error(self): subparsers.add_parser('foo') subparsers.add_parser('bar') with self.assertRaises(ArgumentParserError) as excinfo: - parser.parse_args(('baz',)) - self.assertEqual( + parser.parse_args(('python',)) + self.assertRegex( excinfo.exception.stderr, - "usage: __main__.py [-h] {foo,bar} ...\\n__main__.py: error: argument" - " {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'?" - " (choose from 'foo', 'bar')\\n" + r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" ) def test_optional_subparsers(self): From 9965694e969de8fbf9fe1279ddf5fed2207170a7 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 00:09:45 +0500 Subject: [PATCH 17/24] assert fix --- Lib/test/test_argparse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 97d48d151b43be..9fc94fdc00642b 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2192,10 +2192,10 @@ def test_wrong_argument_subparsers_no_destination_error(self): subparsers.add_parser('foo') subparsers.add_parser('bar') with self.assertRaises(ArgumentParserError) as excinfo: - parser.parse_args(('python',)) + parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" + r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? \(choose from 'foo', 'bar'\)\n$" ) def test_optional_subparsers(self): From 4ef218a17fd0c6614be04735235195cb3a9697ce Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 00:34:17 +0500 Subject: [PATCH 18/24] assertion fix --- Lib/test/test_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 9fc94fdc00642b..d9de6cfbab8031 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2195,7 +2195,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? \(choose from 'foo', 'bar'\)\n$" + r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? (choose from 'foo', 'bar')\\n$" ) def test_optional_subparsers(self): From e63a01c1fe01813770119ad826f44d8579805ddf Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 00:56:29 +0500 Subject: [PATCH 19/24] revert testing --- Lib/argparse.py | 11 +---------- Lib/test/test_argparse.py | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 7437faa4fb4547..240625ff01084e 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -85,7 +85,6 @@ ] -import difflib as _difflib import os as _os import re as _re import sys as _sys @@ -2544,17 +2543,9 @@ def _get_value(self, action, arg_string): def _check_value(self, action, value): # converted value must be one of the choices (if specified) if action.choices is not None and value not in action.choices: - closest_choice = _difflib.get_close_matches(value, action.choices) args = {'value': value, 'choices': ', '.join(map(repr, action.choices))} - - if closest_choice := closest_choice and closest_choice[0] or '': - args['closest'] = closest_choice - msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' - '(choose from %(choices)s)') - else: - msg = _('invalid choice: %(value)r (choose from %(choices)s)') - + msg = _('invalid choice: %(value)r (choose from %(choices)s)') raise ArgumentError(action, msg % args) # ======================= diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index d9de6cfbab8031..cabb2f837693ff 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2195,7 +2195,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? (choose from 'foo', 'bar')\\n$" + r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" ) def test_optional_subparsers(self): From bfc926239a0d48999bbbf2a0fc5d1df128366d9d Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 01:01:11 +0500 Subject: [PATCH 20/24] test: hammer: --- Lib/test/test_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index cabb2f837693ff..c6dab42290a685 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2195,7 +2195,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" + r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$", ) def test_optional_subparsers(self): From b3b4a9eb460160d262517d967e6d3e7c5734910c Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 01:46:41 +0500 Subject: [PATCH 21/24] fixed --- Lib/argparse.py | 17 +++++++++++++---- Lib/test/test_argparse.py | 14 +++++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 240625ff01084e..e8a85d65865cdc 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -84,7 +84,7 @@ 'ZERO_OR_MORE', ] - +import difflib as _difflib import os as _os import re as _re import sys as _sys @@ -2543,9 +2543,18 @@ def _get_value(self, action, arg_string): def _check_value(self, action, value): # converted value must be one of the choices (if specified) if action.choices is not None and value not in action.choices: - args = {'value': value, - 'choices': ', '.join(map(repr, action.choices))} - msg = _('invalid choice: %(value)r (choose from %(choices)s)') + closest_choice = _difflib.get_close_matches(value, action.choices) + args = { + 'value': value, + 'choices': ', '.join(map(repr, action.choices)), + } + if closest_choice := closest_choice and closest_choice[0] or None: + args['closest'] = closest_choice + msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' + '(choose from %(choices)s)') + else: + msg = _('invalid choice: %(value)r (choose from %(choices)s)') + raise ArgumentError(action, msg % args) # ======================= diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index c6dab42290a685..65d469f308783a 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2187,6 +2187,18 @@ def test_required_subparsers_no_destination_error(self): ) def test_wrong_argument_subparsers_no_destination_error(self): + parser = ErrorRaisingArgumentParser() + subparsers = parser.add_subparsers(required=True) + subparsers.add_parser('foo') + subparsers.add_parser('bar') + with self.assertRaises(ArgumentParserError) as excinfo: + parser.parse_args(('test',)) + self.assertRegex( + excinfo.exception.stderr, + r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" + ) + + def test_wrong_argument_subparsers_no_destination_error_with_closest_choice_input(self): parser = ErrorRaisingArgumentParser() subparsers = parser.add_subparsers(required=True) subparsers.add_parser('foo') @@ -2195,7 +2207,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$", + r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant bar? \(choose from 'foo', 'bar'\)\n$", ) def test_optional_subparsers(self): From b8bc465b07d5bce0361c6d62dd427e07fce7ab22 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 13:25:19 +0500 Subject: [PATCH 22/24] PR review changes :hammer: --- Lib/argparse.py | 13 +++++++++++-- Lib/test/test_argparse.py | 12 ------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index e8a85d65865cdc..3e1c62714a2a78 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2541,14 +2541,23 @@ def _get_value(self, action, arg_string): return result def _check_value(self, action, value): + if not action.choices and isinstance(action.choices, list): + msg = 'Either add options in choices array or remove it' + raise ArgumentError(action, msg) + # converted value must be one of the choices (if specified) if action.choices is not None and value not in action.choices: - closest_choice = _difflib.get_close_matches(value, action.choices) + try: + closest_choice = _difflib.get_close_matches(value, action.choices, 1) + except TypeError: + closest_choice = [] + args = { 'value': value, 'choices': ', '.join(map(repr, action.choices)), } - if closest_choice := closest_choice and closest_choice[0] or None: + if closest_choice: + closest_choice = closest_choice[0] args['closest'] = closest_choice msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? ' '(choose from %(choices)s)') diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 65d469f308783a..9d878dc4f80691 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2187,18 +2187,6 @@ def test_required_subparsers_no_destination_error(self): ) def test_wrong_argument_subparsers_no_destination_error(self): - parser = ErrorRaisingArgumentParser() - subparsers = parser.add_subparsers(required=True) - subparsers.add_parser('foo') - subparsers.add_parser('bar') - with self.assertRaises(ArgumentParserError) as excinfo: - parser.parse_args(('test',)) - self.assertRegex( - excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 'foo', 'bar'\)\n$" - ) - - def test_wrong_argument_subparsers_no_destination_error_with_closest_choice_input(self): parser = ErrorRaisingArgumentParser() subparsers = parser.add_subparsers(required=True) subparsers.add_parser('foo') From ade070fc575613d6d2a9eb7a7b75f954026c0800 Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 17:25:02 +0500 Subject: [PATCH 23/24] test case fix :hammer: --- Lib/test/test_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 9d878dc4f80691..2efd49ca408539 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2195,7 +2195,7 @@ def test_wrong_argument_subparsers_no_destination_error(self): parser.parse_args(('baz',)) self.assertRegex( excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant bar? \(choose from 'foo', 'bar'\)\n$", + r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? \(choose from 'foo', 'bar'\)\n$", ) def test_optional_subparsers(self): From 3753a0d524e951a7bb30d25f8599698ae176c46d Mon Sep 17 00:00:00 2001 From: Abdul Rafey Date: Sat, 26 Nov 2022 18:00:57 +0500 Subject: [PATCH 24/24] test case fixation assertIn --- Lib/test/test_argparse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 2efd49ca408539..ec289310367db3 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2193,9 +2193,9 @@ def test_wrong_argument_subparsers_no_destination_error(self): subparsers.add_parser('bar') with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('baz',)) - self.assertRegex( + self.assertIn( + "error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? (choose from 'foo', 'bar')", excinfo.exception.stderr, - r"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? \(choose from 'foo', 'bar'\)\n$", ) def test_optional_subparsers(self):