How to use argparse subparsers correctly?
Asked Answered
S

1

79

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
Slater answered 12/6, 2013 at 19:28 Comment(1)
Instead of (multiple) cam_parser.set_defaults(...) one can use a single parser.add_subparsers(dest="which")Comity
C
92

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.

Comprise answered 12/6, 2013 at 19:59 Comment(6)
great thank you very much. However I was still getting an error when I passed -v for some reason i.e. it expected -v and when I did pass it I got my old error "unrecognized arguments". Even if I passed it before the positional arguments. Any ideas? I've been trying to find a similar example but haven't had much luck.Slater
is before the argument that specifies which subparser refering to the code of the user entering the argument or both?Cisco
It appears executing group1 = parser.add_subparsers(help='subparser group 1') and group2 = parser.add_subparsers(help='subparser group 2') gives error:cannot have multiple subparser arguments error. I was hoping to use it to group subcommands.Devol
@MinhTran You would need to use a_parser.add_subparsers() and b_parser.add_subparsers() in that case.Comprise
@Comprise something that I'm not able to find a good example of is how to execute code based on the passed argument. Typically with a single parser i'd have args = parser.parse_args() then something like if args.thing: <do thing>, it's not clear how this is meant to work with subparsers thoughCargian
The last part of this section of the argparse documentation gives an example of executing one function or another based on which subcommand is provided.Comprise

© 2022 - 2024 — McMap. All rights reserved.