argparse: some mutually exclusive arguments in required group

邮差的信 提交于 2019-12-05 12:24:49

问题


I have a set of arguments that can logically be separated in 2 groups:

  • Actions: A1, A2, A3, etc.
  • Informations: I1, I2, I3, etc.

At least one of these arguments is required for the program to start, but "information" args can be used with "action" args. So

  • At least one in Actions or Informations is required
  • All Actions are mutually exclusive

I can't find how to do it using argparse. I know about add_mutually_exclusive_group and its required argument, but I can't use it on "Actions" because it's not actually required. Of course, I could add a condition after argparse to manually check my rules, but it seems like an hack. Can argparse do this?

Edit: Sorry, here are some examples.

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

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

回答1:


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.

actions = {"a1", "a2", "a3"}
informations = {"i1", "i2", "i3"}
p = argparse.ArgumentParser()
# Contents of actions and informations contrived
# to make the example short. You may need a series
# of calls to add_argument to define the options and
# constants properly
for ai in actions + informations:
    p.add_argument("--" + ai, action='append_const', const=ai, dest=infoactions)

args = p.parse_args()
if not args.infoactions:
    p.error("At least one action or information required")
elif len(actions.intersection(args.infoactions)) > 1:
    p.error("At most one action allowed")



回答2:


Im i missing something or do you just want:

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()

output:

$ 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 dont really suggest this "unlimited" -I# approach.. but here is an example of it.




回答3:


mutually_exclusive_group is a simple xor logic test. You could define 2 separate groups, but it does not provide any means of working across/between the groups.

I have worked on a patch to allow more complex logic and nested groups. The testing logic isn't that bad, but designing a good user interface is tricky, as is creating a meaningful usage line. So that enhancement probably will never see production.

Testing arguments after parsing is perfectly good. It only becomes tricky if you can't distinguish between attributes with default values and ones the usage gave you - so the default default None is best. argparse is primarily a parser, figuring out what the user wants. Whether they want something legit (beyond the simplest cases) is a different issue.



来源:https://stackoverflow.com/questions/35369448/argparse-some-mutually-exclusive-arguments-in-required-group

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!