如何使用argparse处理CLI子命令

时间:2014-10-06 13:05:52

标签: python argparse subcommand subparsers

我需要实现一个命令行界面,程序接受子命令。

例如,如果程序名为“foo”,则CLI看起来像

foo cmd1 <cmd1-options>
foo cmd2
foo cmd3 <cmd3-options>

cmd1cmd3必须至少与其中一个选项一起使用,并且三个cmd*参数始终是独占的。

我试图在argparse中使用subparser,但暂时没有成功。问题在于cmd2,它没有参数:

如果我尝试添加不带参数的subparser条目,parse_args返回的命名空间将不包含任何告知我已选择此选项的信息(请参阅下面的示例)。 如果我尝试将cmd2作为参数添加到parser(而不是subparser),那么argparse将期望任何subparsers参数后跟cmd2参数。

使用argparse有一种简单的方法可以实现这一目标吗?用例应该很常见......

以下是我到目前为止所尝试的更接近我需要的内容:

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='Functions')
parser_1 = subparsers.add_parser('cmd1', help='...')
parser_1.add_argument('cmd1_option1', type=str, help='...')

parser_2 = subparsers.add_parser(cmd2, help='...')

parser_3 = subparsers.add_parser('cmd3', help='...')
parser_3.add_argument('cmd3_options', type=int, help='...')

args = parser.parse_args()

2 个答案:

答案 0 :(得分:6)

首先,从不插入命名空间中的子分析符。在您尝试以下列方式运行脚本的示例中:

$python3 test_args.py cmd1 1
Namespace(cmd1_option1='1')

其中test_args.py包含您提供的代码(开头为import argparse,结尾为print(args)

请注意,cmd1仅提及其论点。 这是设计

正如评论中所指出的,您可以添加将dest参数传递给add_subparsers电话的信息。

处理这些情况的常用方法是使用subparsers的set_defaults方法:

import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='Functions')
parser_1 = subparsers.add_parser('cmd1', help='...')
parser_1.add_argument('cmd1_option1', type=str, help='...')
parser_1.set_defaults(parser1=True)

parser_2 = subparsers.add_parser('cmd2', help='...')
parser_2.set_defaults(parser2=True)

parser_3 = subparsers.add_parser('cmd3', help='...')
parser_3.add_argument('cmd3_options', type=int, help='...')
parser_3.set_defaults(parser_3=True)

args = parser.parse_args()
print(args)

结果是:

$python3 test_args.py cmd1 1
Namespace(cmd1_option1='1', parser1=True)
$python3 test_args.py cmd2
Namespace(parser2=True)

通常,不同的subparser大多数时候会以完全不同的方式处理参数。通常的模式是使用不同的函数来运行不同的命令,并使用set_defaults来设置func属性。解析参数时,只需调用该callable:

subparsers = parser.add_subparsers()
parser_1 = subparsers.add_parser(...)
parser_1.set_default(func=do_command_one)

parser_k = subparsers.add_parser(...)
parser_k.set_default(func=do_command_k)

args = parser.parse_args()
if args.func:
    args.func(args)

答案 1 :(得分:0)

如果Namespace命令被赋予add_subparsers,则可以将subparser标识添加到主dest

来自文档:

  

但是,如果需要检查调用的子分析程序的名称,则add_subparsers()调用的dest关键字参数将起作用:

>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(dest='subparser_name')
>>> subparser1 = subparsers.add_parser('1')
>>> subparser1.add_argument('-x')
>>> subparser2 = subparsers.add_parser('2')
>>> subparser2.add_argument('y')
>>> parser.parse_args(['2', 'frobble'])
Namespace(subparser_name='2', y='frobble')

默认情况下,destargparse.SUPPRESS,这使subparsers不会将名称添加到namespace