testing commands launching and help
2 files changed, 53 insertions(+), 88 deletions(-)

M test/test_cli_commands.py
M vanity/commander.py
M test/test_cli_commands.py +22 -3
@@ 9,10 9,10 @@ GOPT_A = [
     ]
 
 
-def cmd1():
+def cmd1(fn, **opts):
     return 1
 
-def cmd2():
+def cmd2(**opts):
     return 2
 
 def cmd3():

          
@@ 112,7 112,7 @@ class TestCliCommands(unittest.TestCase)
         @cmds.add('frob')
         def frob(test):
             return test
-        @cmds.add('blipp', opts=[('check', 'c', None, 'be careful')])
+        @cmds.add(opts=[('check', 'c', None, 'be careful')])
         def blipp(also):
             return also + 1
 

          
@@ 125,6 125,25 @@ class TestCliCommands(unittest.TestCase)
         self.assertEqual(cmd.target, blipp)
         self.assertTrue(opts['check'])
 
+    def test_launching_command(self):
+        arguments = 'foo test.txt'.split()
+        result = commander.launch(GOPT_A, CMDTABLE_A, arguments)
+        self.assertEqual(result, 1)
+        arguments = 'bar'.split()
+        result = commander.launch(GOPT_A, CMDTABLE_A, arguments)
+        self.assertEqual(result, 2)
+
+    def test_help_wanted(self):
+        arguments = '-h foo'.split()
+        self.assertRaises(commander.HelpWanted,
+            commander.launch, GOPT_A, CMDTABLE_A, arguments)
+        arguments = 'foo -h'.split()
+        self.assertRaises(commander.HelpWanted,
+            commander.launch, GOPT_A, CMDTABLE_A, arguments)
+        arguments = 'help'.split()
+        self.assertRaises(commander.HelpWanted,
+            commander.launch, GOPT_A, CMDTABLE_A, arguments)
+
 
 if __name__ == '__main__':
     unittest.main()

          
M vanity/commander.py +31 -85
@@ 18,6 18,7 @@ XXX
 """
 
 from vanity import cli
+import sys
 
 
 class InvalidCommand(cli.CliError):

          
@@ 33,7 34,15 @@ class AmbiguousCommand(cli.CliError):
         self.matches = matches
 
 
-def launch(globalopts, cmdtable, arguments):
+class HelpWanted(cli.CliError):
+    """The user has requested help"""
+    def __init__(self, cmd, opts, args):
+        self.cmd = cmd
+        self.opts = opts
+        self.args = args
+
+
+def launch(globalopts, cmdtable, arguments, autohelp=True):
     """Launch a subcommand based on the given arguments, return the
     result of the launched function.
 

          
@@ 41,7 50,19 @@ def launch(globalopts, cmdtable, argumen
     * ``cmdtable`` -  a commands table
     * ``arguments`` - the command line arguments
     """
-    pass
+    # inject help objects (if requested)
+    cmdtable = CommandTable(cmdtable)
+    globalopts = cli.OptionTable(globalopts)
+    if autohelp:
+        cmdtable._table[HELP.name] = HELP
+        globalopts._table[HELPOPT.name] = HELPOPT
+    # parse cli
+    cmd, opts, args = parse(globalopts, cmdtable, arguments)
+    # if help requested: raise HelpWanted
+    if cmd == HELP or opts.get('help'):
+        raise HelpWanted(cmd, opts, args)
+    # fire off the command
+    return cmd(opts, args)
 
 
 def parse(globalopts, cmdtable, arguments):

          
@@ 166,100 187,25 @@ class CommandTable(object):
         * ``opts`` - an options table; see vanity.cli for details
         * ``help`` - a short command help string
         """
-        if not name:
-            name = func.__name__
         if not opts:
             opts = []
         if not help:
             help = '[OPTIONS] [ARGS]'
         def _wrap(func):
-            cmd = Command(name, func, aliases, opts, help)
+            if name:
+                _name = name
+            else:
+                _name = func.__name__
+            cmd = Command(_name, func, aliases, opts, help)
             self._table[cmd.name] = cmd
             return func
         return _wrap
 
 
-'''
-
-
-def splitidents(idents):
-    """Return a ident string as a list of idents.
-    """
-    return str(idents).split()
-
-class CommandTable(object):
-    """Processes a table of commands and the global options.
-    """
-    def __init__(self, globalopts, commands):
-        self._global = OptionTable(globalopts)
-        self._table = {}
-        for command in commands:
-            self._addcommand(command)
-
-    def _addcommand(self, command):
-        func, idents, opts, desc = command
-        for ident in splitidents(idents):
-            self._table[ident] = (
-                func,
-                idents,
-                OptionTable(opts),
-                desc)
-
-    def labels(self):
-        return self._table.keys()
-
-
-    def firstlabels(self):
-        seen = []
-        for key in self.labels():
-            f, idents, opts, desc = self._table[key]
-            idents = splitidents(idents)
-            if idents[0] not in seen:
-                seen.append(idents[0])
-        return seen
-
+HELP = Command('help', None, None, [], 'display command help')
+HELPOPT = cli.Option('help', 'h', None, 'display command help')
 
-    def opts(self):
-        """Return the global options table
-        """
-        return self._global
-
-    def find(self, label):
-        """Given a command name or partial command name,
-        return the closest full command name.
-        If there are no matches a InvalidCommand exception is
-        raised. If there are too many matches an AmbiguousCommand
-        exception is raised.
-        """
-        matches = []
-        for key in self._table.keys():
-            if key.startswith(label):
-                matches.append(key)
-        if len(matches) == 1:
-            return matches[0]
-        if not matches:
-            raise InvalidCommand(label)
-        if label in self._table.keys():
-            #exact match
-            return label
-        raise AmbiguousCommand(label, matches)
-
-    def lookup(self, label):
-        """Return the table entry given a full or partial
-        command name.
-        """
-        key = self.find(label)
-        return self._table[key]
-
-    def get(self, label):
-        """For a full or partial command name, return the
-        function, it's identifiers, an options table containing
-        both command and global options and the command
-        description.
-        """
-        (func, id, options, desc) = self.lookup(label)
-        options = self._global + options
-        return (func, id, options, desc)
+'''
 
 
 def parsecommand(opttable, cmdtable, arguments, getopts=None):