Jay Wong Jay Wong - 1 month ago 11
Python Question

Python Argparse: how to make an argument required if and only if one flag is given?

I am wondering how can I make one argument required when one flag is given, and optional when that flag is not given?

import argparse


parser = argparse.ArgumentParser()

parser.add_argument('-c', '--convert', action = 'store_true')
parser.add_argument('-l', '--lookup', action = 'store_true')
parser.add_argument('name', type = str)

args = parser.parse_args()

if args.name:
print(args.name)
if args.convert:
print ("convert now!")


For example, in the codes above, I want
name
to be required, only when
-c
is given. When I run the program only with
-l
, then there is an error:

$ python3 test.py -l
usage: test.py [-h] [-c] [-l] name
test.py: error: the following arguments are required: name


I have tried to use argument group to divide the arguments into two groups 1.
-c
and
name
; 2.
-l
, but it didn't really work.

Any suggestions are appreciated!

Answer

There isn't anything in argparse to do this directly; but it can be approximated in various ways

parser.add_argument('-c', '--convert', action = 'store_true')
parser.add_argument('-l', '--lookup', action = 'store_true')
parser.add_argument('name', nargs='?', default='good default') 

It's not required in either case, but in the case of -c you could either use the good default, or you can complain after parsing.

parser.add_argument('-c', '--convert')
parser.add_argument('-l', '--lookup', nargs='?', default='adefault', const='aconst')

In this case, -c expects an argument, your required name. An argument is optional for -l. If no -l, the value is the default; if -l without the argument, the value is the const. You could even put -c and -l in a mutually exclusive group.

There isn't a mechanism for requiring several arguments to go together (i.e. no 'mutually-required-group`). However subparsers work along that line. Do I need to illustrate how subparsers could be use here?

Custom Actions classes can be used to force some sort of interaction between arguments, but usually it's easier to implement that sort of thing after parsing. Remember argparse allows you give arguments in any order. Thus the name positional could occur before -c, or after, or between -l and -c etc.