I'm writing an argument parser for a python module with various subparsers. My objective is to have an argument that's shared whose Argument constructor is passed to multiple children:
from argparse import ArgumentParser
parser = ArgumentParser(prog = 'master')
parser1 = ArgumentParser(help = None)
parser1.add_argument('foo', type = int, help = 'Number of times to process %(prog)s') # Line of interest
parser2 = ArgumentParser(help = None)
parser2.add_argument('--bar', type = int, default = 0, help = 'Start at this number')
parser3 = ArgumentParser(help = None)
parser3.add_argument('--baz', type = str, default = 'DEFAULT', help = 'Init file with this text')
subparsers = parser.add_subparsers()
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2])
sp2 = subparsers.add_parser('prog2', parents = [parser1, parser3])
parser.parse_args('prog1 -h'.split())
The desired output would be something like
usage: master prog1 [-h] [--bar BAR] foo
positional arguments:
foo Number of times to process prog1
optional arguments:
-h, --help show this message and exit
--bar Start at this number
When I use this exact setup, i get master prog1
instead of prog1
in the help string for foo
. What should i change in the line marked #Line of interest
to get the desired result?
I can explain what is going on, but may not be able offer a solution.
The short answer is that the sp1.prog
is used both in its usage
format and as the %(prog)s
value in the help lines. And it is constructed with that usage
line in mind.
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2])
creates a parser, and adds arguments from the parents
. add_parser
is a method of the class _SubParsersAction
(the subparser Action class). And the prog
attribute for that parser is created with:
if kwargs.get('prog') is None:
kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
You should be able to see this attribute with print(sp1.prog)
(I expect 'master prog1'). That's the value that is used in the usage
line, and in any of the help lines with %(prog)s
.
subparsers._prog_prefix
is derived from parser.prog
(see the add_subparsers
code for details). But you can also specify a prog
parameter:
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='prog1')
That should correct the string in the help
line. But it will also change the string the usage
.
You could also give the subparser an explicit usage
:
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='prog1', usage='master prog1 ...')
Without doing surgery to the HelpFormatter
I don't think you can change prog
in the help lines without also changing it in the usage.
And given the way parents
works you can't change the help line for prog1 foo
without also changing it for prog2 foo
. parents
copies Action objects by reference, so the two subparsers share the foo
Action object.
You many have to abandon the parents
approach, at least for this argument, and hardcode the name. If you need to add the argument to multiple subparsers, write a little utility function to facilitate that. The parents
mechanism is just (usually) a convenience, something that saves some typing/editing.
This modified script will illustrate my points
parser = ArgumentParser(prog = 'master')
parser1 = ArgumentParser(add_help = False)
fooarg=parser1.add_argument('foo', type = int, help = 'foo prog: %(prog)s') # Line of interest
parser2 = ArgumentParser(add_help = False)
parser2.add_argument('--bar', type = int, default = 0, help = 'Start at this number')
parser3 = ArgumentParser(add_help = False)
parser3.add_argument('--baz', type = str, default = 'DEFAULT', help = 'Init file with this text')
subparsers = parser.add_subparsers(prog='subparsers')
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='name1')
sp2 = subparsers.add_parser('prog2', parents = [parser1, parser3])
#parser.print_help()
# fooarg is an Action for both subparsers
# print(fooarg.help)
# fooarg.help = 'FOO HELP'
print('==>sp1 prog:', sp1.prog)
sp1.print_help()
print('==>sp2 prog:', sp2.prog)
sp2.print_help()
sp1.prog = 'custom'
sp1.print_help()
# addition
fooarg.default = 'default'
fooarg.metavar = 'META'
fooarg.help = 'prog: %(prog)s, dest=%(dest)s, nargs=%(nargs)s, type=%(type)s, default=%(default)s'
sp1.print_help()
This last bit adds a bunch of Action attributes to the help. But prog
is the only one that comes from the parser
:
positional arguments:
META prog: custom, dest=foo, nargs=None, type=int, default=default
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.