# HG changeset patch # User John Mulligan # Date 1257109738 18000 # Sun Nov 01 16:08:58 2009 -0500 # Node ID da03ff76887aa96357c0e59c9eb5ae576f9671c5 # Parent ef91d0105adab663f233b0b1b866874b9a11cdce testing commands launching and help diff --git a/test/test_cli_commands.py b/test/test_cli_commands.py --- a/test/test_cli_commands.py +++ b/test/test_cli_commands.py @@ -9,10 +9,10 @@ ] -def cmd1(): +def cmd1(fn, **opts): return 1 -def cmd2(): +def cmd2(**opts): return 2 def cmd3(): @@ -112,7 +112,7 @@ @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 @@ 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() diff --git a/vanity/commander.py b/vanity/commander.py --- a/vanity/commander.py +++ b/vanity/commander.py @@ -18,6 +18,7 @@ """ from vanity import cli +import sys class InvalidCommand(cli.CliError): @@ -33,7 +34,15 @@ 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 @@ * ``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 @@ * ``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):