argparse:必需组

时间:2016-02-12 18:11:32

标签: python argparse

我有一组参数可以在逻辑上分为两组:

  • 操作:A1A2A3
  • 信息:I1I2I3

程序启动时至少需要其中一个参数,但“信息”参数可以与“动作”参数一起使用。所以

  • 至少需要一项“行动或信息”
  • 所有操作都是互斥的

我找不到如何使用argparse来做到这一点。我知道add_mutually_exclusive_group及其required参数,但我不能在“动作”上使用它,因为它实际上并不是必需的。当然,我可以在argparse之后添加一个条件来手动检查我的规则,但它看起来像是一个黑客。 argparse可以这样做吗?

编辑:对不起,这里有一些例子。

# Should pass
--A1
--I1
--A1 --I2
--A2 --I1 --I2

# Shouldn't pass
--A1 --A2
--A1 --A2 --I1

3 个答案:

答案 0 :(得分:4)

There's nothing hacky about verifying arguments after they've been parsed. Just collect them all in a single set, then confirm that it is not empty and contains at most one action.

[02/12/2016 19:48:35 > 686340: SYS INFO] Detected WebJob file/s were updated, refreshing WebJob
[02/12/2016 19:48:35 > 686340: SYS INFO] Status changed to Stopping
[02/12/2016 19:48:35 > 686340: SYS INFO] Status changed to Stopped
[02/12/2016 19:48:35 > 686340: SYS INFO] Status changed to Starting
[02/12/2016 19:48:35 > 686340: SYS INFO] Run script 'Timbo.Azure.Worker.exe' with script host - 'WindowsScriptHost'
[02/12/2016 19:48:35 > 686340: SYS INFO] Status changed to Running
[02/12/2016 19:48:35 > 686340: SYS ERR ] Job failed due to exit code -2146232576
[02/12/2016 19:48:35 > 686340: SYS INFO] Process went down, waiting for 60 seconds
[02/12/2016 19:48:35 > 686340: SYS INFO] Status changed to PendingRestart
[02/12/2016 19:49:36 > 686340: SYS INFO] Run script 'Timbo.Azure.Worker.exe' with script host - 'WindowsScriptHost'
[02/12/2016 19:49:36 > 686340: SYS INFO] Status changed to Running
[02/12/2016 19:49:36 > 686340: SYS ERR ] Job failed due to exit code -2146232576
[02/12/2016 19:49:36 > 686340: SYS INFO] Process went down, waiting for 60 seconds
[02/12/2016 19:49:36 > 686340: SYS INFO] Status changed to PendingRestart

答案 1 :(得分:2)

我错过了什么,或者你只是想要:

import argparse
import os

def main():
    parser = argparse.ArgumentParser()
    actions = parser.add_mutually_exclusive_group()
    actions.add_argument("-A1", action="store_true")
    actions.add_argument("-A2", action="store_true")
    actions.add_argument("-A3", action="store_true")
    low = int(os.environ.get('LOWER_BOUNDS', 0))
    high = int(os.environ.get('UPPER_BOUNDS', 3)) + 1
    infos = parser.add_argument_group()
    for x in range(low, high):
        infos.add_argument("-I" + str(x), action="store_true")

    args = parser.parse_args()
    if not any(vars(args).values()):
        parser.error('No arguments provided.')
    print args

if __name__ == '__main__':
    main()

输出:

$ python test.py 
usage: test.py [-h] [-A1 | -A2 | -A3] [-I0] [-I1] [-I2] [-I3]
test.py: error: No arguments provided.
$ python test.py -A1
Namespace(A1=True, A2=False, A3=False, I1=False, I2=False, I3=False)
$ python test.py -A1 -A2
usage: test.py [-h] [-A1 | -A2 | -A3] [-I1] [-I2] [-I3]
test.py: error: argument -A2: not allowed with argument -A1
$ python test.py -A1 -I1
Namespace(A1=True, A2=False, A3=False, I1=True, I2=False, I3=False)
$ python test.py -A1 -I1 -I2
Namespace(A1=True, A2=False, A3=False, I1=True, I2=True, I3=False)
$ python test.py -A1 -I1 -I2 -I3
Namespace(A1=True, A2=False, A3=False, I1=True, I2=True, I3=True)
$ UPPER_BOUNDS=40 python test.py -A1 -I1 -I2 -I40
Namespace(A1=True, A2=False, A3=False, I0=False, I1=True, I10=False, I11=False, I12=False, I13=False, I14=False, I15=False, I16=False, I17=False, I18=False, I19=False, I2=True, I20=False, I21=False, I22=False, I23=False, I24=False, I25=False, I26=False, I27=False, I28=False, I29=False, I3=False, I30=False, I31=False, I32=False, I33=False, I34=False, I35=False, I36=False, I37=False, I38=False, I39=False, I4=False, I40=True, I5=False, I6=False, I7=False, I8=False, I9=False)

PS。我真的没有建议这种“无限制”-I#方法......但这里有一个例子。

答案 2 :(得分:1)

mutually_exclusive_group是一个简单的xor逻辑测试。您可以定义2个单独的组,但它不提供跨组/跨组之间的任何工作方式。

我已经开发了一个补丁,允许更复杂的逻辑和嵌套组。测试逻辑并不是那么糟糕,但设计一个好的用户界面很棘手,就像创建一个有意义的usage行一样。因此,增强可能永远不会出现生产。

解析后测试参数非常好。如果您无法区分具有默认值的属性和用户提供的属性,那么它变得棘手 - 因此默认的默认None是最佳的。 argparse主要是一个解析器,弄清楚用户想要什么。他们是否想要合法的东西(超出最简单的情况)是一个不同的问题。