首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Python中,我如何看到--帮助其父母需要参数的子命令?

在Python中,我如何看到--帮助其父母需要参数的子命令?
EN

Stack Overflow用户
提问于 2017-11-22 14:43:44
回答 3查看 4.2K关注 0票数 8

我的程序使用点击进行命令行处理。它有一个主命令,它接受所需的参数。此命令有接受可选参数的子命令。不同的子命令采用不同的选项,但它们都需要来自父命令的相同参数。我希望命令行如下所示:

代码语言:javascript
复制
python myprogram.py argument-value subcommand1 --option-1=value

我可以像这样使用Click来写这个

代码语言:javascript
复制
import click

@click.group()
@click.argument("argument")
@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__":
    main()

最高级的帮助信息是我想要的。

代码语言:javascript
复制
python myprogram.py --help
Usage: myprogram.py [OPTIONS] ARGUMENT COMMAND [ARGS]...

  ARGUMENT is required for both subcommands

Options:
  --help  Show this message and exit.

Commands:
  subcommand1
  subcommand2

如果我传递所需的参数,我可以获得子命令的帮助。

代码语言:javascript
复制
python myprogram.py dummy-argument subcommand1 --help
Usage: myprogram.py subcommand1 [OPTIONS]

Options:
  --option-1 TEXT  option for subcommand 1
  --help           Show this message and exit.

但是,我希望获得子命令帮助,而不需要用户传递虚拟参数。我希望能够运行python myprogram.py subcommand1 --help并看到与上面相同的输出,但是我只是获得顶层的帮助文本。

代码语言:javascript
复制
python myprogram.py subcommand1 --help
Usage: myprogram.py [OPTIONS] ARGUMENT COMMAND [ARGS]...

  ARGUMENT is required for both subcommands

Options:
  --help  Show this message and exit.

Commands:
  subcommand1
  subcommand2

有没有办法得到我想要的行为?我意识到Click非常重视它的每个命令都是独立的,但这似乎是一个常见的场景。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-11-22 19:57:02

您的需求中存在固有的模糊性,因为子命令名可能与公共参数的有效值相同。

因此,需要某种方法来消除歧义。我在下面提出一个可能的解决办法。

当找到与子命令名匹配的参数值时,建议的解决方案将搜索是否存在--help。如果找到它,则假定正在为该子命令请求帮助,并将自动填充dummy-argument

定制类:

代码语言:javascript
复制
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()装饰器,如下所示:

代码语言:javascript
复制
@click.argument("argument", cls=PerCommandArgWantSubCmdHelp)

这是怎么回事?

这是因为click是一个设计良好的OO框架。@click.argument()装饰器通常实例化一个click.Argument对象,但允许使用cls参数对此行为进行重写。因此,在我们自己的类中继承click.Argument相对容易,而不是使用所需的方法。

在本例中,我们遍历click.Argument.handle_parse_result()并查找子命令名的模式,然后是--help。找到后,我们将修改参数列表,以获得模式单击需要解析的方式来显示子命令帮助。

测试代码:

代码语言:javascript
复制
@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

测试结果:

代码语言:javascript
复制
-----------
> 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.                
票数 3
EN

Stack Overflow用户

发布于 2018-08-06 13:32:43

另一种可能的方法是定义一个自定义装饰器,它添加公共参数/选项,并在每个子命令上使用这个装饰符。这样,在发出subcommand --help时,单击将不会请求参数/选项。

点击的GitHub问题295号中列出了一个可能的实现。示例代码显示了如何添加一个通用装饰器,它可以添加不同的-但共享的-选项。然而,它确实解决了OP的问题。

票数 1
EN

Stack Overflow用户

发布于 2021-03-02 19:40:16

我设法做到了

代码语言:javascript
复制
def create(config):
if config is None:
    click.echo('ERROR: Configuration File not found!')
    main(datalake(create(['--help'])))
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47437472

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档