argparse 和互斥组,每个组都有自己需要的设置
argparse and mutually exclusive groups, each with their own required setting
我有一个程序需要有一个选项来测试服务器 ID 列表 或 对服务器发出命令。这意味着,如果我发出 --test
,则不需要其他任何东西。它针对每台服务器运行全部测试并打印结果。
但是,如果我没有指定 --test
,那么它应该需要一些选项,例如 --id
和 --command
。
但是,我不确定 argparse
是否可以处理互斥组中的必需选项。代码(为简单起见进行了修改)如下。我已经修改了选项,所以如果您指定 -a
,那么您应该可以开始了,不需要其他选项。
import argparse
parser = argparse.ArgumentParser()
test_or_not = parser.add_mutually_exclusive_group(required=True)
test_or_not.add_argument('-a', action='store_true')
or_not = test_or_not.add_argument_group()
target = or_not.add_mutually_exclusive_group(required=True)
target.add_argument('-b',action="store_true")
target.add_argument('-c',action="store_true")
target.add_argument('-d',action="store_true")
target.add_argument('-e',action="store_true")
group = or_not.add_mutually_exclusive_group(required=True)
group.add_argument('-f',action="store_true")
group.add_argument('-g',action="store_true")
or_not.add_argument('-i',action="store_true")
or_not.add_argument('-j',action="store_true")
or_not.add_argument('-k',action="store_true")
or_not.add_argument('-l',action="store_true")
args = parser.parse_args()
产生错误是因为 argparse
仍然需要单独的选项,即使它们在一个互斥的组中。有没有办法 argparse
可以容纳这组选项,或者我是否需要在 argparse
之外添加一些编程?
$ python3 ~/tmp/groups.py -a
usage: groups.py [-h] -a (-b | -c | -d | -e) (-f | -g) [-i] [-j] [-k] [-l]
groups.py: error: one of the arguments -b -c -d -e is required
编辑:我可以添加一个完全在 argparse
之外工作的新选项,如下所示,但如果可能的话,我想将它的结构保持在 argparse
内。
import argparse
import sys
if '--test' in sys.argv:
go_do_testing()
sys.exit(0)
parser = argparse.ArgumentParser()
<snip>
正如评论中所建议的那样,如果您希望 test
和 run
逻辑相互排斥,那么要走的路就是使用子解析器。以下是该想法的说明:
#!/usr/bin/env python3
"""
Script to test or run commands on given servers.
./the_script.py test # To test all servers
./the_script.py run --id 127.0.0.1 --command "echo hello world"
"""
from argparse import ArgumentParser, RawDescriptionHelpFormatter as RDHF
def test_servers(servers):
"""
Given a list of servers, let's test them!
"""
for server in servers:
print('Just tested server {s}'.format(s=server))
def do_actual_work(server_id, command):
"""
Given a server ID and a command, let's run the command on that server!
"""
print('Connected to server {s}'.format(s=server_id))
print('Ran command {c} successfully'.format(c=command))
if __name__ == '__main__':
parser = ArgumentParser(description=__doc__, formatter_class=RDHF)
subs = parser.add_subparsers()
subs.required = True
subs.dest = 'run or test'
test_parser = subs.add_parser('test', help='Test all servers')
test_parser.set_defaults(func=test_servers)
run_parser = subs.add_parser('run', help='Run a command on the given server')
run_parser.add_argument('-i', '--id',
help='The ID of the server to connect to and run commands',
required=True)
run_parser.add_argument('-c', '--command',
help='The command to run',
required=True)
run_parser.set_defaults(func=do_actual_work)
args = parser.parse_args()
if args.func.__name__ == 'test_servers':
all_servers = ['127.0.0.1', '127.0.0.2']
test_servers(all_servers)
else:
do_actual_work(args.id, args.command)
该脚本设置了相互排斥和必需的子解析器 test
和 run
。对于 test
子解析器,不需要其他任何东西。但是,对于 run
子解析器,--id
和 --command
都是必需的。这些子解析器中的每一个都与其指定的目标函数相关联。为简单起见,我将 test_parser
绑定到 test_servers
;而 run_parser
与 do_actual_work
.
关联
此外,您应该能够按如下方式调用脚本以 运行 所有测试:
./the_script.py test
要运行特定服务器上的特定命令,您调用脚本如下:
./the_script.py run --id 127 --command "echo hello world"
希望这有用。
我有一个程序需要有一个选项来测试服务器 ID 列表 或 对服务器发出命令。这意味着,如果我发出 --test
,则不需要其他任何东西。它针对每台服务器运行全部测试并打印结果。
但是,如果我没有指定 --test
,那么它应该需要一些选项,例如 --id
和 --command
。
但是,我不确定 argparse
是否可以处理互斥组中的必需选项。代码(为简单起见进行了修改)如下。我已经修改了选项,所以如果您指定 -a
,那么您应该可以开始了,不需要其他选项。
import argparse
parser = argparse.ArgumentParser()
test_or_not = parser.add_mutually_exclusive_group(required=True)
test_or_not.add_argument('-a', action='store_true')
or_not = test_or_not.add_argument_group()
target = or_not.add_mutually_exclusive_group(required=True)
target.add_argument('-b',action="store_true")
target.add_argument('-c',action="store_true")
target.add_argument('-d',action="store_true")
target.add_argument('-e',action="store_true")
group = or_not.add_mutually_exclusive_group(required=True)
group.add_argument('-f',action="store_true")
group.add_argument('-g',action="store_true")
or_not.add_argument('-i',action="store_true")
or_not.add_argument('-j',action="store_true")
or_not.add_argument('-k',action="store_true")
or_not.add_argument('-l',action="store_true")
args = parser.parse_args()
产生错误是因为 argparse
仍然需要单独的选项,即使它们在一个互斥的组中。有没有办法 argparse
可以容纳这组选项,或者我是否需要在 argparse
之外添加一些编程?
$ python3 ~/tmp/groups.py -a
usage: groups.py [-h] -a (-b | -c | -d | -e) (-f | -g) [-i] [-j] [-k] [-l]
groups.py: error: one of the arguments -b -c -d -e is required
编辑:我可以添加一个完全在 argparse
之外工作的新选项,如下所示,但如果可能的话,我想将它的结构保持在 argparse
内。
import argparse
import sys
if '--test' in sys.argv:
go_do_testing()
sys.exit(0)
parser = argparse.ArgumentParser()
<snip>
正如评论中所建议的那样,如果您希望 test
和 run
逻辑相互排斥,那么要走的路就是使用子解析器。以下是该想法的说明:
#!/usr/bin/env python3
"""
Script to test or run commands on given servers.
./the_script.py test # To test all servers
./the_script.py run --id 127.0.0.1 --command "echo hello world"
"""
from argparse import ArgumentParser, RawDescriptionHelpFormatter as RDHF
def test_servers(servers):
"""
Given a list of servers, let's test them!
"""
for server in servers:
print('Just tested server {s}'.format(s=server))
def do_actual_work(server_id, command):
"""
Given a server ID and a command, let's run the command on that server!
"""
print('Connected to server {s}'.format(s=server_id))
print('Ran command {c} successfully'.format(c=command))
if __name__ == '__main__':
parser = ArgumentParser(description=__doc__, formatter_class=RDHF)
subs = parser.add_subparsers()
subs.required = True
subs.dest = 'run or test'
test_parser = subs.add_parser('test', help='Test all servers')
test_parser.set_defaults(func=test_servers)
run_parser = subs.add_parser('run', help='Run a command on the given server')
run_parser.add_argument('-i', '--id',
help='The ID of the server to connect to and run commands',
required=True)
run_parser.add_argument('-c', '--command',
help='The command to run',
required=True)
run_parser.set_defaults(func=do_actual_work)
args = parser.parse_args()
if args.func.__name__ == 'test_servers':
all_servers = ['127.0.0.1', '127.0.0.2']
test_servers(all_servers)
else:
do_actual_work(args.id, args.command)
该脚本设置了相互排斥和必需的子解析器 test
和 run
。对于 test
子解析器,不需要其他任何东西。但是,对于 run
子解析器,--id
和 --command
都是必需的。这些子解析器中的每一个都与其指定的目标函数相关联。为简单起见,我将 test_parser
绑定到 test_servers
;而 run_parser
与 do_actual_work
.
此外,您应该能够按如下方式调用脚本以 运行 所有测试:
./the_script.py test
要运行特定服务器上的特定命令,您调用脚本如下:
./the_script.py run --id 127 --command "echo hello world"
希望这有用。