Pupper
Pupper

Reputation: 2355

ArgumentParser: Optional argument with optional value

If I have an optional argument with optional argument value, is there a way to validate if the argument is set when the value is not given?

For instance:

parser = argparse.ArgumentParser()
parser.add_argument('--abc', nargs='?')
args = parser.parse_args()

Would correctly give me:

optional arguments:
    --abc [ABC]

How do I distinguish between 1 and 2 below?

  1. '' => args.abc is None
  2. '--abc' => args.abc is still None
  3. '--abc something' => args.abc is something

...

Update:

Found a trick to solve this problem: you can use "nargs='*'" instead of "nargs='?'". This way #1 would return None, and #2 would return an empty list. The downside is this will allow multiple values for the arguments to be accepted too; so you'd need to add a check for it if appropriate.

Alternatively you can also set a default value for the argument; see answer from chepner and Anand S Kumar.

Upvotes: 12

Views: 4411

Answers (4)

Andreas Yankopolus
Andreas Yankopolus

Reputation: 931

I'm using this to have a command-line arg for multiprocessing. Specifying --multi uses all cores and given an arg specifies a number of cores, e.g., --multi 4 for four cores.

parser.add_argument("-mp", "--multi", type=int, nargs="*", help=multi_text)

Parsing logic is then:

    if (args.multi == None):
        num_cores = 1
    elif (args.multi == []):
        num_cores = multiprocessing.cpu_count()
    elif (len(args.multi) == 1):
        num_cores = args.multi[0]
    else:
        print("Invalid specification of core usage.")
        sys.exit(1)

Upvotes: 0

hpaulj
hpaulj

Reputation: 231375

With nargs='?', you can supply both a default and const.

In [791]: parser=argparse.ArgumentParser()    
In [792]: parser.add_argument('--abc', nargs='?', default='default', const='const')

If the argument is not given it uses the default:

In [793]: parser.parse_args([])
Out[793]: Namespace(abc='default')

If given, but without an argument string, it uses the const:

In [794]: parser.parse_args(['--abc'])
Out[794]: Namespace(abc='const')

Otherwise it uses the argument string:

In [795]: parser.parse_args(['--abc','test'])
Out[795]: Namespace(abc='test')

In [796]: parser.print_help()
usage: ipython3 [-h] [--abc [ABC]]

optional arguments:
  -h, --help   show this help message and exit
  --abc [ABC]

Upvotes: 15

Anand S Kumar
Anand S Kumar

Reputation: 90889

Not sure if this is the standard way, but you can set default argument to something , and then that value would be used in case --abc is not in the argument list.

Example code -

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--abc', nargs='?', default="-1")
args = parser.parse_args()
print(args)

Result -

>python a.py
Namespace(abc='-1')

>python a.py --abc
Namespace(abc=None)

>python a.py --abc something
Namespace(abc='something')

Upvotes: 2

chepner
chepner

Reputation: 531055

Use a different default value for the option. Compare

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--abc', nargs='?', default="default")
>>> parser.parse_args()
Namespace(abc='default')
>>> parser.parse_args(['--abc'])
Namespace(abc=None)
>>> parser.parse_args(['--abc', 'value'])
Namespace(abc='value')

I'm not sure how you would provide a different value for when --abc is used without an argument, short of using a custom action instead of the nargs argument.

Upvotes: 4

Related Questions