21

How do I set up argparse as follows:

if -2 is on the command line, no other arguments are required
if -2 is not on the command line, -3 and -4 arguments are required

For example,

-2 [good]
-3 a -4 b [good]
-3 a [not good, -4 required]
-2 -5 c [good]
-2 -3 a [good]

There are a number of similar questions here, but either they don't address this situation or I don't understand.

Python 2.7 if that matters.

2
  • 1
    Make a subparser keyed on -2 that replicates the other commands as optional. At the top level, link -3 and -4 together. Commented Aug 2, 2013 at 21:01
  • Using subparser commands that begin with - can be tricky. -2 may work, but -t or --two wouldn't because they look like optionals. But if -3 is defined as an argument, then -2 no longer works as a subparser command (or a choice). Commented Aug 3, 2013 at 4:34

3 Answers 3

25

A subparser (as suggested in comments) might work.

Another alternative (since mutually_exclusive_group can't quite do this) is just to code it manually, as it were:

import argparse

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('-2', dest='two', action='store_true')
    parser.add_argument('-3', dest='three')
    parser.add_argument('-4', dest='four')
    parser.add_argument('-5', dest='five')

    args = parser.parse_args()

    if not args.two:
        if args.three is None or args.four is None:
            parser.error('without -2, *both* -3 <a> *and* -4 <b> are required')

    print args
    return 0

Adding a little driver to this:

import sys
sys.exit(main())

and run with your examples, it seems to do the right thing; here are two runs:

$ python mxgroup.py -2; echo $?
Namespace(five=None, four=None, three=None, two=True)
0
$ python mxgroup.py -3 a; echo $?
usage: mxgroup.py [-h] [-2] [-3 THREE] [-4 FOUR] [-5 FIVE]
mxgroup.py: error: without -2, *both* -3 <a> *and* -4 <b> are required
2
$ 
Sign up to request clarification or add additional context in comments.

4 Comments

In the absence of better alternatives, doing it manually does seem the best course
In stackoverflow.com/questions/17917265/… I suggest a two step parsing. First use parse_known_args to check for the -2 flag, and if that is missing, use another parser to look for -3 and -4.
I do not suppose there is a way to affect what --help will print other than setting help for each argument ...
@Leonid: does not seem to be. For similar things (never quite this) I've just added explanations in help epilogue.
3

I think it is pretty hard to achieve that (including a nice help message) while only using the standard argparse functions. You can however easily test it yourself after parsing the arguments. You can describe the extra requirements in the epilogue or so. Note that it is unusual to use numbers as options, I had to use dest='two', since args.2 is not valid syntax.

#!/usr/bin/env python

import argparse

parser = argparse.ArgumentParser(
   description='bla bla',
   epilog='Note: arguments -3 and -4 are required when -2 is missing')

parser.add_argument('-2', dest='two', action='store_true')
parser.add_argument('-3', dest='three')
parser.add_argument('-4', dest='four')
parser.add_argument('-5', dest='five')

args = parser.parse_args()

if not args.two and (args.three is None or args.four is None):
    parser.error('arguments -3 and -4 are required when -2 is missing')

print 'Good:', args

With these results:

[~]: ./test.py -h
usage: test.py [-h] [-2] [-3 THREE] [-4 FOUR] [-5 FIVE]

bla bla

optional arguments:
  -h, --help  show this help message and exit
  -2
  -3 THREE
  -4 FOUR
  -5 FIVE

Note: arguments -3 and -4 are required when -2 is missing

[~]: ./test.py -2
Good: Namespace(five=None, four=None, three=None, two=True)
[~]: ./test.py -3 a -4 b
Good: Namespace(five=None, four='b', three='a', two=False)
[~]: ./test.py -3 a
usage: test.py [-h] [-2] [-3 THREE] [-4 FOUR] [-5 FIVE]
test.py: error: arguments -3 and -4 are required when -2 is missing
[~]: ./test.py -2 -5 c
Good: Namespace(five='c', four=None, three=None, two=True)
[~]: ./test.py -2 -3 a
Good: Namespace(five=None, four=None, three='a', two=True)

1 Comment

While args.2 does not work, getattr(args,'2') does. Arguments like -2 are allowed, but add unnecessary complications.
0

You can define parameter as optional but then you can check it later and raise an exception as below;

import argparse

TYPES = ["once", "weekly"]

DAYS = ["monday", "tuesday", "wednesday",
              "thursday", "friday", "saturday", "sunday"]

def take_arg():
    ap = argparse.ArgumentParser()
    ap.add_argument("-t", "--type", required=True,
                    help="select the type {}".format(TYPES))
    ap.add_argument("-d", "--day", required=False, help="write a day {}".format(DAYS))
    arg = ap.parse_args()
    if arg.type == "weekly":
        if arg.day not in DAYS:
            raise Exception("DayParamNotExist")
    return arg

def main():
    ap_res=take_arg()
    print(ap_res)

if __name__ == '__main__':
    main()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.