A few argparse_oe changes/fixes
cover A few argparse_oe changes/fixes
From: Christopher Larson <[email protected]>
The following changes since commit e2dbe5eb869b8336b91023b83d7ca866197efa73:
license.bbclass: make sure that image manifest dir exists (2016-04-22 16:28:47 +0100)
are available in the git repository at:
git://github.com/kergoth/openembedded-core argparse-oe-fixes
https://github.com/kergoth/openembedded-core/tree/argparse-oe-fixes
Christopher Larson (4):
scripts/lib/argparse_oe: show self.prog in the error message scripts/lib/argparse_oe: show subparser help for unrecognized args scripts/lib/argparse_oe: simplify options title change scripts/lib/argparse_oe: also change 'positional arguments' to
'arguments'
scripts/lib/argparse_oe.py | 64 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 12 deletions(-)
Signature · 1 line
2.8.0
PATCH 1/4 scripts/lib/argparse_oe: show self.prog in the error message
From: Christopher Larson <[email protected]>
This aligns our subclassed error() with that in the original class, using _print_message and self.prog. Also add a docstring based on the original.
--- scripts/lib/argparse_oe.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
scripts/lib/argparse_oe.py +7 -2
@@ -16,8 +16,13 @@ class ArgumentParser(argparse.ArgumentParser): super(ArgumentParser, self).__init__(*args, **kwargs) def error(self, message): - sys.stderr.write('ERROR: %s\n' % message) - self.print_help() + """error(message: string) + + Prints a help message incorporating the message to stderr and + exits. + """ + self._print_message('%s: error: %s\n' % (self.prog, message), sys.stderr) + self.print_help(sys.stderr) sys.exit(2) def error_subcommand(self, message, subcommand):
Signature · 1 line
2.8.0
PATCH 2/4 scripts/lib/argparse_oe: show subparser help for unrecognized args
From: Christopher Larson <[email protected]>
As an example, recipetool create foo bar baz shows `recipetool: error:
unrecognized arguments: bar baz` and then displays the main help, not the help for the create command. Fix by saving the subparser name and using it in parse_args() to look up the subparser.
--- scripts/lib/argparse_oe.py | 49 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-)
scripts/lib/argparse_oe.py +43 -6
@@ -27,15 +27,20 @@ class ArgumentParser(argparse.ArgumentParser): def error_subcommand(self, message, subcommand): if subcommand: - for action in self._actions: - if isinstance(action, argparse._SubParsersAction): - for choice, subparser in action.choices.items(): - if choice == subcommand: - subparser.error(message) - return + action = self._get_subparser_action() + try: + subparser = action._name_parser_map[subcommand] + except KeyError: + self.error('no subparser for name "%s"' % subcommand) + else: + subparser.error(message) + self.error(message) def add_subparsers(self, *args, **kwargs): + if 'dest' not in kwargs: + kwargs['dest'] = '_subparser_name' + ret = super(ArgumentParser, self).add_subparsers(*args, **kwargs) # Need a way of accessing the parent parser ret._parent_parser = self
@@ -48,6 +53,38 @@ class ArgumentParser(argparse.ArgumentParser): def add_subparser_group(self, groupname, groupdesc, order=0): self._subparser_groups[groupname] = (groupdesc, order) + def parse_args(self, args=None, namespace=None): + """Parse arguments, using the correct subparser to show the error.""" + args, argv = self.parse_known_args(args, namespace) + if argv: + message = 'unrecognized arguments: %s' % ' '.join(argv) + if self._subparsers: + subparser = self._get_subparser(args) + subparser.error(message) + else: + self.error(message) + sys.exit(2) + return args + + def _get_subparser(self, args): + action = self._get_subparser_action() + if action.dest == argparse.SUPPRESS: + self.error('cannot get subparser, the subparser action dest is suppressed') + + name = getattr(args, action.dest) + try: + return action._name_parser_map[name] + except KeyError: + self.error('no subparser for name "%s"' % name) + + def _get_subparser_action(self): + if not self._subparsers: + self.error('cannot return the subparser action, no subparsers added') + + for action in self._subparsers._group_actions: + if isinstance(action, argparse._SubParsersAction): + return action + class ArgumentSubParser(ArgumentParser): def __init__(self, *args, **kwargs):
Signature · 1 line
2.8.0
PATCH 3/4 scripts/lib/argparse_oe: simplify options title change
In reply to Christopher LarsonFrom: Christopher Larson <[email protected]>
There's no need to iterate over the action groups here, as self._optionals and self._positionals are available.
--- scripts/lib/argparse_oe.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
scripts/lib/argparse_oe.py +1 -4
@@ -14,6 +14,7 @@ class ArgumentParser(argparse.ArgumentParser): kwargs.setdefault('formatter_class', OeHelpFormatter) self._subparser_groups = OrderedDict() super(ArgumentParser, self).__init__(*args, **kwargs) + self._optionals.title = 'options' def error(self, message): """error(message: string)
@@ -93,10 +94,6 @@ class ArgumentSubParser(ArgumentParser): if 'order' in kwargs: self._order = kwargs.pop('order') super(ArgumentSubParser, self).__init__(*args, **kwargs) - for agroup in self._action_groups: - if agroup.title == 'optional arguments': - agroup.title = 'options' - break def parse_known_args(self, args=None, namespace=None): # This works around argparse not handling optional positional arguments being
Signature · 1 line
2.8.0
PATCH 4/4 scripts/lib/argparse_oe: also change 'positional arguments' to 'arguments'
In reply to Christopher LarsonFrom: Christopher Larson <[email protected]>
This aligns with our existing 'optional arguments' to 'options' change, and seems more intuitive for users.
--- scripts/lib/argparse_oe.py | 1 + 1 file changed, 1 insertion(+)
scripts/lib/argparse_oe.py +1 -0
@@ -14,6 +14,7 @@ class ArgumentParser(argparse.ArgumentParser): kwargs.setdefault('formatter_class', OeHelpFormatter) self._subparser_groups = OrderedDict() super(ArgumentParser, self).__init__(*args, **kwargs) + self._positionals.title = 'arguments' self._optionals.title = 'options' def error(self, message):
Signature · 1 line
2.8.0