Reputation: 769
The usually way to define a subparser is to do
master_parser = argparse.ArgumentParser()
subparsers = master_parser.add_subparsers()
parser = subparsers.add_parser('sub')
parser.add_argument('--subopt')
and the subparser would be called with
command sub --subopt
I am implementing a package that calls a number of converters. If I use the usual subparser approach, I would have to do
convert ext1_to_ext2 file.ext1 file.ext2 --args
which is both repetitive and error prone because users might call
convert ext1_to_ext3 file.ext1 file.ext2 --args
I would much prefer that the subparser is automatically determined from the master parser so users can use command
convert file.ext1 file.ext2 EXTRA
and argparse
would determine subparser ext1_to_ext2
from file.ext1
and file.ext2
and call the subparser ext1_to_ext2
to parse EXTRA
. Of course EXTRA
here is subparser specific.
I tried to use groups of parameters for each converter (add_argument_group
) but the parameters in argument groups cannot overlap and I got a messy list of combined arguments from all parsers, so using subparser seems to be the way to go.
I tried to use parse_known_args
with two positional arguments, determine and use the appropriate subparser to parse the remaining args, but it is difficult to provide users a list of converters and their arguments from help message.
Is there a way to do this?
Upvotes: 1
Views: 1508
Reputation: 1
This gives you a little more control in my opinion. It's along the way towards what your asking for. Just add file extension checking for your needs.
#prog.py
topParser=argparse.ArgumentParser()
subParsers = topParser.add_subparsers(
title='SubCommands',
description='Use "prog.py <subCommand> (-h | --help)" to learn more about each subcommand',
help='I can do stuff')
subParser1 = subParsers.add_parser('use1', help="Use1 does one thing")
subParser2 = subParsers.add_parser('use2', help='Use2 does another thing')
subParser1.add_argument(
'-f','--first-arg-for-use1',
help="A text file",
required=True
)
subParser1.add_argument(
'-s','--second-arg-for-use1',
help="An encoding",
required=True
)
subParser2.add_argument(
'-f','--first-arg-for-use2',
help="An image format",
required=True
)
args = topParser.parse_args()
print(args)
If nothing else, it shows how to handle the help text for the different layers.
Upvotes: 0
Reputation: 530970
Inferring the subparser to use is tricky, since it requires reimplementing a lot of the logic used by argparse
itself while you are examining each of the following arguments.
A simpler approach is to take the subparser command, which subsquently allows you to "typecheck" the following arguments to ensure they use the correct argument. For example
# This allows a file name ending with any of the given extensions,
# or allows "file.1" in place of "file.1.jpg"
def jpeg_file(s):
for ext in ("jpg", "jpeg"):
if s.endswith(ext) or os.path.exists("%s.%s" % (s, ext)):
return s
raise argparse.ArgumentTypeError()
def tiff_file(s):
# similar to jpeg_file
master_parser = argparse.ArgumentParser()
subparsers = master_parser.add_subparsers()
jpg_to_tiff_parser = subparsers.add_parser('sub')
jpg_to_tiff_parser = parse.add_argument('jpg', type=jpg_file)
jpg_to_tiff_parser = parse.add_argument('tiff', type=tiff_file)
Upvotes: 1