Python click 模块,MultiCommand() 实例源码

我们从Python开源项目中,提取了以下19个代码示例,用于说明如何使用click.MultiCommand()

项目:treadmill    作者:Morgan-Stanley    | 项目源码 | 文件源码
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, name):
            try:
                return plugin_manager.load(section, name).init()
            except KeyError:
                raise click.UsageError('Invalid command: %s' % name)

    return MCommand
项目:SuperOcto    作者:mcecchi    | 项目源码 | 文件源码
def __init__(self, *args, **kwargs):
        click.MultiCommand.__init__(self, *args, **kwargs)

        from octoprint.util.commandline import CommandlineCaller
        from functools import partial

        def log_util(f):
            def log(*lines):
                    for line in lines:
                        f(line)
            return log

        self.command_caller = CommandlineCaller()
        self.command_caller.on_log_call = log_util(lambda x: click.echo(">> {}".format(x)))
        self.command_caller.on_log_stdout = log_util(click.echo)
        self.command_caller.on_log_stderr = log_util(partial(click.echo, err=True))
项目:pipenv    作者:pypa    | 项目源码 | 文件源码
def resolve_ctx(cli, prog_name, args):
    ctx = cli.make_context(prog_name, list(args), resilient_parsing=True)
    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
        ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True)
    return ctx
项目:pipenv    作者:pypa    | 项目源码 | 文件源码
def get_choices(cli, prog_name, args, incomplete):
    ctx = resolve_ctx(cli, prog_name, args)
    if ctx is None:
        return

    optctx = None
    if args:
        for param in ctx.command.get_params(ctx):
            if isinstance(param, Option) and not param.is_flag and args[-1] in param.opts + param.secondary_opts:
                optctx = param

    choices = []
    if optctx:
        choices += [c if isinstance(c, tuple) else (c, None) for c in optctx.type.complete(ctx, incomplete)]
    elif incomplete and not incomplete[:1].isalnum():
        for param in ctx.command.get_params(ctx):
            if not isinstance(param, Option):
                continue
            for opt in param.opts:
                if startswith(opt, incomplete):
                    choices.append((opt, param.help))
            for opt in param.secondary_opts:
                if startswith(opt, incomplete):
                    # don't put the doc so fish won't group the primary and
                    # and secondary options
                    choices.append((opt, None))
    elif isinstance(ctx.command, MultiCommand):
        for name in ctx.command.list_commands(ctx):
            if startswith(name, incomplete):
                choices.append((name, ctx.command.get_command_short_help(ctx, name)))
    else:
        for param in ctx.command.get_params(ctx):
            if isinstance(param, Argument):
                choices += [c if isinstance(c, tuple) else (c, None) for c in param.type.complete(ctx, incomplete)]

    for item, help in choices:
        yield (item, help)
项目:pipenv    作者:pypa    | 项目源码 | 文件源码
def init():
    """patch click to support enhanced completion"""
    import click
    click.types.ParamType.complete = param_type_complete
    click.types.Choice.complete = choice_complete
    click.core.MultiCommand.get_command_short_help = multicommand_get_command_short_help
    click.core._bashcomplete = _shellcomplete
项目:valohai-cli    作者:valohai    | 项目源码 | 文件源码
def format_commands(self, ctx, formatter):
        rows_by_prefix = defaultdict(list)

        def add_commands(multicommand, prefix=''):
            for subcommand in multicommand.list_commands(ctx):
                cmd = multicommand.get_command(ctx, subcommand)
                assert cmd is not None
                rows_by_prefix[prefix.strip()].append((prefix + subcommand, (cmd.short_help or '')))
                if isinstance(cmd, click.MultiCommand):
                    add_commands(cmd, prefix + '%s ' % cmd.name)

        add_commands(self)
        for prefix, rows in sorted(rows_by_prefix.items()):
            title = (
                'Commands (%s ...)' % prefix
                if prefix
                else 'Commands'
            )
            with formatter.section(title):
                formatter.write_dl(rows)
项目:click-completion    作者:click-contrib    | 项目源码 | 文件源码
def resolve_ctx(cli, prog_name, args):
    ctx = cli.make_context(prog_name, list(args), resilient_parsing=True)
    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
        ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True)
    return ctx
