argparse 和互斥组,每个组都有自己所需的设置 [英] argparse and mutually exclusive groups, each with their own required setting

查看:31
本文介绍了argparse 和互斥组,每个组都有自己所需的设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序需要有一个选项来测试服务器 ID 列表对服务器发出命令.这意味着,如果我发出 --test,则不需要其他任何内容.它对每台服务器运行所有测试并打印结果.

I have a program that needs to have an option to either test a list of server ids OR issue a command against the server. This means, if I issue --test, then nothing else is required. It runs the whole gamut of tests against each server and prints the results.

但是,如果我不指定 --test,那么它应该需要一些选项,例如 --id--command>.

However, if I do NOT specify --test, then it should require a few options such as --id and --command.

但是,我不确定 argparse 是否可以处理互斥组中所需的选项.代码(为简单起见修改)如下.我已经修改了选项,所以如果你指定 -a,那么你应该很高兴并且不需要其他选项.

However, I'm not sure that argparse can handle required options within mutually exclusive groups. Code (modified for simplicity) is as follows. I've modified the options so if you specify -a, then you SHOULD be good to go and no other options be necessary.

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 之外添加一些编程?

The resulting error is produced because argparse is still requiring individual options even though they're in a mutually exclusive group. Is there a way that argparse can accommodate this set of options or do I need to add a bit of programming outside of 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 中.

I could add a new option that entirely works OUTSIDE of argparse as below, but I'd like to keep it structured within argparse if at all possible.

import argparse
import sys

if '--test' in sys.argv:
    go_do_testing()
    sys.exit(0)

parser = argparse.ArgumentParser()
<snip>

推荐答案

如评论中所建议的,如果您希望 testrun 互斥,要走的路逻辑,将使用子解析器.以下是该想法的说明:

As suggested in the comments, the way to go, if you wish to have mutually exclusive test and run logics, would be to use subparsers. The following is an illustration of the idea:

#!/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)

脚本设置了互斥和必需的子解析器testrun.对于 test 子解析器,不需要其他任何东西.但是,对于 run 子解析器,--id--command 都是必需的.这些子解析器中的每一个都与其指定的目标函数相关联.为简单起见,我将 test_parser 绑定到 test_servers;而 run_parserdo_actual_work 相关联.

The script sets up both mutually exclusive and required subparsers test and run. For the test subparser, nothing else is required. However, for the run subparser, both --id and --command would be required. Each of these subparsers is associated with its designated target function. For simplicity I had the test_parser tied to test_servers; while run_parser is associated with do_actual_work.

此外,您应该能够按如下方式调用脚本来运行所有测试:

Further, you should be able to call the script as follows to run all tests:

./the_script.py test

要在特定服务器上运行特定命令,请按如下方式调用脚本:

To run a specific command on a specific server, you call the script as follows:

./the_script.py run --id 127 --command "echo hello world"

我希望这证明有用.

这篇关于argparse 和互斥组,每个组都有自己所需的设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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