Python click.MultiCommand() Examples

The following are 19 code examples of click.MultiCommand(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module click , or try the search function .
Example #1
Source File: _compat.py    From click-shell with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
def get_choices(cli, prog_name, args, incomplete):
        """
        This is identical to click._bashcomplete:get_choices in click 6.4+
        """
        ctx = resolve_ctx(cli, prog_name, args)

        if ctx is None:
            return

        choices = []
        if incomplete and not incomplete[:1].isalnum():
            for param in ctx.command.params:
                if not isinstance(param, click.Option):
                    continue
                choices.extend(param.opts)
                choices.extend(param.secondary_opts)
        elif isinstance(ctx.command, click.MultiCommand):
            choices.extend(ctx.command.list_commands(ctx))

        for item in choices:
            if item.startswith(incomplete):
                yield item 
Example #2
Source File: core.py    From click-shell with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
def make_click_shell(ctx, prompt=None, intro=None, hist_file=None):
    assert isinstance(ctx, click.Context)
    assert isinstance(ctx.command, click.MultiCommand)

    # Set this to None so that it doesn't get printed out in usage messages
    ctx.info_name = None

    # Create our shell object
    shell = ClickShell(ctx=ctx, hist_file=hist_file)

    if prompt is not None:
        shell.prompt = prompt

    if intro is not None:
        shell.intro = intro

    # Add all the commands
    for name in ctx.command.list_commands(ctx):
        command = ctx.command.get_command(ctx, name)
        shell.add_command(command, name)

    return shell 
Example #3
Source File: __init__.py    From autopwn with GNU Affero General Public License v3.0 6 votes vote down vote up
def make_click_shell(ctx, prompt=None, title=None, intro=None, hist_file=None):
    assert isinstance(ctx, click.Context)
    assert isinstance(ctx.command, click.MultiCommand)

    # Set this to None so that it doesn't get printed out in usage messages
    ctx.info_name = None

    # Create our shell object
    shell = MyClickShell(ctx=ctx, hist_file=hist_file)

    if prompt is not None:
        shell.prompt = prompt

    if intro is not None:
        shell.intro = intro

    if title is not None:
        shell.title = title

    # Add all the commands
    for name in ctx.command.list_commands(ctx):
        command = ctx.command.get_command(ctx, name)
        shell.add_command(command, name)

    return shell 
Example #4
Source File: __init__.py    From hobbit-core with MIT License 5 votes vote down vote up
def format_options(self, ctx, formatter):
        """Writes all the options into the formatter if they exist."""
        # Borrowed from click.MultiCommand
        opts = []
        for param in self.get_params(ctx):
            rv = param.get_help_record(ctx)
            if rv is not None:
                # rewrite for color
                rv = list(rv)
                rv[0] = click.style(rv[0], fg='green')
                opts.append(tuple(rv))

        if opts:
            with formatter.section('Options'):
                formatter.write_dl(opts) 
Example #5
Source File: __init__.py    From treadmill with Apache License 2.0 5 votes vote down vote up
def make_commands(section, **click_args):
    """Make a Click multicommand from all submodules of the module."""

    class MCommand(click.MultiCommand):
        """Treadmill CLI driver."""

        def __init__(self, *args, **kwargs):
            if kwargs and click_args:
                kwargs.update(click_args)

            click.MultiCommand.__init__(self, *args, **kwargs)

        def list_commands(self, ctx):
            """Return list of commands in section."""
            return sorted(plugin_manager.names(section))

        def get_command(self, ctx, cmd_name):
            """Return dymanically constructed command."""
            try:
                return plugin_manager.load(section, cmd_name).init()
            except ImportError as import_err:
                print(
                    'dependency error: {}:{} - {}'.format(
                        section, cmd_name, str(import_err)
                    ),
                    file=sys.stderr
                )
            except KeyError:
                raise click.UsageError('Invalid command: %s' % cmd_name)

    return MCommand 
Example #6
Source File: test_core.py    From click-shell with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def test_create(self):

        shell = Shell()

        assert isinstance(shell, click.MultiCommand) 
Example #7
Source File: quick.py    From quick with GNU General Public License v3.0 5 votes vote down vote up
def initCommandUI(self, func, run_exit, parent_layout=None):
        opt_set = CommandLayout(func, run_exit, parent_layout=parent_layout)
        if isinstance(func, click.MultiCommand):
            tabs = _InputTabWidget()
            for cmd, f in func.commands.items():
                sub_opt_set = self.initCommandUI(f, run_exit, parent_layout=opt_set)
                tab = QtWidgets.QWidget()
                tab.setLayout(sub_opt_set)
                tabs.addTab(tab, cmd)
            opt_set.addWidget(
                    tabs, opt_set.rowCount(), 0, 1, 2
                    )
            # return opt_set
        elif isinstance(func, click.Command):
            new_thread = getattr(func, "new_thread", self.new_thread)
            opt_set.add_cmd_buttons( args=
                    [
                        {
                            'label':'&Run',
                            'cmd_slot': partial(self.run_cmd,\
                                    new_thread=new_thread),
                            "tooltip":"run command"
                            },
                        {
                            'label':'&Copy',
                            'cmd_slot': self.copy_cmd,
                            "tooltip":"copy command to clipboard"
                            },
                        ]
                    )
        return opt_set 
Example #8
Source File: make_cli_rst.py    From cooler with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def _filter_commands(ctx, commands=None):
    """Return list of used commands."""
    lookup = getattr(ctx.command, 'commands', {})
    if not lookup and isinstance(ctx.command, click.MultiCommand):
        lookup = _get_lazyload_commands(ctx.command)

    if commands is None:
        return sorted(lookup.values(), key=lambda item: item.name)

    names = [name.strip() for name in commands.split(',')]
    return [lookup[name] for name in names if name in lookup] 
Example #9
Source File: ext.py    From sphinx-click with MIT License 5 votes vote down vote up
def _filter_commands(ctx, commands=None):
    """Return list of used commands."""
    lookup = getattr(ctx.command, 'commands', {})
    if not lookup and isinstance(ctx.command, click.MultiCommand):
        lookup = _get_lazyload_commands(ctx.command)

    if commands is None:
        return sorted(lookup.values(), key=lambda item: item.name)

    names = [name.strip() for name in commands.split(',')]
    return [lookup[name] for name in names if name in lookup] 
Example #10
Source File: __main__.py    From pifpaf with Apache License 2.0 5 votes vote down vote up
def format_commands(self, ctx, formatter):
        # Same as click.MultiCommand.format_commands except it does not use
        # get_command so we don't have to load commands on listing.
        rows = []
        for subcommand in self.list_commands(ctx):
            rows.append((subcommand, 'Run ' + subcommand))

        if rows:
            with formatter.section('Commands'):
                formatter.write_dl(rows) 
Example #11
Source File: lib.py    From click-completion with MIT License 5 votes vote down vote up
def resolve_ctx(cli, prog_name, args, resilient_parsing=True):
    """

    Parameters
    ----------
    cli : click.Command
        The main click Command of the program
    prog_name : str
        The program name on the command line
    args : [str]
        The arguments already written by the user on the command line

    Returns
    -------
    click.core.Context
        A new context corresponding to the current command
    """
    ctx = cli.make_context(prog_name, list(args), resilient_parsing=resilient_parsing)
    while ctx.args + ctx.protected_args and isinstance(ctx.command, MultiCommand):
        a = ctx.protected_args + ctx.args
        cmd = ctx.command.get_command(ctx, a[0])
        if cmd is None:
            return None
        if hasattr(cmd, "no_args_is_help"):
            no_args_is_help = cmd.no_args_is_help
            cmd.no_args_is_help = False
        ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=resilient_parsing)
        if hasattr(cmd, "no_args_is_help"):
            cmd.no_args_is_help = no_args_is_help
    return ctx 
