diff options
author | Jeremy Morse <jeremy.morse@sony.com> | 2019-10-31 13:41:24 +0000 |
---|---|---|
committer | Jeremy Morse <jeremy.morse@sony.com> | 2019-10-31 13:49:47 +0000 |
commit | f78c236efda85af1e526ac35ed535ef4786450e3 (patch) | |
tree | 1ff1609178e085f58b46dfcbce21fd6b2ef40025 /debuginfo-tests/dexter/dex/utils/ExtArgParse.py | |
parent | efacf2ce55d698e5df8173f0d4dacbc7d3c7fd34 (diff) | |
download | bcm5719-llvm-f78c236efda85af1e526ac35ed535ef4786450e3.tar.gz bcm5719-llvm-f78c236efda85af1e526ac35ed535ef4786450e3.zip |
Import Dexter to debuginfo-tests
Dexter (Debug Experience Tester) is a test-driver for our debug info
integration tests, reading a set of debug experience expectations and
comparing them with the actual behaviour of a program under a debugger.
More about Dexter can be found in the RFC:
http://lists.llvm.org/pipermail/llvm-dev/2019-October/135773.html
and the phab review in D68708. Not all the debuginfo tests have been
transformed into Dexter tests, and we look forwards to doing that
incrementally.
This commit mostly aims to flush out buildbots that are running
debuginfo-tests but don't have python 3 installed, possibly
green-dragon and some windows bots.
Diffstat (limited to 'debuginfo-tests/dexter/dex/utils/ExtArgParse.py')
-rw-r--r-- | debuginfo-tests/dexter/dex/utils/ExtArgParse.py | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/debuginfo-tests/dexter/dex/utils/ExtArgParse.py b/debuginfo-tests/dexter/dex/utils/ExtArgParse.py new file mode 100644 index 00000000000..9fa08fb066e --- /dev/null +++ b/debuginfo-tests/dexter/dex/utils/ExtArgParse.py @@ -0,0 +1,148 @@ +# DExTer : Debugging Experience Tester +# ~~~~~~ ~ ~~ ~ ~~ +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +"""Extended Argument Parser. Extends the argparse module with some extra +functionality, to hopefully aid user-friendliness. +""" + +import argparse +import difflib +import unittest + +from dex.utils import PrettyOutput +from dex.utils.Exceptions import Error + +# re-export all of argparse +for argitem in argparse.__all__: + vars()[argitem] = getattr(argparse, argitem) + + +def _did_you_mean(val, possibles): + close_matches = difflib.get_close_matches(val, possibles) + did_you_mean = '' + if close_matches: + did_you_mean = 'did you mean {}?'.format(' or '.join( + "<y>'{}'</>".format(c) for c in close_matches[:2])) + return did_you_mean + + +def _colorize(message): + lines = message.splitlines() + for i, line in enumerate(lines): + lines[i] = lines[i].replace('usage:', '<g>usage:</>') + if line.endswith(':'): + lines[i] = '<g>{}</>'.format(line) + return '\n'.join(lines) + + +class ExtArgumentParser(argparse.ArgumentParser): + def error(self, message): + """Use the Dexception Error mechanism (including auto-colored output). + """ + raise Error('{}\n\n{}'.format(message, self.format_usage())) + + # pylint: disable=redefined-builtin + def _print_message(self, message, file=None): + if message: + if file and file.name == '<stdout>': + file = PrettyOutput.stdout + else: + file = PrettyOutput.stderr + + self.context.o.auto(message, file) + + # pylint: enable=redefined-builtin + + def format_usage(self): + return _colorize(super(ExtArgumentParser, self).format_usage()) + + def format_help(self): + return _colorize(super(ExtArgumentParser, self).format_help() + '\n\n') + + @property + def _valid_visible_options(self): + """A list of all non-suppressed command line flags.""" + return [ + item for sublist in vars(self)['_actions'] + for item in sublist.option_strings + if sublist.help != argparse.SUPPRESS + ] + + def parse_args(self, args=None, namespace=None): + """Add 'did you mean' output to errors.""" + args, argv = self.parse_known_args(args, namespace) + if argv: + errors = [] + for arg in argv: + if arg in self._valid_visible_options: + error = "unexpected argument: <y>'{}'</>".format(arg) + else: + error = "unrecognized argument: <y>'{}'</>".format(arg) + dym = _did_you_mean(arg, self._valid_visible_options) + if dym: + error += ' ({})'.format(dym) + errors.append(error) + self.error('\n '.join(errors)) + + return args + + def add_argument(self, *args, **kwargs): + """Automatically add the default value to help text.""" + if 'default' in kwargs: + default = kwargs['default'] + if default is None: + default = kwargs.pop('display_default', None) + + if (default and isinstance(default, (str, int, float)) + and default != argparse.SUPPRESS): + assert ( + 'choices' not in kwargs or default in kwargs['choices']), ( + "default value '{}' is not one of allowed choices: {}". + format(default, kwargs['choices'])) + if 'help' in kwargs and kwargs['help'] != argparse.SUPPRESS: + assert isinstance(kwargs['help'], str), type(kwargs['help']) + kwargs['help'] = ('{} (default:{})'.format( + kwargs['help'], default)) + + super(ExtArgumentParser, self).add_argument(*args, **kwargs) + + def __init__(self, context, *args, **kwargs): + self.context = context + super(ExtArgumentParser, self).__init__(*args, **kwargs) + + +class TestExtArgumentParser(unittest.TestCase): + def test_did_you_mean(self): + parser = ExtArgumentParser(None) + parser.add_argument('--foo') + parser.add_argument('--qoo', help=argparse.SUPPRESS) + parser.add_argument('jam', nargs='?') + + parser.parse_args(['--foo', '0']) + + expected = (r"^unrecognized argument\: <y>'\-\-doo'</>\s+" + r"\(did you mean <y>'\-\-foo'</>\?\)\n" + r"\s*<g>usage:</>") + with self.assertRaisesRegex(Error, expected): + parser.parse_args(['--doo']) + + parser.add_argument('--noo') + + expected = (r"^unrecognized argument\: <y>'\-\-doo'</>\s+" + r"\(did you mean <y>'\-\-noo'</> or <y>'\-\-foo'</>\?\)\n" + r"\s*<g>usage:</>") + with self.assertRaisesRegex(Error, expected): + parser.parse_args(['--doo']) + + expected = (r"^unrecognized argument\: <y>'\-\-bar'</>\n" + r"\s*<g>usage:</>") + with self.assertRaisesRegex(Error, expected): + parser.parse_args(['--bar']) + + expected = (r"^unexpected argument\: <y>'\-\-foo'</>\n" + r"\s*<g>usage:</>") + with self.assertRaisesRegex(Error, expected): + parser.parse_args(['--', 'x', '--foo']) |