I am using Python's (2.7) argparse facility and would like to automatically sort the help it produces alphabetically by option.
By default help entries are sorted in the order they are added*, as in:
p = argparse.ArgumentParser(description='Load duration curves and other plots')
p.add_argument('--first', '-f', type=int, default=1, help='First Hour')
p.add_argument('--dur', '-d', type=int, default=-1, help='Duration in Hours. Use -1 for all')
p.add_argument('--title', '-t', help='Plot Title (for all plots), default=file name')
p.add_argument('--interp', '-i', action="store_true", default=True,
help='Use linear interpolation for smoother curves')
...
args = p.parse_args()
Which when called as python script -h
produces:
usage: script.py [-h] [--first FIRST] [--dur DUR] [--title TITLE] [--interp]
Load duration curves and other plots
optional arguments:
-h, --help show this help message and exit
--first FIRST, -f FIRST
First Hour
--dur DUR, -d DUR Duration in Hours. Use -1 for all
--title TITLE, -t TITLE
Plot Title (for all plots), default=file name
--interp, -i Use linear interpolation for smoother curves
Is it possible to automatically sort them alphabetically instead? This would be dur, first, h, interp, title.
*Obviously the work around is to manually maintain by adding entries using p.add_argument in alphabetical added order but I am trying to avoid doing so.
When you create the ArgumentParser class you can pass in a help formatter: http://docs.python.org/library/argparse.html#formatter-class
So apparently you can use one of the supplied formatters, but cannot override and replace them without reverse engineering a bit:
The order of arguments in the help is determined by the
parser.format_help
method:help
is created by fetching anformatter
object, and then adding 'sections' to it. Here it loops through the_action_groups
, putting each in its own section, and adding its actions (arguments) with theadd_arguments
method. The formatter is temporary, existing only to create a strings (usually multiple lines).Action groups include the default
postionals
andoptionals
, plus any the the user creates. These groups are only used for help, not for parsing. So theaction_group._group_actions
list could be reordered without affecting parsing. (the parser has its own list of actions,parser._actions
).This confirms @mgilson's observation that sorting
p._actions
does not affect the help, but sorting the_group_actions
does.Sorting
_actions
will affect theusage
(whether part of help or standalone):Note that
action_groups
are not passed to the usage section. The usage section does reorder its actions, displayingoptionals
first, thenpositionals
.Sort arguments before/during the
add_argument
stage if you want to control parsing order of positionals, and their order in the usage.If you just want to control order in the help groups, then feel free to reorder things in the
._group_actions
list, either before calling the formatter, or within it.There have been other SO questions about controlling the order of actions in the
usage
. Some, for example, don't want thepositionals
ordered afteroptionals
.I agree that the Formatter class is cumbersom. But it is, for the most part, separate from the Parser class. So it could be rewritten with minimal effect on parsing. The existing Formatter subclasses just tweak low level methods, ones that control line wrapping and help line formating. The significant interface between parser and formatter are the
format_usage
andformat_help
methods, which are relatively simpler and highlevel.You can do this by providing a custom
HelpFormatter
class; the internals of which are officially undocumented. This means you are on your own when it comes to compatibility from Python version to version, but I find the interface quite stable:Here I sort on the option strings (
('--dur', '-d')
, etc.), but you could take your pick as to what you want to sort on. This simple sorting option puts the single-dash options last, like the-h
option.which outputs:
This is similar to @mgilson's answer. I thought I had posted this earlier, but apparently not.
You can adjust what exactly is used as the key in the dictionary, as well as the arguments to
sorted
and the exact structure of the call toadd_arguments
, to get the desired sorting order. This adheres to the publicly documented interface ofargparse
, but does add a layer to the process of defining your parser. (Depending on your philosophy, such separation of information about the options from the implementation of the parser might be a good thing.)An alternative, definitely more ugly way to do it than proposed by @MartijnPieters:
It may be nice to put this in a
try
/except
clause as it's only formatting help, therefore it shouldn't really matter for the execution of the program if this piece of code fails on anAttributeError
or something ...