Example #12
Source File: lib.py    From pipenv with MIT License 5 votes vote down vote up
def resolve_ctx(cli, prog_name, args, resilient_parsing=True):
    """

    Parameters
    ----------
    cli : click.Command
        The main click Command of the program
    prog_name : str
        The program name on the command line
    args : [str]
        The arguments already written by the user on the command line

    Returns
    -------
    click.core.Context
        A new context corresponding to the current command
    """
    ctx = cli.make_context(prog_name, list(args), resilient_parsing=resilient_parsing)
    while ctx.args + ctx.protected_args and isinstance(ctx.command, MultiCommand):
        a = ctx.protected_args + ctx.args
        cmd = ctx.command.get_command(ctx, a[0])
        if cmd is None:
            return None
        if hasattr(cmd, "no_args_is_help"):
            no_args_is_help = cmd.no_args_is_help
            cmd.no_args_is_help = False
        ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=resilient_parsing)
        if hasattr(cmd, "no_args_is_help"):
            cmd.no_args_is_help = no_args_is_help
    return ctx 
Example #13
Source File: __init__.py    From hobbit-core with MIT License 5 votes vote down vote up
def format_commands(self, ctx, formatter):
        """Extra format methods for multi methods that adds all the commands
        after the options.
        """
        # Borrowed from click.MultiCommand
        commands = []
        for subcommand in self.list_commands(ctx):
            cmd = self.get_command(ctx, subcommand)
            # What is this, the tool lied about a command.  Ignore it
            if cmd is None:
                continue
            if cmd.hidden:
                continue

            commands.append((subcommand, cmd))

        # allow for 3 times the default spacing
        if len(commands):
            limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands)

            rows = []
            for subcommand, cmd in commands:
                help = cmd.get_short_help_str(limit)
                rows.append((subcommand, help))

            for i, row in enumerate(rows):  # rewrite for color
                row = list(row)
                row[0] = click.style(row[0], fg='green')
                rows[i] = tuple(row)

            if rows:
                with formatter.section('Commands'):
                    formatter.write_dl(rows) 
