I need to implement a command line interface in which the program accepts subcommands.
For example, if the program is called “foo”, the CLI would look like
foo cmd1 <cmd1-options>
foo cmd2
foo cmd3 <cmd3-options>
cmd1
and cmd3
must be used with at least one of their options and the three cmd*
arguments are always exclusive.
I am trying to use subparsers in argparse, but with no success for the moment. The problem is with cmd2
, that has no arguments:
if I try to add the subparser entry with no arguments, the namespace returned by parse_args
will not contain any information telling me that this option was selected (see the example below).
if I try to add cmd2
as an argument to the parser
(not the subparser), then argparse will expect that the cmd2
argument will be followed by any of the subparsers arguments.
Is there a simple way to achieve this with argparse
? The use case should be quite common…
Here follows what I have attempted so far that is closer to what I need:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='Functions')
parser_1 = subparsers.add_parser('cmd1', help='...')
parser_1.add_argument('cmd1_option1', type=str, help='...')
parser_2 = subparsers.add_parser(cmd2, help='...')
parser_3 = subparsers.add_parser('cmd3', help='...')
parser_3.add_argument('cmd3_options', type=int, help='...')
args = parser.parse_args()
First of all subparsers are never inserted in the namespace. In the example you posted if you try to run the script as:
where
test_args.py
contain the code you provided (with theimport argparse
at the beginning andprint(args)
at the end).Note that there is no mention to
cmd1
only to its argument. This is by design.As pointed out in the comments you can add that information passing the
dest
argument to theadd_subparsers
call.The usual way to handle these circumstances is to use the
set_defaults
method of the subparsers:Which results in:
In general different subparser will, most of the time, handle the arguments in completely different ways. The usual pattern is to have different functions to run the different commands and use
set_defaults
to set afunc
attribute. When you parse the arguments you simply call that callable:The subparser identity can be added to the main
Namespace
if theadd_subparsers
command is given adest
.From the documentation:
By default the
dest
isargparse.SUPPRESS
, which keepssubparsers
from adding the name to thenamespace
.