5

Here is my code portion:

parser = argparse.ArgumentParser()
parser.add_argument('-a', action='store', dest='xxx', default = 'ABC')
parser.add_argument('-b', action='store', dest='yyy')
parser.add_argument('-c', action='store', dest='zzz')
args = parser.parse_args()

I want the code to work like this:

If b and c are given, do command2. Otherwise, do command1

if -a argument is given, then adding -b or -c throws an error

I tried this way:

if args.xxx and (args.yyy or args.zzz):
   parser.print_help()
   sys.exit()

But it didn't worked, because '-a' always has a deafult value and i can't change it. How can i fix it?

Vadmeggy
  • 123
  • 7
  • 1
    remove the default value for `a` – behzad.nouri Jul 30 '14 at 11:01
  • I need the default value :( – Vadmeggy Jul 30 '14 at 11:02
  • If `-a` is the set as the default do you want `-b` and `-c`? – Noelkd Jul 30 '14 at 11:08
  • No, it doesen't matter. I want to make a switch. If a is given(or not), then do command1 if b and c is given, then do command2 – Vadmeggy Jul 30 '14 at 11:12
  • 1
    You can use a mutually exclusive group for `a` or `b and c`. https://docs.python.org/2/howto/argparse.html#conflicting-options But not sure how you would declare `b` and `c` not exclusive. – toine Jul 30 '14 at 11:12
  • You question is confusing: "If a is given(or not), then do command1 if b and c is given, then do command2". One possible interpretation: "Always do command1. If b and c are given, also do command2". Another possible interpretation: "If b and c are given, do command2. Otherwise, do command1." You should edit your question to clarify. – FMc Jul 30 '14 at 11:30
  • this is probably a duplicate of: http://stackoverflow.com/questions/17909294/python-argparse-mutual-exclusive-group – toine Jul 30 '14 at 11:36

2 Answers2

3

Here's one way to do it:

# If option xxx is not the default, yyy and zzz should not be present.
if args.xxx != 'ABC' and (args.yyy or args.zzz):
   # Print help, exit.

# Options yyy and zzz should both be either present or None.
if (args.yyy is None) != (args.zzz is None):
   # Print help, exit.

# Earn our pay.
if args.yyy is None:
    command2()
else:
    command1()

You might also consider a usage pattern based on subcommands, as noted in the comment by user toine.

Community
  • 1
  • 1
FMc
  • 41,963
  • 13
  • 79
  • 132
  • That's exactly what i wanted. Thank you :) / I tried subcommands, but it made my script more difficult to use. – Vadmeggy Jul 30 '14 at 13:30
2

I would use:

parser = argparse.ArgumentParser()
parser.add_argument('-a', dest='xxx')
parser.add_argument('-b', dest='yyy')
parser.add_argument('-c', dest='zzz')
args = parser.parse_args()

if args.xxx is None:
    args.xxx = 'ABC'
else:
    if args.zzz is not None or args.yyy is not None:
        parser.error('cannot use "b" or "c" with "a"')
if args.zzz is not None and args.yyy is not None:
     command2()
else:
     command1()

Testing for None is the surest way of testing whether the argument was given or not (though the simpler truth test is nearly as good). Internally parse_args keeps a list of seen_actions, but that isn't available to the user. In http://bugs.python.org/issue11588 there's a proposal to provide a testing hook that would have access to this list.

hpaulj
  • 221,503
  • 14
  • 230
  • 353