support calling commands from python when options are defined in list
authorAlexander Solovyov <piranha@piranha.org.ua>
Thu, 10 Sep 2009 00:17:29 +0300
changeset 88 dbea34bde1f7
parent 87 ec9736668bca
child 89 472a33d66076
support calling commands from python when options are defined in list
opster.py
test_opts.py
--- a/opster.py	Sun Sep 06 16:32:32 2009 +0300
+++ b/opster.py	Thu Sep 10 00:17:29 2009 +0300
@@ -37,12 +37,14 @@
        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:
-            # no options supplied and no options present in func
             options_ = []
+        try:
+            options_ = options_ + list(options)
+        except TypeError:
+            pass
 
         name_ = name or func.__name__.replace('_', '-')
         if usage is None:
@@ -64,13 +66,13 @@
             except StopIteration:
                 options_.append(('h', 'help', False, 'show help'))
 
-            argv = opts.pop('args', None)
+            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)(*args, **opts)
+                return call_cmd_regular(func, options_)(*args, **opts)
 
             if argv is None:
                 argv = sys.argv[1:]
@@ -403,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 '
@@ -458,15 +464,18 @@
             raise
     return inner
 
-def call_cmd_regular(func):
+def call_cmd_regular(func, opts):
     def inner(*args, **kwargs):
-        funcargs, varargs, varkw, defaults = inspect.getargspec(func)
+        funcargs, _, varkw, defaults = inspect.getargspec(func)
+        if len(args) > len(funcargs):
+            raise TypeError('You have supplied more positional arguments'
+                            ' than applicable')
 
-        funckwargs = funcargs[len(args):]
-        funckwargs = dict(zip(funckwargs, (default for _, default, _
-                                           in defaults[-len(funckwargs):])))
+        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
 
--- a/test_opts.py	Sun Sep 06 16:32:32 2009 +0300
+++ b/test_opts.py	Thu Sep 10 00:17:29 2009 +0300
@@ -15,7 +15,7 @@
 
     It looks very similar to some serve command
     '''
-    print opts
+    print locals()
 
 @command(usage='[-l HOST] DIR')
 def another(dirname,