具有通用选项的Python多命令CLI [英] Python multi-command CLI with common options

查看:158
本文介绍了具有通用选项的Python多命令CLI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的Python应用程序添加CLI. CLI应该允许一次运行多个命令.这些命令应具有通用选项和个人选项.

I am adding CLI for my Python application. The CLI should allow to run multiple commands in a time. The commands should have common options and personal options.

示例:

$ python mycliapp.py --common-option1 value1 --common-option2 value2 cmd1 --cmd1-option cmd2 --cmd2-option somevalue cmd3

该示例具有所有命令使用的两个常用选项,每个命令只能具有或不具有该命令使用的选项.

The example has two common options used by all commands and each command can have or not the option used by the command only.

我已经考虑过Python Click.它具有丰富的功能,但不允许(至少我没有找到)没有一些主要命令的情况下可以使用常用选项.

I have considered Python Click. It has rich functionality, but it does not allow (at least I didn't found) to use common options without some main command.

使用Click 时,上面的示例如下所示:

The above example will look as follows with Click:

$ python mycliapp.py maincmd --common-option1 value1 --common-option2 value2 cmd1 --cmd1-option cmd2 --cmd2-option somevalue cmd3

也被认为是Python Argparse.看起来它可以满足我的需要,并且我设法编写了一个代码,该代码可与常用选项和单个命令一起使用,但无法管理多个命令. 此页面 Python argparse-向多个子解析器添加参数有一个很好的例子,但似乎command2应该是command1的子命令.有点不同,因为我需要命令可以按任何顺序执行.

Also, considered Python Argparse. It looks that it can do what I need and I have managed to write a code, which works with common options and single command, but cannot manage to use multiple commands. This page Python argparse - Add argument to multiple subparsers has good example, but seems that command2 should be a sub-command of command1. It is a bit different since I need that the commands can be executed in any order.

推荐答案

单击绝对支持这种语法.一个简单的示例如下所示:

Click absolutely supports this sort of syntax. A simple example looks something like:

import click


@click.group(chain=True)
@click.option('--common-option1')
@click.option('--common-option2')
def main(common_option1, common_option2):
    pass


@main.command()
@click.option('--cmd1-option', is_flag=True)
def cmd1(cmd1_option):
    pass


@main.command()
@click.option('--cmd2-option')
def cmd2(cmd2_option):
    pass


@main.command()
def cmd3():
    pass


if __name__ == '__main__':
    main()

假设以上内容位于mycliapp.py中,我们将看到常见的帮助输出:

Assuming the above is in mycliapp.py, we see the common help output:

$ python example.py --help
Usage: example.py [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...

Options:
  --common-option1 TEXT
  --common-option2 TEXT
  --help                 Show this message and exit.

Commands:
  cmd1
  cmd2
  cmd3

对于cmd1:

$ python mycliapp.py cmd1 --help
Usage: mycliapp.py cmd1 [OPTIONS]

Options:
  --cmd1-option
  --help         Show this message and exit.

对于cmd2:

$ python mycliapp.py cmd2 --help
Usage: mycliapp.py cmd2 [OPTIONS]

Options:
  --cmd2-option TEXT
  --help              Show this message and exit.

等等.

有了这个,我们可以从您的问题中运行命令行:

With this we can run the command line from your question:

python mycliapp.py --common-option1 value1 --common-option2 value2 \
  cmd1 --cmd1-option \
  cmd2 --cmd2-option somevalue \
  cmd3


更新1

以下是使用建议的回调模型实现管道的示例在文档中:

Here's an example that implements pipelines using the callback model suggested in the documentation:

import click


@click.group(chain=True)
@click.option('--common-option1')
@click.option('--common-option2')
@click.pass_context
def main(ctx, common_option1, common_option2):
    ctx.obj = {
        'common_option1': common_option1,
        'common_option2': common_option2,
    }


@main.resultcallback()
def process_pipeline(processors, common_option1, common_option2):
    print('common_option1 is', common_option1)
    for func in processors:
        res = func()
        if not res:
            raise click.ClickException('Failed processing!')


@main.command()
@click.option('--cmd1-option', is_flag=True)
def cmd1(cmd1_option):
    def process():
        print('This is cmd1')
        return cmd1_option

    return process


@main.command()
@click.option('--cmd2-option')
def cmd2(cmd2_option):
    def process():
        print('This is cmd2')
        return cmd2_option != 'fail'

    return process


@main.command()
@click.pass_context
def cmd3(ctx):
    def process():
        print('This is cmd3 (common option 1 is: {common_option1}'.format(**ctx.obj))
        return True

    return process


if __name__ == '__main__':
    main()

每个命令都返回一个布尔值,指示该布尔值是否成功.失败的命令将中止管道处理.例如,这里cmd1失败,因此cmd2永远不会执行:

Each command returns a boolean indicating whether or not it was successful. A failed command will abort pipeline processing. For example, here cmd1 fails so cmd2 never executes:

$ python mycliapp.py cmd1 cmd2
This is cmd1
Error: Failed processing!

但是,如果我们使cmd1高兴,它就会起作用:

But if we make cmd1 happy, it works:

$ python mycliapp.py cmd1 --cmd1-option cmd2
This is cmd1
This is cmd2

类似地,对此进行比较:

And similarly, compare this:

$ python mycliapp.py cmd1 --cmd1-option cmd2 --cmd2-option fail cmd3
This is cmd1
This is cmd2
Error: Failed processing!

与此:

$ python mycliapp.py cmd1 --cmd1-option cmd2  cmd3
This is cmd1
This is cmd2
This is cmd3

当然,您不需要按顺序调用事物:

And of course you don't need to call things in order:

$ python mycliapp.py cmd2 cmd1 --cmd1-option
This is cmd2
This is cmd1

这篇关于具有通用选项的Python多命令CLI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