How to use argparse subparsers correctly?

Question:

I’ve been searching through a lot of the subparser examples on here and in general but can’t seem to figure this seemingly simple thing out.

I have two var types of which one has constraints so thought subparser was the way to go. e.g. -t allows for either "A" or "B". If the user passes "A" then they are further required to also specify if it is either "a1" or "a2". If they pass just "B" then nothing.

Can I do this and have argparse return me what type of "A" was passed or if it was just "B"?

The below seems to work but for some reason breaks when passing anything after the subparse.

e.g. from a linux terminal

>> python test01.py -t A a1 -v 61

errors with…

usage: test01.py a1 [-h]
test01.py a1: error: unrecognized arguments: -v

Hopefully that makes sense.

The code:

import argparse

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='types of A')

parser.add_argument("-t",
                    choices = ["A", "B"],
                    dest = "type",
                    required=True,
                    action='store',
                    help="Some help blah blah")

cam_parser = subparsers.add_parser('a1', help='Default')
cam_parser.set_defaults(which='a1')

cam_parser = subparsers.add_parser('a2', help='parse this instead of default')
cam_parser.set_defaults(which='a2')


parser.add_argument("-v",
                    nargs = '+',
                    required=True,
                    dest = "version",
                    type=int,
                    action='store',
                    help="some version help blah blah")   

argument = parser.parse_args()

print argument.type
print argument.version
Asked By: user1571144

||

Answers:

Subparsers are invoked based on the value of the first positional argument, so your call would look like

python test01.py A a1 -v 61

The “A” triggers the appropriate subparser, which would be defined to allow a positional argument and the -v option.

Because argparse does not otherwise impose any restrictions on the order in which arguments and options may appear, and there is no simple way to modify what arguments/options may appear once parsing has begun (something involving custom actions that modify the parser instance might work), you should consider replacing -t itself:

import argparse

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='types of A')
parser.add_argument("-v", ...)

a_parser = subparsers.add_parser("A")
b_parser = subparsers.add_parser("B")

a_parser.add_argument("something", choices=['a1', 'a2'])

Since -v is defined for the main parser, it must be specified before the argument that specifies which subparser is used for the remaining arguments.

Answered By: chepner
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.