项目:click-completion    作者:click-contrib    | 项目源码 | 文件源码
def get_choices(cli, prog_name, args, incomplete):
    ctx = resolve_ctx(cli, prog_name, args)
    if ctx is None:
        return

    optctx = None
    if args:
        for param in ctx.command.get_params(ctx):
            if isinstance(param, Option) and not param.is_flag and args[-1] in param.opts + param.secondary_opts:
                optctx = param

    choices = []
    if optctx:
        choices += [c if isinstance(c, tuple) else (c, None) for c in optctx.type.complete(ctx, incomplete)]
    elif incomplete and not incomplete[:1].isalnum():
        for param in ctx.command.get_params(ctx):
            if not isinstance(param, Option):
                continue
            for opt in param.opts:
                if startswith(opt, incomplete):
                    choices.append((opt, param.help))
            for opt in param.secondary_opts:
                if startswith(opt, incomplete):
                    # don't put the doc so fish won't group the primary and
                    # and secondary options
                    choices.append((opt, None))
    elif isinstance(ctx.command, MultiCommand):
        for name in ctx.command.list_commands(ctx):
            if startswith(name, incomplete):
                choices.append((name, ctx.command.get_command_short_help(ctx, name)))
    else:
        for param in ctx.command.get_params(ctx):
            if isinstance(param, Argument):
                choices += [c if isinstance(c, tuple) else (c, None) for c in param.type.complete(ctx, incomplete)]

    for item, help in choices:
        yield (item, help)
项目:quokka_ng    作者:rochacbruno    | 项目源码 | 文件源码
def __init__(self, modules_path, base_module_name, **attrs):
        click.MultiCommand.__init__(self, **attrs)
        self.base_module_name = base_module_name
        self.modules_path = modules_path
项目:freckles    作者:makkus    | 项目源码 | 文件源码
def __init__(self, config, **kwargs):
        """Base class to provide a command-based (similar to e.g. git) cli for freckles.

        This class parses the folders in the paths provided by the config
        element for so-called 'freckle adapters'. A freckle adapter is a
        collection of files that describe commandline-arguments and tasks lists
        to execute on a folder (more information: XXX)

        Args:
          config (FrecklesConfig): the config wrapper object
          kwargs (dict): additional arguments that are forwarded to the partent click.MultiCommand constructor

        """

        click.MultiCommand.__init__(self, "freckles", result_callback=assemble_freckle_run, invoke_without_command=True,
                                    **kwargs)

        use_repo_option = click.Option(param_decls=["--use-repo", "-r"], required=False, multiple=True, help="extra context repos to use", is_eager=True, callback=download_extra_repos)
        output_option = click.Option(param_decls=["--output", "-o"], required=False, default="default",
                                     metavar="FORMAT", type=click.Choice(SUPPORTED_OUTPUT_FORMATS), is_eager=True,
                                     help="format of the output")
        no_run_option = click.Option(param_decls=["--no-run"],
                                     help='don\'t execute frecklecute, only prepare environment and print task list',
                                     type=bool, is_flag=True, default=False, required=False)
        version_option = click.Option(param_decls=["--version"], help='prints the version of freckles', type=bool,
                                      is_flag=True, is_eager=True, expose_value=False, callback=print_version)


        self.params = get_freckles_option_set()
        self.params.extend([ use_repo_option, output_option,  no_run_option, version_option])
        self.config = config

        self.profile_repo = ProfileRepo(self.config)

        # self.command_names.append(BREAK_COMMAND_NAME)
