Updated opster.py to its revision 979199a41678
authorDmitriy Morozov <dmitriy@mrzv.org>
Tue, 15 Sep 2009 17:22:19 -0700
changeset 29 c85b9ac4880d
parent 28 7ddd1989eb00
child 30 919f428df29a
Updated opster.py to its revision 979199a41678
opster.py
--- a/opster.py	Tue Sep 15 13:56:35 2009 -0700
+++ b/opster.py	Tue Sep 15 17:22:19 2009 -0700
@@ -6,7 +6,7 @@
 from itertools import imap
 
 __all__ = ['command', 'dispatch']
-__version__ = '0.9.8'
+__version__ = '0.9.9'
 __author__ = 'Alexander Solovyov'
 __email__ = 'piranha@piranha.org.ua'
 
@@ -37,15 +37,20 @@
        with multiple subcommands, overrides ``shortlist``
     '''
     def wrapper(func):
-        # copy option list
         try:
-            options_ = list(options or guess_options(func))
+            options_ = list(guess_options(func))
+        except TypeError:
+            options_ = []
+        try:
+            options_ = options_ + list(options)
         except TypeError:
-            # no options supplied and no options present in func
-            options_ = []
+            pass
 
-        name_ = name or func.__name__
-        usage_ = usage or guess_usage(func, options_)
+        name_ = name or func.__name__.replace('_', '-')
+        if usage is None:
+            usage_ = guess_usage(func, options_)
+        else:
+            usage_ = usage
         prefix = hide and '~' or (shortlist and '^' or '')
         CMDTABLE[prefix + name_] = (func, options_, usage_)
 
@@ -53,7 +58,7 @@
             return help_cmd(func, replace_name(usage_, sysname()), options_)
 
         @wraps(func)
-        def inner(*arguments, **kwarguments):
+        def inner(*args, **opts):
             # look if we need to add 'help' option
             try:
                 (True for option in reversed(options_)
@@ -61,16 +66,21 @@
             except StopIteration:
                 options_.append(('h', 'help', False, 'show help'))
 
-            args = kwarguments.pop('args', None)
-            if arguments or kwarguments:
-                args, opts = arguments, kwarguments
-            else:
-                args = args or sys.argv[1:]
-                try:
-                    opts, args = catcher(lambda: parse(args, options_),
-                                         help_func)
-                except Abort:
-                    return -1
+            argv = opts.pop('argv', None)
+            if opts.pop('help', False):
+                return help_func()
+
+            if args or opts:
+                # no catcher here because this is call from Python
+                return call_cmd_regular(func, options_)(*args, **opts)
+
+            if argv is None:
+                argv = sys.argv[1:]
+
+            try:
+                opts, args = catcher(lambda: parse(argv, options_), help_func)
+            except Abort:
+                return -1
 
             try:
                 if opts.pop('help', False):
@@ -316,10 +326,9 @@
 # --------
 
 def _dispatch(args, cmdtable, globalopts):
-    cmd, func, args, options, globaloptions = cmdparse(args, cmdtable,
-                                                       globalopts)
+    cmd, func, args, options = cmdparse(args, cmdtable, globalopts)
 
-    if globaloptions['help']:
+    if options.pop('help', False):
         return 'help', cmdtable['help'][0], [cmd], {}
     elif not cmd:
         return 'help', cmdtable['help'][0], ['shortlist'], {}
@@ -350,12 +359,7 @@
     except getopt.GetoptError, e:
         raise ParseError(cmd, e)
 
-    globaloptions = {}
-    for o in globalopts:
-        name = o[1]
-        globaloptions[name] = options.pop(name)
-
-    return (cmd, cmd and info[0] or None, args, options, globaloptions)
+    return (cmd, cmd and info[0] or None, args, options)
 
 def findpossible(cmd, table):
     """
@@ -401,8 +405,12 @@
 
 def guess_options(func):
     args, varargs, varkw, defaults = inspect.getargspec(func)
-    for lname, (sname, default, hlp) in zip(args[-len(defaults):], defaults):
-        yield (sname, lname.replace('_', '-'), default, hlp)
+    for name, option in zip(args[-len(defaults):], defaults):
+        try:
+            sname, default, hlp = option
+            yield (sname, name.replace('_', '-'), default, hlp)
+        except TypeError:
+            pass
 
 def guess_usage(func, options):
     usage = '%name '
@@ -419,6 +427,8 @@
     return usage
 
 def catcher(target, help_func):
+    '''Catches all exceptions and prints human-readable information on them
+    '''
     try:
         return target()
     except UnknownCommand, e:
@@ -454,6 +464,21 @@
             raise
     return inner
 
+def call_cmd_regular(func, opts):
+    def inner(*args, **kwargs):
+        funcargs, _, varkw, defaults = inspect.getargspec(func)
+        if len(args) > len(funcargs):
+            raise TypeError('You have supplied more positional arguments'
+                            ' than applicable')
+
+        funckwargs = dict((lname.replace('-', '_'), default)
+                          for _, lname, default, _ in opts)
+        if 'help' not in (defaults or ()) and not varkw:
+            funckwargs.pop('help', None)
+        funckwargs.update(kwargs)
+        return func(*args, **funckwargs)
+    return inner
+
 def replace_name(usage, name):
     if '%name' in usage:
         return usage.replace('%name', name, 1)