Example #14
Source File: test_formatter.py    From sphinx-click with MIT License 4 votes vote down vote up
def test_hidden(self):
        """Ensure 'hidden' subcommands are not shown."""
        @click.command()
        def hello():
            """A sample command."""

        @click.command()
        def world():
            """A world command."""

        @click.command(hidden=True)
        def hidden():
            """A hidden command."""

        class MyCLI(click.MultiCommand):
            _command_mapping = {
                'hello': hello,
                'world': world,
                'hidden': hidden,
            }

            def list_commands(self, ctx):
                return ['hello', 'world', 'hidden']

            def get_command(self, ctx, name):
                return self._command_mapping[name]

        cli = MyCLI(help='A sample custom multicommand.')
        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, show_nested=False))

        # Note that we do NOT expect this to show the 'hidden' command
        self.assertEqual(
            textwrap.dedent("""
        A sample custom multicommand.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A sample command.

        .. object:: world

            A world command.
        """).lstrip(), '\n'.join(output)) 
Example #15
Source File: test_formatter.py    From sphinx-click with MIT License 4 votes vote down vote up
def test_basics(self):
        """Validate a custom ``click.MultiCommand`` with no parameters.

        This exercises the code paths to extract commands correctly from these
        commands.
        """

        @click.command()
        def hello():
            """A sample command."""

        @click.command()
        def world():
            """A world command."""

        class MyCLI(click.MultiCommand):
            _command_mapping = {
                'hello': hello,
                'world': world,
            }

            def list_commands(self, ctx):
                return ['hello', 'world']

            def get_command(self, ctx, name):
                return self._command_mapping[name]

        cli = MyCLI(help='A sample custom multicommand.')
        ctx = click.Context(cli, info_name='cli')
        output = list(ext._format_command(ctx, show_nested=False))

        self.assertEqual(
            textwrap.dedent("""
        A sample custom multicommand.

        .. program:: cli
        .. code-block:: shell

            cli [OPTIONS] COMMAND [ARGS]...

        .. rubric:: Commands

        .. object:: hello

            A sample command.

        .. object:: world

            A world command.
        """).lstrip(), '\n'.join(output)) 
