Example #1
0
def test_print_json_ensure_ascii():
    console = Console(file=io.StringIO(), color_system="truecolor")
    console.print_json(data={"foo": "💩"}, ensure_ascii=False)
    result = console.file.getvalue()
    print(repr(result))
    expected = '\x1b[1m{\x1b[0m\n  \x1b[1;34m"foo"\x1b[0m: \x1b[32m"💩"\x1b[0m\n\x1b[1m}\x1b[0m\n'
    assert result == expected
Example #2
0
def test_print_json_indent_none():
    console = Console(file=io.StringIO(), color_system="truecolor")
    data = {"name": "apple", "count": 1}
    console.print_json(data=data, indent=None)
    result = console.file.getvalue()
    expected = '\x1b[1m{\x1b[0m\x1b[1;34m"name"\x1b[0m: \x1b[32m"apple"\x1b[0m, \x1b[1;34m"count"\x1b[0m: \x1b[1;36m1\x1b[0m\x1b[1m}\x1b[0m\n'
    assert result == expected
Example #3
0
def test_print_json_data():
    console = Console(file=io.StringIO(), color_system="truecolor")
    console.print_json(data=[False, True, None, "foo"], indent=4)
    result = console.file.getvalue()
    print(repr(result))
    expected = '\x1b[1m[\x1b[0m\n    \x1b[3;91mfalse\x1b[0m,\n    \x1b[3;92mtrue\x1b[0m,\n    \x1b[3;35mnull\x1b[0m,\n    \x1b[32m"foo"\x1b[0m\n\x1b[1m]\x1b[0m\n'
    assert result == expected
def render_json(data: Any):
    """
    Print nicely formatted representation of a JSON serializable python primitive.
    """
    console = Console()
    console.print()
    console.print_json(json.dumps(data))
    console.print()
Example #5
0
def parse_apk(apkfile, workers, fn_match=None, outfile=None):
    console = Console()
    console.log(f"Parsing {apkfile} with {workers} workers ...")
    dexes = list(extract_dex_files(apkfile))
    console.log(f"Found {len(dexes)} DEX file.")
    total = sum(map(lambda d: len(d.data), dexes))
    progress = Progress(
        TextColumn("[progress.description]{task.description}"),
        BarColumn(
            complete_style='bar.complete',
            finished_style='bar.finished',
            pulse_style='bar.pulse',
        ),
        TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
        TimeRemainingColumn(),
        TimeElapsedColumn(),
        console=console,
    )
    out = {}
    out.update(JNI_COMMON)
    num_classes = 0
    t0 = datetime.now()
    with progress:
        task = progress.add_task("Analyzing...", total=total)
        with multiprocessing.Pool(workers) as pool:
            result = pool.imap(parse_dex_proc, dexes)
            for dex, count, res in result:
                if count == 0:
                    console.log(
                        "Parse {} ({} bytes) [bold red]failed: {}".format(
                            dex.name, len(dex.data), res))
                    continue
                console.log("Parse {} ({} bytes), found {} classes.".format(
                    dex.name, len(dex.data), count))
                num_classes += count
                progress.update(task, advance=len(dex.data))
                for cname, data in res.items():
                    if fn_match and not fn_match(cname):
                        continue
                    out.update(data)
    console.log("Aanlyzed {} classes, cost: {}".format(num_classes,
                                                       datetime.now() - t0))
    console.log("Found {} JNI methods.".format(len(out)))
    if not outfile:
        console.print_json(data=out)
    else:
        with open(outfile, 'w') as f:
            json.dump(out, f, indent=2, ensure_ascii=False)
Example #6
0
    def get(model_tag, output):
        """Print Model details by providing the model_tag

        \b
        bentoml models get FraudDetector:latest
        bentoml models get --output=json FraudDetector:20210709_DE14C9
        """
        model = model_store.get(model_tag)
        console = Console()

        if output == "path":
            console.print(model.path)
        elif output == "json":
            info = json.dumps(model.info.to_dict(), indent=2, default=str)
            console.print_json(info)
        else:
            info = yaml.dump(model.info, indent=2)
            console.print(info)
Example #7
0
def parse_dx(dx: Analysis, fn_match=None, outfile=None):
    console = Console()
    out = {}
    out.update(JNI_COMMON)
    count = 0
    for cx in dx.get_internal_classes():
        methods = parse_class_def(cx.get_class())
        count += 1
        if not methods:
            continue
        cname = methods[0].jclass
        if fn_match and not fn_match(cname):
            continue
        for m in methods:
            out.update(m.as_dict)
    console.log(f"Parse {count} classes.")
    console.log(f"Found {len(out)} JNI methods.")
    if not outfile:
        console.print_json(data=out)
    else:
        with open(outfile, 'w') as f:
            json.dump(out, f, indent=2, ensure_ascii=False)
Example #8
0
def test_print_json_error():
    console = Console(file=io.StringIO(), color_system="truecolor")
    with pytest.raises(TypeError):
        console.print_json(["foo"], indent=4)
