commands: Internalise handling of help action
This means help will always be handled by the root command. Additionally this adds an exit helper.
This commit is contained in:
parent
0b1b249ae8
commit
d82f48a42f
@ -18,6 +18,23 @@ class ArgumentParser(argparse.ArgumentParser):
|
|||||||
raise CommandError(message)
|
raise CommandError(message)
|
||||||
|
|
||||||
|
|
||||||
|
class _HelpError(Exception):
|
||||||
|
"""Internal exception used to trigger help code path."""
|
||||||
|
|
||||||
|
|
||||||
|
class _HelpAction(argparse.Action):
|
||||||
|
def __init__(self, option_strings, dest=None, help=None):
|
||||||
|
super(_HelpAction, self).__init__(
|
||||||
|
option_strings=option_strings,
|
||||||
|
dest=dest or argparse.SUPPRESS,
|
||||||
|
default=argparse.SUPPRESS,
|
||||||
|
nargs=0,
|
||||||
|
help=help)
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
raise _HelpError()
|
||||||
|
|
||||||
|
|
||||||
class Command(object):
|
class Command(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._children = collections.OrderedDict()
|
self._children = collections.OrderedDict()
|
||||||
@ -27,6 +44,7 @@ class Command(object):
|
|||||||
def _build(self):
|
def _build(self):
|
||||||
actions = []
|
actions = []
|
||||||
parser = ArgumentParser(add_help=False)
|
parser = ArgumentParser(add_help=False)
|
||||||
|
parser.register('action', 'help', _HelpAction)
|
||||||
|
|
||||||
for args, kwargs in self._arguments:
|
for args, kwargs in self._arguments:
|
||||||
actions.append(parser.add_argument(*args, **kwargs))
|
actions.append(parser.add_argument(*args, **kwargs))
|
||||||
@ -44,6 +62,9 @@ class Command(object):
|
|||||||
def set_defaults(self, **kwargs):
|
def set_defaults(self, **kwargs):
|
||||||
self._defaults.update(kwargs)
|
self._defaults.update(kwargs)
|
||||||
|
|
||||||
|
def exit(self, return_code):
|
||||||
|
sys.exit(return_code)
|
||||||
|
|
||||||
def format_usage(self, prog=None):
|
def format_usage(self, prog=None):
|
||||||
actions = self._build()[1]
|
actions = self._build()[1]
|
||||||
prog = prog or os.path.basename(sys.argv[0])
|
prog = prog or os.path.basename(sys.argv[0])
|
||||||
@ -99,8 +120,12 @@ class Command(object):
|
|||||||
|
|
||||||
def parse(self, args, prog=None):
|
def parse(self, args, prog=None):
|
||||||
prog = prog or os.path.basename(sys.argv[0])
|
prog = prog or os.path.basename(sys.argv[0])
|
||||||
return self._parse(
|
try:
|
||||||
args, argparse.Namespace(), self._defaults.copy(), prog)
|
return self._parse(
|
||||||
|
args, argparse.Namespace(), self._defaults.copy(), prog)
|
||||||
|
except _HelpError:
|
||||||
|
print self.format_help(prog)
|
||||||
|
self.exit(0)
|
||||||
|
|
||||||
def _parse(self, args, namespace, defaults, prog):
|
def _parse(self, args, namespace, defaults, prog):
|
||||||
defaults.update(self._defaults)
|
defaults.update(self._defaults)
|
||||||
|
|||||||
@ -197,6 +197,16 @@ class CommandParsingTest(unittest.TestCase):
|
|||||||
result = cmd.parse(['command'])
|
result = cmd.parse(['command'])
|
||||||
self.assertEqual(result.foo, 'bar')
|
self.assertEqual(result.foo, 'bar')
|
||||||
|
|
||||||
|
def test_help_action_works(self):
|
||||||
|
cmd = command.Command()
|
||||||
|
cmd.add_argument('-h', action='help')
|
||||||
|
cmd.format_help = mock.Mock()
|
||||||
|
cmd.exit = mock.Mock()
|
||||||
|
|
||||||
|
cmd.parse(['-h'])
|
||||||
|
cmd.format_help.assert_called_once_with(mock.ANY)
|
||||||
|
cmd.exit.assert_called_once_with(0)
|
||||||
|
|
||||||
|
|
||||||
class UsageTest(unittest.TestCase):
|
class UsageTest(unittest.TestCase):
|
||||||
@mock.patch('sys.argv')
|
@mock.patch('sys.argv')
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user