项目:freckles    作者:makkus    | 项目源码 | 文件源码
def __init__(self, current_command, config, **kwargs):
        """Base class to provide a command-based (similar to e.g. git) cli for frecklecute.

        This class parses the folders in the paths provided by the config
        element for so-called 'frecklecutables', (yaml) text files that contain a list of tasks and optionally command-line argument descriptions. More information: XXX

        Args:
          current_command (tuple): a tuple in the format (command_name, command_path), which is used for commands that are paths, instead of filenames in one of the known frecklecutable paths. Can be (None, None) if not a path.
          config (FrecklesConfig): the config wrapper object
          kwargs (dict): additional arguments that are forwarded to the partent click.MultiCommand constructor
        """

        click.MultiCommand.__init__(self, "freckles", **kwargs)

        output_option = click.Option(param_decls=["--output", "-o"], required=False, default="default",
                                     metavar="FORMAT", type=click.Choice(SUPPORTED_OUTPUT_FORMATS),
                                     help="format of the output", is_eager=True)
        ask_become_pass_option = click.Option(param_decls=["--ask-become-pass", "-pw"],
                                              help='whether to force ask for a password, force ask not to, or let try freckles decide (which might not always work)',
                                              type=click.Choice(["auto", "true", "false"]), default="auto")
        version_option = click.Option(param_decls=["--version"], help='prints the version of freckles', type=bool,
                                      is_flag=True, is_eager=True, expose_value=False, callback=print_version)
        no_run_option = click.Option(param_decls=["--no-run"],
                                     help='don\'t execute frecklecute, only prepare environment and print task list',
                                     type=bool, is_flag=True, default=False, required=False)
        use_repo_option = click.Option(param_decls=["--use-repo", "-r"], required=False, multiple=True, help="extra context repos to use", is_eager=True, callback=download_extra_repos, expose_value=True)

        self.params = [use_repo_option, output_option, ask_become_pass_option, no_run_option, version_option]

        self.config = config
        # .trusted_repos = DEFAULT_FRECKLES_CONFIG.trusted_repos
        # local_paths = get_local_repos(trusted_repos, "frecklecutables")

        self.command_repo = CommandRepo(config=self.config, additional_commands=[current_command])
        self.current_command = current_command[0]
项目:treadmill    作者:Morgan-Stanley    | 项目源码 | 文件源码
def make_multi_command(module_name, **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):
            climod = importlib.import_module(module_name)
            commands = set(
                [modulename for _loader, modulename, _ispkg
                 in pkgutil.iter_modules(climod.__path__)]
            )
            return sorted([cmd.replace('_', '-') for cmd in commands])

        def get_command(self, ctx, name):
            try:
                full_name = '.'.join([module_name, name.replace('-', '_')])
                mod = importlib.import_module(full_name)
                return mod.init()
            except Exception:  # pylint: disable=W0703
                with tempfile.NamedTemporaryFile(delete=False, mode='w') as f:
                    traceback.print_exc(file=f)
                    click.echo(
                        'Unable to load plugin: %s [ %s ]' % (name, f.name),
                        err=True)
                return

    return MCommand
项目:SuperOcto    作者:mcecchi    | 项目源码 | 文件源码
def __init__(self, *args, **kwargs):
        click.MultiCommand.__init__(self, *args, **kwargs)

        self.settings = None
        self.plugin_manager = None
        self.hooks = dict()

        self._logger = logging.getLogger(__name__)
        self._initialized = False
项目:click-completion    作者:click-contrib    | 项目源码 | 文件源码
def init():
    """patch click to support enhanced completion"""
    import click
    click.types.ParamType.complete = param_type_complete
    click.types.Choice.complete = choice_complete
    click.core.MultiCommand.get_command_short_help = multicommand_get_command_short_help
    click.core._bashcomplete = _shellcomplete
项目:q2cli    作者:qiime2    | 项目源码 | 文件源码
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)

    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