Example #9
0
class Environment(object):
    """Provides access to the current CLI environment."""
    def __init__(self):
        # {'path:to:command': ModuleLoader()}
        # {'vs:list': ModuleLoader()}
        self.commands = {}
        self.aliases = {}

        self.vars = {}

        self.client = None
        self.console = Console()
        self.err_console = Console(stderr=True)
        self.format = 'table'
        self.skip_confirmations = False
        self.config_file = None

        self._modules_loaded = False

    def out(self, output):
        """Outputs a string to the console (stdout)."""
        if self.format == 'json':
            try:
                self.console.print_json(output)
            # Tried to print not-json, so just print it out normally...
            except JSONDecodeError:
                click.echo(output)
        elif self.format == 'jsonraw':
            #  Using Rich here is problematic because in the unit tests it thinks the terminal is 80 characters wide
            #  and only prints out that many characters.
            click.echo(output)
        else:
            # If we want to print a list of tables, Rich doens't handle that well.
            if isinstance(output, list):
                for line in output:
                    self.console.print(line, overflow='ignore')
            else:
                self.console.print(output, overflow='ignore')

    def err(self, output, newline=True):
        """Outputs an error string to the console (stderr)."""

        self.err_console.print(output, new_line_start=newline)

    def fmt(self, output, fmt=None):
        """Format output based on current the environment format."""
        if fmt is None:
            fmt = self.format
        return formatting.format_output(output, fmt)

    def format_output_is_json(self):
        """Return True if format output is json or jsonraw"""
        return 'json' in self.format

    def fout(self, output):
        """Format the input and output to the console (stdout)."""
        if output is not None:
            try:
                self.out(self.fmt(output))
            except UnicodeEncodeError:
                # If we hit an undecodeable entry, just try outputting as json.
                self.out(self.fmt(output, 'json'))

    def python_output(self, output):
        """Prints out python code"""
        self.console.print(Syntax(output, "python"))

    def input(self, prompt, default=None, show_default=True):
        """Provide a command prompt."""
        return click.prompt(prompt, default=default, show_default=show_default)

    def getpass(self, prompt, default=None):
        """Provide a password prompt."""
        password = click.prompt(prompt, hide_input=True, default=default)

        # https://github.com/softlayer/softlayer-python/issues/1436
        # click.prompt uses python's getpass() in the background
        # https://github.com/python/cpython/blob/3.9/Lib/getpass.py#L97
        # In windows, shift+insert actually inputs the below 2 characters
        # If we detect those 2 characters, need to manually read from the clipbaord instead
        # https://stackoverflow.com/questions/101128/how-do-i-read-text-from-the-clipboard
        if password == 'àR':
            # tkinter is a built in python gui, but it has clipboard reading functions.
            # pylint: disable=import-outside-toplevel
            from tkinter import Tk
            tk_manager = Tk()
            password = tk_manager.clipboard_get()
            # keep the window from showing
            tk_manager.withdraw()
        return password

    # Command loading methods
    def list_commands(self, *path):
        """Command listing."""
        path_str = ':'.join(path)

        commands = []
        for command in self.commands:

            # Filter based on prefix and the segment length
            if all([
                    command.startswith(path_str),
                    len(path) == command.count(":")
            ]):

                # offset is used to exclude the path that the caller requested.
                offset = len(path_str) + 1 if path_str else 0
                commands.append(command[offset:])

        return sorted(commands)

    def get_command(self, *path):
        """Return command at the given path or raise error."""
        path_str = ':'.join(path)

        if path_str in self.commands:
            return self.commands[path_str].load()

        return None

    def resolve_alias(self, path_str):
        """Returns the actual command name. Uses the alias mapping."""
        if path_str in self.aliases:
            return self.aliases[path_str]
        return path_str

    def load(self):
        """Loads all modules."""
        if self._modules_loaded is True:
            return

        self.load_modules_from_python(routes.ALL_ROUTES)
        self.aliases.update(routes.ALL_ALIASES)
        self._load_modules_from_entry_points('softlayer.cli')

        self._modules_loaded = True

    def load_modules_from_python(self, route_list):
        """Load modules from the native python source."""
        for name, modpath in route_list:
            if ':' in modpath:
                path, attr = modpath.split(':', 1)
            else:
                path, attr = modpath, None
            self.commands[name] = ModuleLoader(path, attr=attr)

    def _load_modules_from_entry_points(self, entry_point_group):
        """Load modules from the entry_points (slower).

        Entry points can be used to add new commands to the CLI.

        Usage:

            entry_points={'softlayer.cli': ['new-cmd = mymodule.new_cmd.cli']}

        """
        for obj in pkg_resources.iter_entry_points(group=entry_point_group,
                                                   name=None):
            self.commands[obj.name] = obj

    def ensure_client(self, config_file=None, is_demo=False, proxy=None):
        """Create a new SLAPI client to the environment.

        This will be a no-op if there is already a client in this environment.
        """
        if self.client is not None:
            return

        # Environment can be passed in explicitly. This is used for testing
        if is_demo:
            client = SoftLayer.BaseClient(
                transport=SoftLayer.FixtureTransport(),
                auth=None,
            )
        else:
            # Create SL Client
            client = SoftLayer.create_client_from_env(
                proxy=proxy,
                config_file=config_file,
            )
        self.client = client