With argparse, currently my main.py --help
looks like this
usage: main.py [--options] <command>
options:
-h, --help show this help message and exit
--debug Logs extra information for debugging
--version show program's version number and exit
--license reads the GPLv3
commands:
install install packages
remove remove packages
update update package list and upgrade the system
is there an easy way to make the subparser commands display before the global options?
my configuration is a bit long to post at the moment but I can if context is needed. I don't have anything crazy going on, this is the important stuff.
formatter = lambda prog: argparse.RawDescriptionHelpFormatter(prog,
max_help_position=64)
bin_name = Path(argv[0]).name
version = __version__
parser = nalaParser( formatter_class=formatter,
usage=f'{bin_name} [--options] <command>',
)
subparsers = parser.add_subparsers(title='commands', metavar='', dest='command')
parser._optionals.title = "options"
install_parser = subparsers.add_parser('install', help='install packages')
remove_parser = subparsers.add_parser('remove', help='remove packages')
update_parser = subparsers.add_parser('update', help='update package list and upgrade the system')
parser.add_argument('--debug', action='store_true', help='Logs extra information for debugging')
parser.add_argument('--version', action='version', version=f'{bin_name} {version}')
parser.add_argument('--license', action=GPLv3)
Since I was already subclassing I just added this method below to nalaParser
def format_help(self):
formatter = self._get_formatter()
# usage
formatter.add_usage(self.usage, self._actions,
self._mutually_exclusive_groups)
# description
formatter.add_text(self.description)
index = -1
# Put options last in the group
for action_group in self._action_groups[:]:
index = + 1
if action_group.title == 'options':
self._action_groups.append(self._action_groups.pop(index))
# positionals, optionals and user-defined groups
for action_group in self._action_groups:
formatter.start_section(action_group.title)
formatter.add_text(action_group.description)
formatter.add_arguments(action_group._group_actions)
formatter.end_section()
# epilog
formatter.add_text(self.epilog)
# determine help from format above
return formatter.format_help()
parser.format_help
passes the action_groups
to the formatter in the order that they were created.
In [24]: parser._action_groups
Out[24]:
[<argparse._ArgumentGroup at 0x7f8167ac02e0>,
<argparse._ArgumentGroup at 0x7f8167ac0850>,
<argparse._ArgumentGroup at 0x7f8167ac0490>]
In [25]: [a.title for a in parser._action_groups]
Out[25]: ['positional arguments', 'options', 'commands']
The default groups are positional
and options
. add_subparsers
puts its Action in the positional
group, except when given a title
. In that case it makes a new group.
You could tweak the format_help
to reorder the groups that it passes to the formatter.
Or it might work to change the 'positional arguments' title as you did with the optionals (instead of giving subparsers
the title
parameter).
Anyways, the key to the behavior is in these two methods.