New submission from Karthikeyan Singaravelan <tir.kar...@gmail.com>:
I came across this idea while working on error messages for click at https://github.com/pallets/click/issues/1446. Currently for unknown arguments which could in some case be typos argparse throws an error but doesn't make any suggestions. It could do some heuristic to suggest matches. The unrecognized argument error prints all unrecognized arguments so in that case it will be less useful to mix match suggestions. It can be helpful for single argument usages. argparse is performance sensitive since it's used in cli environments so I feel the tradeoff to do simple match to make suggestions as a good user experience. # ssl_helper.py import argparse parser = argparse.ArgumentParser() parser.add_argument('--include-ssl', action='store_true') namespace = parser.parse_args() No suggestions are included currently $ python3.8 ssl_helper.py --include-ssll usage: ssl_helper.py [-h] [--include-ssl] ssl_helper.py: error: unrecognized arguments: --include-ssll Include suggestions based when one of the option starts with the argument supplied similar to click $ ./python.exe ssl_helper.py --include-ssll usage: ssl_helper.py [-h] [--include-ssl] ssl_helper.py: error: unrecognized argument: --include-ssll . Did you mean --include-ssl? difflib.get_close_matches could also provide better suggestions in some cases but comes at import cost and could be imported only during error messages as proposed in the click issue ./python.exe ssl_helper.py --exclude-ssl usage: ssl_helper.py [-h] [--include-ssl] ssl_helper.py: error: unrecognized argument: --exclude-ssl . Did you mean --include-ssl? Attached is a simple patch of the implementation with startswith which is more simple and difflib.get_close_matches diff --git Lib/argparse.py Lib/argparse.py index 5d3ce2ad70..e10a4f0c9b 100644 --- Lib/argparse.py +++ Lib/argparse.py @@ -1818,8 +1818,29 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def parse_args(self, args=None, namespace=None): args, argv = self.parse_known_args(args, namespace) if argv: - msg = _('unrecognized arguments: %s') - self.error(msg % ' '.join(argv)) + suggestion = None + if len(argv) == 1: + argument = argv[0] + + # simple startswith + for option in self._option_string_actions: + if argument.startswith(option): + suggestion = option + break + + # difflib impl + import difflib + try: + suggestion = difflib.get_close_matches(argv[0], self._option_string_actions, n=1)[0] + except IndexError: + pass + + if suggestion: + msg = _('unrecognized argument: %s . Did you mean %s?') + self.error(msg % (' '.join(argv), suggestion)) + else: + msg = _('unrecognized arguments: %s') + self.error(msg % ' '.join(argv)) return args def parse_known_args(self, args=None, namespace=None): ---------- components: Library (Lib) messages: 358699 nosy: paul.j3, rhettinger, xtreak priority: normal severity: normal status: open title: Add suggestions to argparse error message output for unrecognized arguments type: enhancement versions: Python 3.9 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue39106> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com