Example #16
Source File: command.py    From q2cli with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
def parse_args(self, ctx, args):
        from q2cli.core.config import CONFIG
        if isinstance(self, click.MultiCommand):
            return super().parse_args(ctx, args)

        errors = []
        parser = self.make_parser(ctx)
        skip_rest = False
        for _ in range(10):  # surely this is enough attempts
            try:
                opts, args, param_order = parser.parse_args(args=args)
                break
            except click.ClickException as e:
                errors.append(e)
                skip_rest = True

        if not skip_rest:
            for param in click.core.iter_params_for_processing(
                    param_order, self.get_params(ctx)):
                try:
                    value, args = param.handle_parse_result(ctx, opts, args)
                except click.ClickException as e:
                    errors.append(e)

            if args and not ctx.allow_extra_args and not ctx.resilient_parsing:
                errors.append(click.UsageError(
                    'Got unexpected extra argument%s (%s)'
                    % (len(args) != 1 and 's' or '',
                       ' '.join(map(click.core.make_str, args)))))
        if errors:
            click.echo(ctx.get_help()+"\n", err=True)
            if len(errors) > 1:
                problems = 'There were some problems with the command:'
            else:
                problems = 'There was a problem with the command:'
            click.echo(CONFIG.cfg_style('problem',
                       problems.center(78, ' ')), err=True)
            for idx, e in enumerate(errors, 1):
                msg = click.formatting.wrap_text(
                    e.format_message(),
                    initial_indent=' (%d/%d%s) ' % (idx, len(errors),
                                                    '?' if skip_rest else ''),
                    subsequent_indent='  ')
                click.echo(CONFIG.cfg_style('error', msg), err=True)
            ctx.exit(1)

        ctx.args = args
        return args 
Example #17
Source File: completion.py    From q2cli with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
def _generate_command_reply(cmd):
    """Recursively generate completion reply for this command and subcommands.

    Parameters
    ----------
    cmd : click.Command
        Command to generate completion replies for (including its subcommands).

    """
    import textwrap
    import click

    ctx = None

    options = ['--help']
    for param in cmd.params:
        if isinstance(param, click.Option):
            options.extend(param.opts)
            options.extend(param.secondary_opts)
            if hasattr(param, 'q2_extra_opts'):
                options.extend(param.q2_extra_opts)

    subcmd_names = []
    if isinstance(cmd, click.MultiCommand):
        subcmd_names.extend(cmd.list_commands(ctx))

    subcmd_cases = []
    for subcmd_name in subcmd_names:
        subcmd_reply = _generate_command_reply(
            cmd.get_command(ctx, subcmd_name))
        subcmd_reply = textwrap.indent(subcmd_reply, '  ')

        case = SUBCOMMAND_CASE_TEMPLATE.format(
            subcmd_name=subcmd_name, subcmd_reply=subcmd_reply)
        subcmd_cases.append(case)

    subcmd_cases = textwrap.indent('\n'.join(subcmd_cases), ' ' * 6)

    cmd_reply = COMMAND_REPLY_TEMPLATE.format(
        options=' '.join(options), subcmd_names=' '.join(subcmd_names),
        subcmd_cases=subcmd_cases)

    return cmd_reply


