我正在尝试使用Python库Click,但很难找到一个实例。我定义了两个组,其中一个组(group2
)用于处理这组命令的公共参数。我想要实现的是这些公共参数由组函数(group2
)处理并分配给上下文变量,因此它们可以被实际命令使用。
一个用例是许多需要用户名和密码的命令,而另一些则不需要(甚至没有选择)。
这是代码
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时的结果:
$ python cli-test.py command2 --optparam=123
> Error: no such option: --optparam`
这个例子有什么问题。我试图密切关注文档,但opt-param
似乎没有得到认可。
答案 0 :(得分:2)
所需方案的基本问题是click.CommandCollection
不会调用组功能。它直接跳到命令。此外,还希望通过装饰器将选项应用于组,但是具有由命令解析的选项。那就是:
> my_prog my_command --group-option
而不是:
> my_prog --group-option my_command
此click.Group
派生类挂钩命令的命令调用,以拦截组参数,并将它们传递给group命令。
Group.add_command
中,将参数添加到命令Group.add_command
中,覆盖command.invoke
command.invoke
中,从组中插入特殊参数并将其放入ctx.obj
并从params
中删除command.invoke
中,调用group命令,然后调用命令本身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
答案 1 :(得分:0)
这不是我要找的答案,而是迈向它的一步。基本上引入了一种新的组(@IBAction func sortWithName(_ sender: UIButton) {
items = allItems.sorted { $0.place < $1.place }
self.tableView.reloadData()
}
@IBAction func sortWithStatus(_ sender: UIButton) {
items = allItems.sorted { $0.status < $1.status }
self.tableView.reloadData()
}
@IBAction func sortWithStatusCount(_ sender: UIButton) {
//Filter your array first
items = allItems.filter { $0.stationsCount != "no data" }
//stationsCount is looks like number so sort it using compare with numeric option
items.sort { $0.stationsCount.compare($1.stationsCount, options: .numeric) == .orderedAscending }
self.tableView.reloadData()
}
),添加到组中的选项现在被添加到命令中。
GroupExt
这不是我想要的。理想情况下,$ python cli-test.py command2 --optparam=12
cli
command2 12
import click
class GroupExt(click.Group):
def add_command(self, cmd, name=None):
click.Group.add_command(self, cmd, name=name)
for param in self.params:
cmd.params.append(param)
@click.group()
def group1():
pass
@group1.command()
@click.argument('argument1')
@click.option('--option1')
def command1(argument1, option1):
print 'In command2', argument1, option1
# Equivalent to @click.group() with special group
@click.command(cls=GroupExt)
@click.option('--optparam', default=None, type=str)
def group2():
print 'in group2'
@group2.command()
def command2(optparam):
print 'command2', optparam
@click.command(cls=click.CommandCollection, sources=[group1, group2])
def cli():
print 'cli'
if __name__ == '__main__':
cli(obj={})
将由optparam
处理,结果会放入上下文中,但目前已在group2
处理。也许有人知道如何扩展它。