您的要求存在固有的歧义,因为子命令名称可能与公共参数的有效值相同。
因此,需要某种消除歧义的方法。我在下面提出一种可能的解决方案。
当找到与子命令名称匹配的参数值时,建议的解决方案将搜索是否存在--help
。如果找到,则假定正在为子命令请求帮助,并将填充dummy-argument
自动地。
定制类:
import click
class PerCommandArgWantSubCmdHelp(click.Argument):
def handle_parse_result(self, ctx, opts, args):
# check to see if there is a --help on the command line
if any(arg in ctx.help_option_names for arg in args):
# if asking for help see if we are a subcommand name
for arg in opts.values():
if arg in ctx.command.commands:
# this matches a sub command name, and --help is
# present, let's assume the user wants help for the
# subcommand
args = [arg] + args
return super(PerCommandArgWantSubCmdHelp, self).handle_parse_result(
ctx, opts, args)
使用自定义类:
要使用自定义类,请传递cls
参数为@click.argument()
装饰器喜欢:
@click.argument("argument", cls=PerCommandArgWantSubCmdHelp)
这是如何运作的?
这是可行的,因为 click 是一个设计良好的 OO 框架。这@click.argument()
装饰器通常会实例化一个click.Argument
对象,但允许使用 cls 参数覆盖此行为。所以继承是一件比较容易的事情click.Argument
在我们自己的类中并重写所需的方法。
在这种情况下我们重写click.Argument.handle_parse_result()
并查找子命令名称的模式,后跟--help
。找到后,我们会修改参数列表以获取模式,单击需要以显示子命令帮助的方式解析此模式。
测试代码:
@click.group()
@click.argument("argument", cls=PerCommandArgWantSubCmdHelp)
@click.pass_context
def main(context, argument):
"""ARGUMENT is required for both subcommands"""
context.obj = {"argument": argument}
@click.command()
@click.option("--option-1", help="option for subcommand 1")
@click.pass_context
def subcommand1(context, option_1):
print("subcommand 1: %s %s" % (context.obj["argument"], option_1))
@click.command()
@click.option("--option-2", help="option for subcommand 2")
@click.pass_context
def subcommand2(context, option_2):
print("subcommand 2: %s %s" % (context.obj["argument"], option_2))
main.add_command(subcommand1)
main.add_command(subcommand2)
if __name__ == "__main__":
commands = (
'subcommand1 --help',
'subcommand2 --help',
'dummy-argument subcommand1 --help',
)
for cmd in commands:
try:
print('-----------')
print('> ' + cmd)
main(cmd.split())
except:
pass
检测结果:
-----------
> subcommand1 --help
Backend TkAgg is interactive backend. Turning interactive mode on.
Usage: test.py subcommand1 [OPTIONS]
Options:
--option-1 TEXT option for subcommand 1
--help Show this message and exit.
-----------
> subcommand2 --help
Usage: test.py subcommand2 [OPTIONS]
Options:
--option-2 TEXT option for subcommand 2
--help Show this message and exit.
-----------
> dummy-argument subcommand1 --help
Usage: test.py subcommand1 [OPTIONS]
Options:
--option-1 TEXT option for subcommand 1
--help Show this message and exit.