changeset 211:421bcbd15282

Improve command line interface.
author Daniele Nicolodi <daniele@grinta.net>
date Fri, 18 Nov 2011 00:23:31 +0100
parents 5b1649631cee
children ca6999a5b402
files src/ltpdarepo/admin.py
diffstat 1 files changed, 62 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/src/ltpdarepo/admin.py	Thu Nov 17 14:32:56 2011 +0100
+++ b/src/ltpdarepo/admin.py	Fri Nov 18 00:23:31 2011 +0100
@@ -28,13 +28,6 @@
     HAS_SQL_ALCHEMY = False
 
 
-class verbosity(argparse.Action):
-    def __call__(self, *args, **kwargs):
-        # increse logging level
-        logger = logging.getLogger('ltpdarepo')
-        logger.setLevel(logger.level - 10)
-
-
 def _bool(value):
     # parse string into boolean value
     if value not in ('yes', 'no', 'true', 'false'):
@@ -42,44 +35,64 @@
     return value in ('yes', 'true')
 
 
+class ArgumentParser(argparse.ArgumentParser):
+    def _check_value(self, action, value):
+        if action.choices is not None and value not in action.choices:
+            self.error("unknown command %s" % value)
+
+    def print_help(self, name=None, out=sys.stdout):
+
+        commands = self._subparsers._group_actions[0].choices
+        options = self._action_groups[1]._group_actions
+
+        if name is not None:
+            command = commands.get(name, None)
+            if command is None:
+                commands['help'].error("unknown command %s" % name)
+            print >>out, commands[name].format_help().strip()
+            return
+
+        print >>out, self.description
+        print >>out, self.format_usage().strip()
+        print >>out, ""
+        print >>out, "commands:"
+        for name, cmd in sorted(commands.iteritems()):
+            doc = ''
+            if cmd.description:
+                doc = cmd.description.splitlines()[0]
+            print >>out, "  %-13s  %s" % (name, doc)
+        print >>out, ""
+        print >>out, "options:"
+        for opt in options:
+            print >>out, "  %-13s  %s" % (", ".join(opt.option_strings), opt.help)
+        print >>out, ""
+
+
 class Commands(object):
     def __init__(self):
-        self.parser = argparse.ArgumentParser(add_help=False)
-        self.commands = self.parser.add_subparsers(metavar='command')
-        options = self.parser.add_argument_group('options')
-        options.add_argument('-v', '--verbose', action=verbosity,
-                             nargs=0, dest=argparse.SUPPRESS,
-                             help='increase verbosity')
+        self.parser = ArgumentParser(add_help=False,
+                                     description='LTPDA Repository administration tool')
+        self.commands = self.parser.add_subparsers(metavar='command',
+                                                   parser_class=argparse.ArgumentParser)
+
+        self.parser.add_argument('-v', '--verbose', action='count',
+                                 dest='verbosity',
+                                 help='increase verbosity. may be specified multiple times')
 
-    def add(self, func, name=None):
+        self.parser.add_argument('-h', '--help', action='help',
+                                 help='show this help message')
+
+    def add(self, func, name=None, help=None):
         name = name or func.__name__
-        desc = func.__doc__ or ' '
-        parser = self.commands.add_parser(name,
-                                          help=desc.splitlines()[0],
-                                          description=desc,
-                                          add_help=False)
-        parser.set_defaults(command=func)
+        desc = help or func.__doc__
+        parser = self.commands.add_parser(name, help=help,
+                                          description=desc, add_help=False)
+        parser.set_defaults(_command=func)
         return parser
 
     def parse(self, *args):
         return self.parser.parse_args(*args)
 
-    def dispatch(self):
-        args = vars(self.parser.parse_args())
-        command = args.pop('command')
-        try:
-            command(**args)
-        except Exception:
-            import traceback
-            sys.stderr.write(traceback.format_exc())
-            sys.exit(1)
-
-    def __iter__(self):
-        return iter(sorted(self.commands.choices.keys()))
-
-    def __getitem__(self, name):
-        return self.commands.choices[name]
-
 
 class Application(ltpdarepo.Application):
 
@@ -98,7 +111,7 @@
     def __getattr__(self, name):
         if name in self.config:
             return self.config[name]
-        return self[name]
+        return self.__dict__[name]
 
     def connect(self, **kwargs):
         # open connection to the database
@@ -122,6 +135,12 @@
     def dispatch(self):
         args = vars(self.commands.parser.parse_args())
 
+        # verbosity
+        verbosity = args.pop('verbosity')
+        if verbosity:
+            logger = logging.getLogger('ltpdarepo')
+            logger.setLevel(logger.level - 10 * verbosity)
+
         # common parameters
         username = args.pop('_username', None)
         if username:
@@ -131,31 +150,17 @@
             self._password = password
 
         # run command
-        command = args.pop('command')
+        command = args.pop('_command')
         command(self, **args)
 
 
-    def help(self, name=None, out=sys.stderr):
-        """provide commands help"""
-
-        if name is not None:
-            print >>out, self.commands[name].format_help().strip()
-            return
-
-        print >>out, "LTPDA Repository administration tool"
-        print >>out, self.commands.parser.format_usage().strip()
-        print >>out, ""
-        print >>out, "commands:"
-        for cmd in self.commands:
-            doc = self.commands[cmd].description or ' '
-            print >>out, "  %-15s  %s" % (cmd, doc.splitlines()[0])
-        print >>out, ""
-        print >>out, "options:"
-        print >>out, "  %-15s  %s" % ("-v, --verbose", "increase verbosity. may be specified multiple times")
-        print >>out, ""
+    def help(self, command=None):
+        """show this help message or given command help """
+        self.commands.parser.print_help(command)
+        self.commands.parser.exit()
 
     cmd = commands.add(help)
-    cmd.add_argument('name', nargs='?', help='command', metavar='NAME')
+    cmd.add_argument('command', nargs='?', metavar='COMMAND')
 
 
     def user(self, username):