我需要实现一个命令行界面,程序接受子命令。
例如,如果程序名为“foo”,则CLI看起来像
foo cmd1 <cmd1-options>
foo cmd2
foo cmd3 <cmd3-options>
cmd1
和cmd3
必须至少与其中一个选项一起使用,并且三个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()
答案 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')
默认情况下,dest
为argparse.SUPPRESS
,这使subparsers
不会将名称添加到namespace
。