summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Hellmann <doug.hellmann@dreamhost.com>2012-05-06 18:26:11 -0400
committerDoug Hellmann <doug.hellmann@dreamhost.com>2012-05-06 18:26:11 -0400
commite31a7f664a97c3e9600279d52df4cb6dab5353b7 (patch)
tree182bef9c9aeeb487667f0b974bcbf006dc6d9c09
parent45fbf20de2a81dfa36ece9e91413f010ca9dafc3 (diff)
downloadcliff-tablib-e31a7f664a97c3e9600279d52df4cb6dab5353b7.tar.gz
make help list commands if none match exactly; fixes #8
-rw-r--r--cliff/help.py15
-rw-r--r--docs/source/history.rst5
-rw-r--r--tests/test_help.py41
3 files changed, 60 insertions, 1 deletions
diff --git a/cliff/help.py b/cliff/help.py
index 2ac8bc4..1e4793e 100644
--- a/cliff/help.py
+++ b/cliff/help.py
@@ -38,7 +38,20 @@ class HelpCommand(Command):
def run(self, parsed_args):
if parsed_args.cmd:
- cmd_factory, cmd_name, search_args = self.app.command_manager.find_command(parsed_args.cmd)
+ try:
+ cmd_factory, cmd_name, search_args = self.app.command_manager.find_command(parsed_args.cmd)
+ except ValueError:
+ # Did not find an exact match
+ cmd = parsed_args.cmd[0]
+ fuzzy_matches = [k[0] for k in self.app.command_manager
+ if k[0].startswith(cmd)
+ ]
+ if not fuzzy_matches:
+ raise
+ self.app.stdout.write('Command "%s" matches:\n' % cmd)
+ for fm in fuzzy_matches:
+ self.app.stdout.write(' %s\n' % fm)
+ return
cmd = cmd_factory(self.app, search_args)
full_name = (cmd_name
if self.app.interactive_mode
diff --git a/docs/source/history.rst b/docs/source/history.rst
index bb3eb54..5b233b8 100644
--- a/docs/source/history.rst
+++ b/docs/source/history.rst
@@ -2,6 +2,11 @@
Release History
=================
+dev
+
+ - Asking for help about a command by prefix lists all matching
+ commands.
+
0.4
- Add shell formatter for single objects.
diff --git a/tests/test_help.py b/tests/test_help.py
index 4a2fd1c..8c7e7ed 100644
--- a/tests/test_help.py
+++ b/tests/test_help.py
@@ -57,6 +57,47 @@ def test_show_help_for_command():
pass
assert stdout.getvalue() == 'TestParser'
+
+def test_list_matching_commands():
+ # FIXME(dhellmann): Are commands tied too closely to the app? Or
+ # do commands know too much about apps by using them to get to the
+ # command manager?
+ stdout = StringIO()
+ app = App('testing', '1', TestCommandManager('cliff.test'), stdout=stdout)
+ app.NAME = 'test'
+ help_cmd = HelpCommand(app, mock.Mock())
+ parser = help_cmd.get_parser('test')
+ parsed_args = parser.parse_args(['t'])
+ try:
+ help_cmd.run(parsed_args)
+ except SystemExit:
+ pass
+ help_output = stdout.getvalue()
+ assert 'Command "t" matches:' in help_output
+ assert 'two' in help_output
+ assert 'three' in help_output
+
+
+def test_list_matching_commands_no_match():
+ # FIXME(dhellmann): Are commands tied too closely to the app? Or
+ # do commands know too much about apps by using them to get to the
+ # command manager?
+ stdout = StringIO()
+ app = App('testing', '1', TestCommandManager('cliff.test'), stdout=stdout)
+ app.NAME = 'test'
+ help_cmd = HelpCommand(app, mock.Mock())
+ parser = help_cmd.get_parser('test')
+ parsed_args = parser.parse_args(['z'])
+ try:
+ help_cmd.run(parsed_args)
+ except SystemExit:
+ pass
+ except ValueError:
+ pass
+ else:
+ assert False, 'Should have seen a ValueError'
+
+
def test_show_help_for_help():
# FIXME(dhellmann): Are commands tied too closely to the app? Or
# do commands know too much about apps by using them to get to the