是否可以在整个命令的末尾传递单击选项?

时间:2018-01-29 12:19:57

标签: python python-2.7 python-click

是否可以在click.option上设置click.group,但在整个命令的末尾传递选项?

@click.option(
    '-d', '--debug',
    help="change to debug mode")
@click.group()
def cli(ctx, **kwargs):
    """
    help message
    """

@click.command()
def version():
    """
    version
    """
    pass

所需的命令如下所示:

./cli.py version -d 

但这失败了:

  

错误:没有这样的选项:-d

2 个答案:

答案 0 :(得分:0)

click.option上设置click.group但在整个命令的末尾传递选项的一种方法是从click.Group继承,并自定义调用命令的代码

这个问题得到了部分回答here。从该问题我们将使用自定义类:GroupWithCommandOptions

自定义类:

import click

class GroupWithCommandOptions(click.Group):
    """ Allow application of options to group with multi command """

    def add_command(self, cmd, name=None):
        click.Group.add_command(self, cmd, name=name)

        # add the group parameters to the command
        for param in self.params:
            cmd.params.append(param)

        # hook the commands invoke with our own
        cmd.invoke = self.build_command_invoke(cmd.invoke)
        self.invoke_without_command = True

    def build_command_invoke(self, original_invoke):

        def command_invoke(ctx):
            """ insert invocation of group function """

            # separate the group parameters
            ctx.obj = dict(_params=dict())
            for param in self.params:
                name = param.name
                ctx.obj['_params'][name] = ctx.params[name]
                del ctx.params[name]

            # call the group function with its parameters
            params = ctx.params
            ctx.params = ctx.obj['_params']
            self.invoke(ctx)
            ctx.params = params

            # now call the original invoke (the command)
            original_invoke(ctx)

        return command_invoke

使用自定义类:

要使用自定义类,请将cls参数传递给@click.group() 装饰者喜欢:

@click.group(cls=GroupWithCommandOptions)

然后使用群组

创建click.CommandCollection
cli = click.CommandCollection(sources=[group1])

命令集很重要,因为我们需要控制何时调用组,以及 CommandCollection不会调用他们的小组,因此我们可以在适当的时候自行完成。

这是如何工作的?

这是有效的,因为click是一个设计良好的OO框架。该 @click.group()装饰器通常实例化一个 click.Group对象但允许此行为被覆盖 使用cls参数。所以这是一个相对的 很容易在我们自己的班级继承click.Group并过度使用所需的方法。

在这种情况下,我们过度click.Group.add_command()将组参数添加到命令中 然后猴子修补命令的invoke()方法,这样可以在命令调用之前调用组调用以允许 它处理在命令中指定的选项。

测试代码:

@click.group(cls=GroupWithCommandOptions)
@click.option('-d', '--debug', help="change to debug mode", is_flag=True)
def group1(**kwargs):
    """Our great program"""
    click.echo('debug: %s' % kwargs['debug'])


@group1.command()
@click.pass_context
def version(ctx):
    """Show the Version"""
    click.echo('show version here')


cli = click.CommandCollection(sources=[group1])


if __name__ == "__main__":
    commands = (
        'version -d',
        '-d version',
        'version',
        '--help',
        'version --help',
    )

    import sys, time
    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for cmd in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + cmd)
            time.sleep(0.1)
            cli(cmd.split())

        except BaseException as exc:
            if str(exc) != '0' and \
                    not isinstance(exc, (click.ClickException, SystemExit)):
                raise

测试结果:

Click Version: 6.7
Python Version: 3.6.2 (default, Jul 17 2017, 23:14:31)
[GCC 5.4.0 20160609]
-----------
> version -d
debug: True
show version here
-----------
> -d version
Error: no such option: -d
-----------
> version
debug: False
show version here
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  version  Show the Version
-----------
> version --help
Usage: test.py version [OPTIONS]

  Show the Version

Options:
  -d, --debug  change to debug mode
  --help       Show this message and exit.

答案 1 :(得分:-1)

使用点击实现此功能是不可能的,因为选项属于它的命令。所有命令都可用的选项应属于包含命令的组。

可以在此处找到实现这一目标的几个实现示例: https://github.com/pallets/click/issues/108