Fix config help order to be alphabetical
Currently The output of --help is in random order. The only way using public argparse api to control the order of display of --help is to add the arguments in the sorted order. So added a caching mechanism to collect all the calls to add_argument and ensure they are sorted before calling argparse's add_argument. The only other choice if anyone is interested is documented here which uses the non-public API http://stackoverflow.com/questions/12268602/sort-argparse-help-alphabetically Fixes LP# 1185959 Change-Id: I5f934c85fd516e2d87b3ece40142f16c898b04ce
This commit is contained in:
parent
fb2798650d
commit
29513917cb
@ -601,12 +601,12 @@ class Opt(object):
|
||||
for opt in self.deprecated_opts:
|
||||
deprecated_name = self._get_deprecated_cli_name(opt.name,
|
||||
opt.group)
|
||||
self._add_to_argparse(container, self.name, self.short,
|
||||
self._add_to_argparse(parser, container, self.name, self.short,
|
||||
kwargs, prefix,
|
||||
self.positional, deprecated_name)
|
||||
|
||||
def _add_to_argparse(self, container, name, short, kwargs, prefix='',
|
||||
positional=False, deprecated_name=None):
|
||||
def _add_to_argparse(self, parser, container, name, short, kwargs,
|
||||
prefix='', positional=False, deprecated_name=None):
|
||||
"""Add an option to an argparse parser or group.
|
||||
|
||||
:param container: an argparse._ArgumentGroup object
|
||||
@ -615,7 +615,6 @@ class Opt(object):
|
||||
:param kwargs: the keyword arguments for add_argument()
|
||||
:param prefix: an optional prefix to prepend to the opt name
|
||||
:param position: whether the optional is a positional CLI argument
|
||||
:raises: DuplicateOptError if a naming confict is detected
|
||||
"""
|
||||
def hyphen(arg):
|
||||
return arg if not positional else ''
|
||||
@ -626,10 +625,7 @@ class Opt(object):
|
||||
if deprecated_name:
|
||||
args.append(hyphen('--') + deprecated_name)
|
||||
|
||||
try:
|
||||
container.add_argument(*args, **kwargs)
|
||||
except argparse.ArgumentError as e:
|
||||
raise DuplicateOptError(e)
|
||||
parser.add_parser_argument(container, *args, **kwargs)
|
||||
|
||||
def _get_argparse_container(self, parser, group):
|
||||
"""Returns an argparse._ArgumentGroup.
|
||||
@ -812,8 +808,8 @@ class BoolOpt(Opt):
|
||||
opt.group,
|
||||
prefix='no')
|
||||
kwargs["help"] = "The inverse of --" + self.name
|
||||
self._add_to_argparse(container, self.name, None, kwargs, prefix,
|
||||
self.positional, deprecated_name)
|
||||
self._add_to_argparse(parser, container, self.name, None, kwargs,
|
||||
prefix, self.positional, deprecated_name)
|
||||
|
||||
def _get_argparse_kwargs(self, group, action='store_true', **kwargs):
|
||||
"""Extends the base argparse keyword dict for boolean options."""
|
||||
@ -1419,6 +1415,52 @@ class _Namespace(argparse.Namespace):
|
||||
return values if multi else values[-1]
|
||||
|
||||
|
||||
class _CachedArgumentParser(argparse.ArgumentParser):
|
||||
|
||||
"""class for caching/collecting command line arguments.
|
||||
|
||||
It also sorts the arguments before intializing the ArgumentParser.
|
||||
We need to do this since ArgumentParser by default does not sort
|
||||
the argument options and the only way to influence the order of
|
||||
arguments in '--help' is to ensure they are added in the sorted
|
||||
order.
|
||||
"""
|
||||
|
||||
def __init__(self, prog=None, usage=None):
|
||||
super(_CachedArgumentParser, self).__init__(prog, usage)
|
||||
self._args_cache = {}
|
||||
|
||||
def add_parser_argument(self, container, *args, **kwargs):
|
||||
values = []
|
||||
if container in self._args_cache:
|
||||
values = self._args_cache[container]
|
||||
values.append({'args': args, 'kwargs': kwargs})
|
||||
self._args_cache[container] = values
|
||||
|
||||
def initialize_parser_arguments(self):
|
||||
for container, values in self._args_cache.iteritems():
|
||||
values.sort(key=lambda x: x['args'])
|
||||
for argument in values:
|
||||
try:
|
||||
container.add_argument(*argument['args'],
|
||||
**argument['kwargs'])
|
||||
except argparse.ArgumentError as e:
|
||||
raise DuplicateOptError(e)
|
||||
self._args_cache = {}
|
||||
|
||||
def parse_args(self, args=None, namespace=None):
|
||||
self.initialize_parser_arguments()
|
||||
return super(_CachedArgumentParser, self).parse_args(args, namespace)
|
||||
|
||||
def print_help(self, file=None):
|
||||
self.initialize_parser_arguments()
|
||||
super(_CachedArgumentParser, self).print_help(file)
|
||||
|
||||
def print_usage(self, file=None):
|
||||
self.initialize_parser_arguments()
|
||||
super(_CachedArgumentParser, self).print_usage(file)
|
||||
|
||||
|
||||
class ConfigOpts(collections.Mapping):
|
||||
|
||||
"""Config options which may be set on the command line or in config files.
|
||||
@ -1449,10 +1491,11 @@ class ConfigOpts(collections.Mapping):
|
||||
if default_config_files is None:
|
||||
default_config_files = find_config_files(project, prog)
|
||||
|
||||
self._oparser = argparse.ArgumentParser(prog=prog, usage=usage)
|
||||
self._oparser.add_argument('--version',
|
||||
action='version',
|
||||
version=version)
|
||||
self._oparser = _CachedArgumentParser(prog=prog, usage=usage)
|
||||
self._oparser.add_parser_argument(self._oparser,
|
||||
'--version',
|
||||
action='version',
|
||||
version=version)
|
||||
|
||||
return prog, default_config_files
|
||||
|
||||
|
@ -130,6 +130,21 @@ class HelpTestCase(BaseTestCase):
|
||||
self.assertTrue('optional' in f.getvalue())
|
||||
self.assertTrue('-h, --help' in f.getvalue())
|
||||
|
||||
def test_print_sorted_help(self):
|
||||
f = moves.StringIO()
|
||||
self.conf.register_cli_opt(cfg.StrOpt('zba'))
|
||||
self.conf.register_cli_opt(cfg.StrOpt('abc'))
|
||||
self.conf.register_cli_opt(cfg.StrOpt('ghi'))
|
||||
self.conf.register_cli_opt(cfg.StrOpt('deb'))
|
||||
self.conf([])
|
||||
self.conf.print_help(file=f)
|
||||
zba = f.getvalue().find('--zba')
|
||||
abc = f.getvalue().find('--abc')
|
||||
ghi = f.getvalue().find('--ghi')
|
||||
deb = f.getvalue().find('--deb')
|
||||
list = [abc, deb, ghi, zba]
|
||||
self.assertEquals(sorted(list), list)
|
||||
|
||||
|
||||
class FindConfigFilesTestCase(BaseTestCase):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user