Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python argparse - either both optional arguments or else neither one

I have a program that uses a default name and password. I'm using argparse to allow the user to specify command line options, and I would like to enable the user to provide the program with a different name and password to use. So I have the following:

parser.add_argument(     '-n',     '--name',     help='the login name that you wish the program to use'     )  parser.add_argument(     '-p',     '--password',     help='the password to log in with.'     ) 

But it doesn't make any sense to specify only the name or only the password, but it would make sense to specify neither one. I noticed that argparse does have the ability to specify that two arguments are mutually exclusive. But what I have are two arguments that must appear together. How do I get this behavior? (I found "argument groups" mentioned in the docs, but they don't appear to solve my problem http://docs.python.org/2/library/argparse.html#argument-groups)

like image 253
tadasajon Avatar asked Jan 16 '13 02:01

tadasajon


People also ask

How do you make an argument optional in Argparse?

Optional Arguments To add an optional argument, simply omit the required parameter in add_argument() . args = parser. parse_args()if args.

How do you make an argument compulsory in Python?

If a user is required to make an argument, they can set the keyword argument required to True .

Why click instead of Argparse?

Click actually implements its own parsing of arguments and does not use optparse or argparse following the optparse parsing behavior. The reason it's not based on argparse is that argparse does not allow proper nesting of commands by design and has some deficiencies when it comes to POSIX compliant argument handling.

What is Metavar in Python?

metavar is the name for the argument in usage messages. dest is the name of the attribute to be added to the object. This object is returned by parse_args .


2 Answers

I believe that the best way to handle this is to post-process the returned namespace. The reason that argparse doesn't support this is because it parses arguments 1 at a time. It's easy for argparse to check to see if something was already parsed (which is why mutually-exclusive arguments work), but it isn't easy to see if something will be parsed in the future.

A simple:

parser.add_argument('-n','--name',...,default=None) parser.add_argument('-p','--password',...,default=None) ns = parser.parse_args()  if len([x for x in (ns.name,ns.password) if x is not None]) == 1:    parser.error('--name and --password must be given together')  name = ns.name if ns.name is not None else "default_name" password = ns.password if ns.password is not None else "default_password" 

seems like it would suffice.

like image 84
mgilson Avatar answered Oct 04 '22 06:10

mgilson


I know this is more than two years late, but I found a nice and concise way to do it:

if bool(ns.username) ^ bool(ns.password):     parser.error('--username and --password must be given together') 

^ is the XOR operator in Python. To require both arguments given at the command line is essentially an XOR test.

like image 39
Ting Qian Avatar answered Oct 04 '22 06:10

Ting Qian