微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

单击 - 如何在带有位置参数的命令下嵌套子命令?

如何解决单击 - 如何在带有位置参数的命令下嵌套子命令?

我正在将 open source project's CLI 从 argparse 转移到 click。目前该库允许以下CLI usage patterns

manim file.py Scene1 Scene2 -p -ql

但也适用于子命令(有些带有自己的子命令),如下所示:

manim plugins --list
manim cfg write --level cwd
... and more.

因此,manim 关键字既是访问子命令的一种方式,更重要的是,它是带有位置参数(python 文件)的命令本身。在 argparse 中,确定 manim 关键字后面的文本是子命令还是位置参数是读取 sys.argv[2] 并确定它是否与可用子命令之一匹配的问题,else 这是一个位置参数。结果是添加子命令和大量样板代码需要付出很多努力……因此转换为单击的动作;然而,这种特殊的使用模式似乎并不是在点击时开箱即用的。

换句话说,下面的代码

    @click.group()
    @click.argument('file')
    def main(file):
        print('main',file)
    
    @main.command()
    @click.option('--opt')
    def subcommand1(opt):
        print("sub1",opt)

提出两个问题:

  1. 需要满足 main 组的位置参数才能运行任何子命令(即 main file.py subcommand1 而不是 main subcommand1
  2. 它不会在没有子命令的情况下执行 Group + 参数(即 main file.py 在没有指定 subommand1 到 Group 的情况下是不可能的)。

经过进一步研究,我使用点击组参数 invoke_without_command

解决了第二个问题
    @click.group(invoke_without_command=True)
    @click.argument('file')
    def main(file):
        print('main',opt)

但我仍然面临第一点的问题——选择不使用位置参数而是调用子命令的一般能力。 Stephen Raunch 回答的这个 StackOverflow article 似乎相关;但是,它仅适用于帮助选项,而不适用于参数和选项的更一般用例。

如何允许子命令的任意嵌套,例如 Group,但仍然提供像 @click.command() 那样使用位置参数执行该 Group 的能力?如果这不是推荐的模式,您会推荐什么?

解决方法

在对该主题进行更多研究时,我遇到了这个 stackoverflow article,这导致了这个自定义组的创建:

import click
from click.decorators import pass_context

class SkipArg(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: 
                # This condition needs updating for multiple positional arguments
                args.insert(0,'')
        super(SkipArg,self).parse_args(ctx,args)

@click.group(cls=SkipArg,invoke_without_command=True)
@click.argument('file')
@pass_context
def main(ctx,file):
    print('main',file)

@main.command()
@click.option('--opt')
def subcommand1(opt):
    print("sub1",opt)

此代码符合使用 click 使命令具有嵌套更多子命令的位置参数的条件。在我将使用点击的情况下,必须针对多个位置参数更新 SkipArg 的逻辑,但作为演示就足够了。

它如何满足标准:

  1. main 组用作命令,因为它可以使用 invoke_without_command 执行。
  2. 执行 subcommand1 不需要位置参数,因为类 SkipArg 将 '' 插入到参数列表的前面。这是一种硬编码逻辑,当第零个参数与其中一个子命令匹配时,它会为 [FILE] 位置参数应用空填充文本。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。