单击命令中的可选参数
Optional argument in command with click
我正在尝试使用 Click 完成一些不太标准的 CLI 解析,它只能部分工作:
- 主 CLI 有多个子命令(在下面的示例中 'show' 和 'check')
- 这两个命令可能都有可选参数,但参数在它们之前而不是在它们之后
- 我决定在组中处理该参数 "above" 它并在上下文中传递值
样本:
import click
@click.group()
@click.argument('hostname', required=False)
@click.pass_context
def cli(ctx, hostname=None):
""""""
ctx.obj = hostname
click.echo("cli: hostname={}".format(hostname))
@cli.command()
@click.pass_obj
def check(hostname):
click.echo("check: hostname={}".format(hostname))
@cli.command()
@click.pass_obj
def show(hostname):
click.echo("check: hostname={}".format(hostname))
if __name__ == '__main__':
cli()
带有主机名的部分有效:
> pipenv run python cli.py localhost check
cli: hostname=localhost
check: hostname=localhost
> pipenv run python cli.py localhost show
cli: hostname=localhost
check: hostname=localhost
但是没有主机名的部分不是:
> pipenv run python cli.py show
Usage: cli.py [OPTIONS] [HOSTNAME] COMMAND [ARGS]...
Error: Missing command.
有人知道我应该开始研究的方向吗?
这可以通过覆盖 click.Group
参数解析器来完成,例如:
自定义Class:
class MyGroup(click.Group):
def parse_args(self, ctx, args):
if args[0] in self.commands:
if len(args) == 1 or args[1] not in self.commands:
args.insert(0, '')
super(MyGroup, self).parse_args(ctx, args)
使用自定义 Class:
然后要使用自定义组,将其作为 cls
参数传递给 group
装饰器,例如:
@click.group(cls=MyGroup)
@click.argument('hostname', required=False)
@click.pass_context
def cli(ctx, hostname=None):
....
怎么办?
之所以有效,是因为 click
是一个设计良好的 OO 框架。 @click.group()
装饰器通常实例化一个 click.Group
对象,但允许使用 cls
参数覆盖此行为。因此,在我们自己的 class 中继承 click.Group
并覆盖所需的方法是一件相对容易的事情。
在这种情况下,我们覆盖 click.Group.parse_args()
,如果第一个参数匹配命令而第二个参数不匹配,那么我们插入一个空字符串作为第一个参数。这会将所有内容放回解析器期望的位置。
我正在尝试使用 Click 完成一些不太标准的 CLI 解析,它只能部分工作:
- 主 CLI 有多个子命令(在下面的示例中 'show' 和 'check')
- 这两个命令可能都有可选参数,但参数在它们之前而不是在它们之后
- 我决定在组中处理该参数 "above" 它并在上下文中传递值
样本:
import click
@click.group()
@click.argument('hostname', required=False)
@click.pass_context
def cli(ctx, hostname=None):
""""""
ctx.obj = hostname
click.echo("cli: hostname={}".format(hostname))
@cli.command()
@click.pass_obj
def check(hostname):
click.echo("check: hostname={}".format(hostname))
@cli.command()
@click.pass_obj
def show(hostname):
click.echo("check: hostname={}".format(hostname))
if __name__ == '__main__':
cli()
带有主机名的部分有效:
> pipenv run python cli.py localhost check
cli: hostname=localhost
check: hostname=localhost
> pipenv run python cli.py localhost show
cli: hostname=localhost
check: hostname=localhost
但是没有主机名的部分不是:
> pipenv run python cli.py show
Usage: cli.py [OPTIONS] [HOSTNAME] COMMAND [ARGS]...
Error: Missing command.
有人知道我应该开始研究的方向吗?
这可以通过覆盖 click.Group
参数解析器来完成,例如:
自定义Class:
class MyGroup(click.Group):
def parse_args(self, ctx, args):
if args[0] in self.commands:
if len(args) == 1 or args[1] not in self.commands:
args.insert(0, '')
super(MyGroup, self).parse_args(ctx, args)
使用自定义 Class:
然后要使用自定义组,将其作为 cls
参数传递给 group
装饰器,例如:
@click.group(cls=MyGroup)
@click.argument('hostname', required=False)
@click.pass_context
def cli(ctx, hostname=None):
....
怎么办?
之所以有效,是因为 click
是一个设计良好的 OO 框架。 @click.group()
装饰器通常实例化一个 click.Group
对象,但允许使用 cls
参数覆盖此行为。因此,在我们自己的 class 中继承 click.Group
并覆盖所需的方法是一件相对容易的事情。
在这种情况下,我们覆盖 click.Group.parse_args()
,如果第一个参数匹配命令而第二个参数不匹配,那么我们插入一个空字符串作为第一个参数。这会将所有内容放回解析器期望的位置。