Python argparse: Combine nargs=* with subparsers

Say you set up argparse with a nargs=’*’ or nargs=’+’ argument first, followed by a subparser to handle a command:

parser = argparse.ArgumentParser()
parser.add_argument('--items', nargs='+', default=[])
subparsers = parser.add_subparsers()
subparser.add_parser('foo')
subparser.add_parser('bar')

The usage would look like this:

usage: script.py [--items ITEM [ITEM ...]] {foo,bar}

This is actually somewhat problematic. If you were to parse the arguments “–items one two foo”, argparse will assume that foo is an item, and complain about the lack of a command (error: too few arguments).

A workaround is letting the user break out of the nargs-based argument by given a single “-“ character. This can easily be done with:

parser.add_argument('-', dest='__dummy', 
    action="store_true", help=argparse.SUPPRESS)

Now, the following will work: “–items one two – foo”.

I think that two dashes (“–“) are more common for this purpose (with a single dash usually referring to stdin/stdout), but unfortunately, argparse doesn’t seem to support using two.

Edit: I’m a dummy. argparse already has support for “–“ to break nargs built in. It’s not 100% the same, as it will force everything that follows to be considered a positional argument (whereas argparse in theory would support multiple sets of positional arguments, I think), but for most cases, relying on the builtin “–“ is the right choice.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s