# NOTE: using double braces to avoid `str.format` interpolation when bash needs
# curly braces in the generated code.
#
# NOTE: the handling of a negative COMP_CWORD is necessary in certain versions
# of bash (e.g. at least the bash shipped with OS X 10.9.5). When adding
# whitespace to the end of a command, and then moving the cursor backwards in
# the command and hitting <tab>, COMP_CWORD can be negative (I've only seen -2
# as its value). This is a bash bug and is not documented behavior. Other CLIs
# with tab completion suffer from the same issue, and each one deals with this
# bug differently (some not at all, e.g. `git`). The workaround used below
# seems to provide the least destructive completion behavior for our CLI.
#
# Bug report reference:
#   https://lists.gnu.org/archive/html/bug-bash/2009-07/msg00108.html 
Example #18
Source File: __init__.py    From click-repl with MIT License 4 votes vote down vote up
def get_completions(self, document, complete_event=None):
        # Code analogous to click._bashcomplete.do_complete

        try:
            args = shlex.split(document.text_before_cursor)
        except ValueError:
            # Invalid command, perhaps caused by missing closing quotation.
            return

        cursor_within_command = (
            document.text_before_cursor.rstrip() == document.text_before_cursor
        )

        if args and cursor_within_command:
            # We've entered some text and no space, give completions for the
            # current word.
            incomplete = args.pop()
        else:
            # We've not entered anything, either at all or for the current
            # command, so give all relevant completions for this context.
            incomplete = ""

        ctx = click._bashcomplete.resolve_ctx(self.cli, "", args)
        if ctx is None:
            return

        choices = []
        for param in ctx.command.params:
            if isinstance(param, click.Option):
                for options in (param.opts, param.secondary_opts):
                    for o in options:
                        choices.append(
                            Completion(
                                text_type(o), -len(incomplete), display_meta=param.help
                            )
                        )
            elif isinstance(param, click.Argument):
                if isinstance(param.type, click.Choice):
                    for choice in param.type.choices:
                        choices.append(Completion(text_type(choice), -len(incomplete)))

        if isinstance(ctx.command, click.MultiCommand):
            for name in ctx.command.list_commands(ctx):
                command = ctx.command.get_command(ctx, name)
                choices.append(
                    Completion(
                        text_type(name),
                        -len(incomplete),
                        display_meta=getattr(command, "short_help"),
                    )
                )

        for item in choices:
            if item.text.startswith(incomplete):
                yield item 
Example #19
Source File: list_commands.py    From globus-cli with Apache License 2.0 4 votes vote down vote up
def list_commands():
    def _print_cmd(command):
        # print commands with short_help
        indent = 4
        min_space = 2

        short_help = command.get_short_help_str()

        # if the output would be pinched too close together, or if the command
        # name would overflow, use two separate lines
        if len(command.name) > _command_length - min_space:
            click.echo(" " * indent + command.name)
            click.echo(" " * (indent + _command_length) + short_help)
        # otherwise, it's all cool to cram into one line, just ljust command
        # names so that they form a nice column
        else:
            click.echo(
                " " * indent
                + "{}{}".format(command.name.ljust(_command_length), short_help)
            )

    def _print_cmd_group(command, parent_names):
        parents = " ".join(parent_names)
        if parents:
            parents = parents + " "
        click.echo("\n=== {}{} ===\n".format(parents, command.name))

    def _recursive_list_commands(command, parent_names=None):
        if parent_names is None:
            parent_names = []

        # names of parent commands, including this one, for passthrough to
        # recursive calls
        new_parent_names = copy.copy(parent_names) + [command.name]

        # group-style commands are printed as headers
        if isinstance(command, click.MultiCommand):
            _print_cmd_group(command, parent_names)

            # get the set of subcommands and recursively print all of them
            group_cmds = [
                v
                for v in command.commands.values()
                if isinstance(v, click.MultiCommand)
            ]
            func_cmds = [v for v in command.commands.values() if v not in group_cmds]
            # we want to print them all, but func commands first
            for cmd in func_cmds + group_cmds:
                _recursive_list_commands(cmd, parent_names=new_parent_names)

        # individual commands are printed solo
        else:
            _print_cmd(command)

    # get the root context (the click context for the entire CLI tree)
    root_ctx = click.get_current_context().find_root()

    _recursive_list_commands(root_ctx.command)
    # get an extra newline at the end
    click.echo("")