使用Click将常用参数添加到组中 [英] Adding common parameters to groups with Click

查看:119
本文介绍了使用Click将常用参数添加到组中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Python库点击,但很难使示例工作.我定义了两组,其中一组(group2)用于处理该组命令的公共参数.我要实现的是那些通用参数由组函数(group2)处理并分配给上下文变量,以便它们可以由实际命令使用.

I am trying to use the Python library Click, but struggle to get an example working. I defined two groups, one of which (group2) is meant to handle common parameters for this group of commands. What I want to achieve is that those common parameters get processed by the group function (group2) and assigned to the context variable, so they can be used by the actual commands.

一个用例是许多需要用户名和密码的命令,而有些则不需要(甚至是可选的).

A use case would be a number of commands that require username and password, while some others don't (not even optionally).

这是代码

import click


@click.group()
@click.pass_context
def group1(ctx):
    pass


@click.group()
@click.option('--optparam', default=None, type=str)
@click.option('--optparam2', default=None, type=str)
@click.pass_context
def group2(ctx, optparam):
    print 'in group2', optparam
    ctx['foo'] = create_foo_by_processing_params(optparam, optparam2)


@group2.command()
@click.pass_context
def command2a(ctx):
    print 'command2a', ctx['foo']


@group2.command()
@click.option('--another-param', default=None, type=str)
@click.pass_context
def command2b(ctx, another_param):
    print 'command2b', ctx['foo'], another_param

# many more more commands here...
# @group2.command()
# def command2x():
# ...


@group1.command()
@click.argument('argument1')
@click.option('--option1')
def command1(argument1, option1):
    print 'In command2', argument1, option1

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


if __name__ == '__main__':
    cli(obj={})

这是使用command2时的结果:

And this is the result when using command2:

$ python cli-test.py command2 --optparam=123
> Error: no such option: --optparam`

此示例出了什么问题.我试图密切关注文档,但是opt-param似乎未被认可.

What's wrong with this example. I tried to follow the docs closely, but opt-param doesn't seem to be recognised.

推荐答案

所需方案的基本问题是click.CommandCollection不调用组函数.它直接跳到命令.另外,希望通过装饰器将选项应用到组,但是需要通过命令来解析选项.那就是:

The basic issue with the desired scheme is that click.CommandCollection does not call the group function. It skips directly to the command. In addition it is desired to apply options to the group via decorator, but have the options parsed by the command. That is:

> my_prog my_command --group-option

代替:

> my_prog --group-option my_command

如何?

click.Group派生类挂钩命令调用,以拦截命令并将组参数传递给group命令.

How?

This click.Group derived class hooks the command invocation for the commands to intercept the group parameters, and pass them to the group command.

  1. Group.add_command中,将参数添加到命令中
  2. Group.add_command中,覆盖command.invoke
  3. 在已覆盖的command.invoke中,将从组中插入的特殊args放入ctx.obj并将其从params中删除
  4. 在已覆盖的command.invoke中,先调用group命令,然后再调用命令本身
  1. In Group.add_command, add the params to the command
  2. In Group.add_command, override command.invoke
  3. In overridden command.invoke, take the special args inserted from the group and put them into ctx.obj and remove them from params
  4. In overridden command.invoke, invoke the group command, and then the command itself

代码:

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

测试代码:

@click.group()
@click.pass_context
def group1(ctx):
    pass

@group1.command()
@click.argument('argument1')
@click.option('--option1')
def command1(argument1, option1):
    click.echo('In command2 %s %s' % (argument1, option1))


@click.group(cls=GroupWithCommandOptions)
@click.option('--optparam', default=None, type=str)
@click.option('--optparam2', default=None, type=str)
@click.pass_context
def group2(ctx, optparam, optparam2):
    # create_foo_by_processing_params(optparam, optparam2)
    ctx.obj['foo'] = 'from group2 %s %s' % (optparam, optparam2)

@group2.command()
@click.pass_context
def command2a(ctx):
    click.echo('command2a foo:%s' % ctx.obj['foo'])

@group2.command()
@click.option('--another-param', default=None, type=str)
@click.pass_context
def command2b(ctx, another_param):
    click.echo('command2b %s %s' % (ctx['foo'], another_param))

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

if __name__ == '__main__':
    cli('command2a --optparam OP'.split())

结果:

command2a foo:from group2 OP None

这篇关于使用Click将常用参数添加到组中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