From fa7eee3bdf18dc1a2d48e865029295428111413f Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 12 Nov 2013 01:34:08 +0100 Subject: [PATCH] commands: Add basic format usage helper --- mopidy/utils/command.py | 16 ++++++++++++---- tests/utils/command_test.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/mopidy/utils/command.py b/mopidy/utils/command.py index 3bc65e59..b8e2aa85 100644 --- a/mopidy/utils/command.py +++ b/mopidy/utils/command.py @@ -1,5 +1,6 @@ import argparse import collections +import sys class CommandError(Exception): @@ -11,18 +12,19 @@ class Command(object): self._children = collections.OrderedDict() self._arguments = [] - def _build_parser(self): + def _build(self): + actions = [] parser = argparse.ArgumentParser(add_help=False) for args, kwargs in self._arguments: - parser.add_argument(*args, **kwargs) + actions.append(parser.add_argument(*args, **kwargs)) if self._children: parser.add_argument('_args', nargs=argparse.REMAINDER) else: parser.set_defaults(_args=[]) - return parser + return parser, actions def add_child(self, name, command): self._children[name] = command @@ -30,11 +32,17 @@ class Command(object): def add_argument(self, *args, **kwargs): self._arguments.append((args, kwargs)) + def format_usage(self, prog=None): + actions = self._build()[1] + formatter = argparse.HelpFormatter(prog or sys.argv[0]) + formatter.add_usage(None, actions, []) + return formatter.format_help() + def parse(self, args, namespace=None): if not namespace: namespace = argparse.Namespace() - parser = self._build_parser() + parser = self._build()[0] result, unknown = parser.parse_known_args(args, namespace) if unknown: diff --git a/tests/utils/command_test.py b/tests/utils/command_test.py index 67fe8735..50006fc8 100644 --- a/tests/utils/command_test.py +++ b/tests/utils/command_test.py @@ -102,3 +102,39 @@ class CommandParsingTest(unittest.TestCase): result = cmd.parse([]) self.assertEqual(result.command, cmd) + + +class UsageTest(unittest.TestCase): + @mock.patch('sys.argv') + def test_basic_usage(self, argv_mock): + argv_mock.__getitem__.return_value = 'foo' + + cmd = command.Command() + self.assertEqual('usage: foo', cmd.format_usage().strip()) + + self.assertEqual('usage: baz', cmd.format_usage('baz').strip()) + + cmd.add_argument('-h', '--help', action='store_true') + self.assertEqual('usage: foo [-h]', cmd.format_usage().strip()) + + cmd.add_argument('bar') + self.assertEqual('usage: foo [-h] bar', cmd.format_usage().strip()) + + @mock.patch('sys.argv') + def test_nested_usage(self, argv_mock): + argv_mock.__getitem__.return_value = 'foo' + + child = command.Command() + cmd = command.Command() + cmd.add_child('bar', child) + + self.assertEqual('usage: foo', cmd.format_usage().strip()) + self.assertEqual('usage: foo bar', cmd.format_usage('foo bar').strip()) + + cmd.add_argument('-h', '--help', action='store_true') + self.assertEqual('usage: foo bar', + child.format_usage('foo bar').strip()) + + child.add_argument('-h', '--help', action='store_true') + self.assertEqual('usage: foo bar [-h]', + child.format_usage('foo bar').strip())