项目:globus-cli    作者:globus    | 项目源码 | 文件源码
def list_commands():
    def _print_cmd(command):
        # print commands with short_help
        indent = 4
        min_space = 2

        # 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:
            safeprint(' '*indent + command.name)
            safeprint(' '*(indent + _command_length) + command.short_help)
        # otherwise, it's all cool to cram into one line, just ljust command
        # names so that they form a nice column
        else:
            safeprint(' '*indent + '{}{}'.format(
                command.name.ljust(_command_length), command.short_help))

    def _print_cmd_group(command, parent_names):
        parents = ' '.join(parent_names)
        if parents:
            parents = parents + ' '
        safeprint('\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
    safeprint('')
项目:globus-cli    作者:globus    | 项目源码 | 文件源码
def get_completion_context(args):
    """
    Walk the tree of commands to a terminal command or multicommand, using the
    Click Context system.
    Effectively, we'll be using the resilient_parsing mode of commands to stop
    evaluation, then having them capture their options and arguments, passing
    us on to the next subcommand. If we walk "off the tree" with a command that
    we don't recognize, we have a hardstop condition, but otherwise, we walk as
    far as we can go and that's the location from which we should do our
    completion work.
    """
    # get the "globus" command as a click.Command
    root_command = click.get_current_context().find_root().command
    # build a new context object off of it, with resilient_parsing set so that
    # no callbacks are invoked
    ctx = root_command.make_context('globus', list(args),
                                    resilient_parsing=True)

    # walk down multicommands until we've matched on everything and are at a
    # terminal context that holds all of our completed args
    while isinstance(ctx.command, click.MultiCommand) and args:
        # trim out any params that are capturable at this level of the command
        # tree by resetting the argument list
        args = ctx.protected_args + ctx.args

        # if there were no remaining args, stop walking the tree
        if not args:
            break

        # check for a matching command, and if one isn't found stop the
        # traversal and abort the whole process -- this would mean that a
        # completed command was entered which doesn't match a known command
        # there's nothing completion can do in this case unless it implements
        # sophisticated fuzzy matching
        command = ctx.command.get_command(ctx, args[0])
        if not command:
            return None

        # otherwise, grab that command, and build a subcontext to continue the
        # tree walk
        else:
            ctx = command.make_context(args[0], args[1:], parent=ctx,
                                       resilient_parsing=True)

    # return the context we found
    return ctx
项目:AerisCloud    作者:AerisCloud    | 项目源码 | 文件源码
def cmd_complete(out, name, cmd, level=1):
    ctx = click.Context(cmd)

    cmpl = {
        'name': name,
        'cmd': cmd,
        'level': level,
        'flags': [opts for param in cmd.params for opts in param.opts
                  if isinstance(param, click.Option)],
        'complete_cmd': complete_cmd
    }

    params = [opts for param in cmd.params for opts in param.opts
              if isinstance(param, click.Parameter) and
              not isinstance(param, click.Option)]

    if isinstance(cmd, click.MultiCommand):
        cmds = cmd.list_commands(ctx)

        for cmd_name in cmds:
            cmd_complete(
                out,
                name + '_' + cmd_name,
                cmd.get_command(ctx, cmd_name),
                level + 1
            )

        cmpl['cmds'] = cmds

        out.write(render_cli('autocomplete-multi', **cmpl))
    else:
        # TODO: we might want to move that list of params somewhere else
        completable = [
            'command',
            'direction',
            'endpoint',
            'env',
            'host',
            'inventory',
            'inventory_name',
            'job',
            'limit',
            'organization_name',
            'platform',
            'project',
            'server',
        ]
        if len(params) == 1 and params[0] in completable:
            cmpl['param'] = params[0]
        elif len(params) > 1:
            cmpl['params'] = [el for el in params if el in completable]

        out.write(render_cli('autocomplete-single', **cmpl))

    if level == 1:
        out.write('complete -F _{0}_completion {0}\n'.format(name))
项目:treadmill    作者:Morgan-Stanley    | 项目源码 | 文件源码
def make_manage_multi_command(module_name, **click_args):
    """Make a Click multicommand from all submodules of the module."""

    old_multi = cli.make_multi_command(module_name, **click_args)
    new_multi = cli.make_commands(module_name, **click_args)

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

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

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

        def list_commands(self, ctx):
            old_commands = set(self.old_multi.list_commands(ctx))
            new_commands = set(self.new_multi.list_commands(ctx))
            return sorted(old_commands | new_commands)

        def get_command(self, ctx, name):
            try:
                return self.new_multi.get_command(ctx, name)
            except click.UsageError:
                pass
            return self.old_multi.get_command(ctx, name)

        def format_commands(self, ctx, formatter):
            rows = []
            for subcommand in self.list_commands(ctx):
                entry_points = list(pkg_resources.iter_entry_points(
                    module_name, subcommand))
                # Try get the help with importlib if entry_point not found
                if len(entry_points) == 0:
                    cmd = self.old_multi.get_command(ctx, subcommand)
                    if cmd is None:
                        continue
                    rows.append((subcommand, cmd.short_help or ''))
                else:
                    dist = entry_points[0].dist
                    if dist.has_metadata('cli_help'):
                        help_text = dist.get_metadata('cli_help')
                    else:
                        help_text = ''
                    rows.append((subcommand, help_text))

            if rows:
                with formatter.section('Commands'):
                    formatter.write_dl(rows)

    return MCommand