Files
clang-p2996/cross-project-tests/debuginfo-tests/dexter/dex/utils/ExtArgParse.py
Tobias Hieta f98ee40f4b [NFC][Py Reformat] Reformat python files in the rest of the dirs
This is an ongoing series of commits that are reformatting our
Python code. This catches the last of the python files to
reformat. Since they where so few I bunched them together.

Reformatting is done with `black`.

If you end up having problems merging this commit because you
have made changes to a python file, the best way to handle that
is to run git checkout --ours <yourfile> and then reformat it
with black.

If you run into any problems, post to discourse about it and
we will try to help.

RFC Thread below:

https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style

Reviewed By: jhenderson, #libc, Mordante, sivachandra

Differential Revision: https://reviews.llvm.org/D150784
2023-05-25 11:17:05 +02:00

155 lines
5.3 KiB
Python

# 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"])