1

I would like to have a required command line argument passed as a positional argument or an optional argument. For example, I would like the same action be performed from any of the following invocations:

prog 10
prog -10
prog -n 10
prog --num 10

Is this possible with argparse?

1 Answers1

1

With a mutually exclusive group I can create a reasonable approximation:

In an interactive session:

In [10]: parser=argparse.ArgumentParser()
In [11]: grp=parser.add_mutually_exclusive_group(required=True)
In [12]: a=grp.add_argument('pos',nargs='?',type=int,default=0)
In [13]: b=grp.add_argument('-n','--num')

grp can contain any number of optionals, and one optional positional. I chose a different type for the positional just a highlight the difference.

Just the positional value:

In [14]: parser.parse_args(['10'])
Out[14]: Namespace(num=None, pos=10)

Various forms of the optional:

In [16]: parser.parse_args(['-n10'])
Out[16]: Namespace(num='10', pos=0)
In [17]: parser.parse_args(['--num=10'])
Out[17]: Namespace(num='10', pos=0)
In [18]: parser.parse_args(['--num','10'])
Out[18]: Namespace(num='10', pos=0)

test the group exclusivity

In [25]: parser.parse_args(['--num=20','10'])
usage: ipython3 [-h] [-n NUM] [pos]
ipython3: error: argument pos: not allowed with argument -n/--num

and group required:

In [26]: parser.parse_args([])
usage: ipython3 [-h] [-n NUM] [pos]
ipython3: error: one of the arguments pos -n/--num is required

I experimented with giving the positional the same dest as the optional - so both would write to num. But this results in the positional over writing the dest with its default (I can add details if needed)

In [19]: a.dest
Out[19]: 'pos'
In [20]: a.dest='num'
In [21]: parser.parse_args(['--num','10'])
Out[21]: Namespace(num=0)

Post parsing code will have to handle the args.pos and args.num values in what ever way makes sense.

The '-10' input is impossible to handle. Well, I could define:

parser.add_argument('-1')

but the result is probably not what you want:

In [31]: parser.parse_args(['--num=20','-12'])
Out[31]: Namespace(1='2', num='20', pos=0)

Overall this requirement makes things unnecessarily difficult for you the programmer.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Thanks for your answer. I agree with you about the uselessness of the `-10` form. I was thinking about the UNIX `tail` command when I posted, but that's a very specific usage and it isn't worth the extra coding in the end. I considered the use of the mutually exclusive group as you suggested, but it seems to me that it's a way to circumvent the `argparse`'s philosophy (which I don't like too much) of a clear distinction between positional and optional arguments. In the end, if I decide to keep `argparse` I think I'll use the optional argument form only (`-n`, `--num`). – TheImpostor Oct 13 '16 at 08:48