5

I want the user to be able to pass a mandatory argument to 'argparse', with either positional, or optional argument.

I.e., both following forms are valid:

my_prog arg
my_prog -m arg

I've seen Argparse optional positional arguments?

But the suggestions there make both form optional. I want that one of them will be mandatory.

Of course, I can add a manual checking after parsing that at least one of them has been set. But I got a hunch that there must be a better solution.

(And even with my manual approach, the 'help' section shows both of them as optional)

1 Answer 1

8

The mutually exclusive group mechanism can take a required parameter. It also works with one ? positional along with the optionals (flagged arguments). (more than one '?' positional doesn't make sense).

As for the help display there are 2 default groups, positonal and optional. So even if an optional (flagged) is set to required it is, by default, displayed in the optional group. The usage line is a better guide as to whether an argument is required or not. If you don't like the group labels in the help section, define your own argument groups.

In [146]: import argparse
In [147]: parser = argparse.ArgumentParser()
In [148]: gp = parser.add_mutually_exclusive_group(required=True)
In [149]: gp.add_argument('pos', nargs='?', default='foo');
In [150]: gp.add_argument('-f','--foo', default='bar');

In [151]: parser.parse_args('arg'.split())
Out[151]: Namespace(foo='bar', pos='arg')

In [152]: parser.parse_args('-f arg'.split())
Out[152]: Namespace(foo='arg', pos='foo')

In [153]: parser.parse_args('arg -f arg'.split())
usage: ipython3 [-h] [-f FOO] [pos]
ipython3: error: argument -f/--foo: not allowed with argument pos

In [154]: parser.parse_args(''.split())
usage: ipython3 [-h] [-f FOO] [pos]
ipython3: error: one of the arguments pos -f/--foo is required


In [155]: parser.parse_args('-h'.split())
usage: ipython3 [-h] [-f FOO] [pos]

positional arguments:
  pos

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

Oops, usage isn't showing the -f and pos in a mutually exlusive group. Sometimes that usage formatting is brittle.

Switching the order in which the arguments are defined gives a better usage

In [156]: parser = argparse.ArgumentParser()
In [157]: gp = parser.add_mutually_exclusive_group(required=True)
In [158]: gp.add_argument('-f','--foo', default='bar');
In [159]: gp.add_argument('pos', nargs='?', default='foo');
In [160]: 
In [160]: parser.parse_args('-h'.split())
usage: ipython3 [-h] (-f FOO | pos)

positional arguments:
  pos

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

With a user defined argument group:

In [165]: parser = argparse.ArgumentParser()
In [166]: gp = parser.add_argument_group('Mutually exclusive')
In [167]: gpm = gp.add_mutually_exclusive_group(required=True)
In [168]: gpm.add_argument('-f','--foo', default='bar');
In [169]: gpm.add_argument('pos', nargs='?', default='foo');
In [170]: 
In [170]: parser.parse_args('-h'.split())
usage: ipython3 [-h] (-f FOO | pos)

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

Mutually exclusive:
  -f FOO, --foo FOO
  pos

This is the one exception to the general rule argument_groups and mutually_exclusive_groups aren't designed for nesting.

The m-x-group was not required, usage would use []

usage: ipython3 [-h] [-f FOO | pos]
Sign up to request clarification or add additional context in comments.

2 Comments

Great. Just one caveat: these group definitions must be after all other regular arguments, otherwise it won't show the nice (-f FOO | pos) in the help
Yes, 2 things affect the usage. Positionals are shown after optionals, and a group only shows up if its arguments match that order. Correcting that brittleness will require a major rewrite of the usage formatter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.