From e31a7f664a97c3e9600279d52df4cb6dab5353b7 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 6 May 2012 18:26:11 -0400 Subject: make help list commands if none match exactly; fixes #8 --- cliff/help.py | 15 ++++++++++++++- docs/source/history.rst | 5 +++++ tests/test_help.py | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) 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 -- cgit v1.2.1