timrau timrau - 11 months ago 40
Python Question

Accept exactly 0, 1 or 2 positional arguments

I'm using argparse package to parse command line arguments. Now I want to accept exactly 0, 1 or 2 strings and put them into a list.

My current approach looks like:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('strs', nargs='*')

print(parser.parse_args(['AAA', 'BBB']).strs)
print(parser.parse_args(['AAA', 'BBB', 'CCC']).strs)

For the 1st, 2nd and 3rd
the results are expected. For the last one my current approach is
if len(parse_args.strs) > 2: raise
. Is there any better approach that could let argparse check for me?

Answer Source

There isn't a means in argparse to accept a range of nargs, just values like 1,2,'+','*'.

You could write a custom Action class that would check the number of values that the nargs='*' passes it. But I think it would be just as easy to perform that test after parsing.

I could find a bug/issue that explores adding a range nargs option if you really want to get into that.

If you didn't have other positionals you could define 3 positionals, 2 of them with ?. You might even be able to combine them into one list with a common name and 'append' action. I'll explore that.

In [573]: p=argparse.ArgumentParser()
In [574]: p.add_argument('str',action='append')
In [575]: p.add_argument('str',nargs='?',action='append')
In [576]: p.add_argument('str',nargs='?',action='append')

In [577]: p.print_help()
usage: ipython3 [-h] str [str] [str]

positional arguments:

optional arguments:
  -h, --help  show this help message and exit

In [578]: p.parse_args('1 2 3'.split())
Out[578]: Namespace(str=['1', '2', '3'])
In [579]: p.parse_args('1 3'.split())
Out[579]: Namespace(str=['1', '3', None])
In [580]: p.parse_args('1'.split())
Out[580]: Namespace(str=['1', None, None])

Got the default Nones. I can correct that with

p.add_argument('str', nargs='?', action='append', default=argparse.SUPPRESS)

In [586]: p.parse_args('1 2'.split())
Out[586]: Namespace(str=['1', '2'])
In [588]: p.parse_args('1 2 3 4'.split())
usage: ipython3 [-h] str [str] [str]
ipython3: error: unrecognized arguments: 4