# HG changeset patch # User Alexander Solovyov <piranha@piranha.org.ua> # Date 1248430571 -10800 # Node ID ae36fb1b69a2dece79e240e1ced6dac7671545d0 # Parent a3feac00d1512567ba604504044095b7a4bb9b4b ability to use commands as usual functions diff -r a3feac00d151 -r ae36fb1b69a2 docs/overview.rst --- a/docs/overview.rst Thu Jul 23 16:52:29 2009 +0300 +++ b/docs/overview.rst Fri Jul 24 13:16:11 2009 +0300 @@ -55,8 +55,27 @@ function. This is done to comply with standarts of writing both console interfaces and Python application. -To make your application work, just call ``main()`` (it will parse -``sys.argv``). +After that you can simply call this function as an entry point to your program:: + + if __name__ == '__main__': + main() + +This will run command line parsing facility, using arguments from +``sys.argv``. ``%name`` will be replaced with ``sys.argv[0]`` (or prepended to +usage string if there is no ``%name``), and rest of arguments will be passed to +command line parser. In case if rest is empty, help will be displayed. + +Of course, you can use your function programmatically, supplying list of +arguments to function:: + + main('-l 0.0.0.0 /my/dir'.split()) + +Or, if you need this, you can call this function as usual:: + + main('/my/dir', listen='0.0.0.0') + +In this case no type conversion (which is done upon arguments parsing) will be +performed. Subcommands ----------- diff -r a3feac00d151 -r ae36fb1b69a2 finaloption.py --- a/finaloption.py Thu Jul 23 16:52:29 2009 +0300 +++ b/finaloption.py Fri Jul 24 13:16:11 2009 +0300 @@ -36,7 +36,11 @@ ''' def wrapper(func): # copy option list - options_ = list(options or guess_options(func)) + try: + options_ = list(options or guess_options(func)) + except TypeError: + # no options supplied and no options present in func + options_ = [] name_ = name or func.__name__ CMDTABLE[(shortlist and '^' or '') + name_] = ( @@ -48,24 +52,33 @@ name_ = name_[2:] return help_cmd(func, replace_name(usage, name_), options_) - def inner(args=None): + @wraps(func) + def inner(*arguments, **kwarguments): + # look if we need to add 'help' option try: (True for option in reversed(options_) if option[1] == 'help').next() except StopIteration: options_.append(('h', 'help', False, 'show help')) - args = args or sys.argv[1:] - if not args: - return help_func() + args = kwarguments.pop('args', None) + if arguments or kwarguments: + args, opts = arguments, kwarguments + else: + args = args or sys.argv[1:] + if not args: + return help_func() + try: + opts, args = catcher(lambda: parse(args, options_), + help_func) + except Abort: + return -1 try: - opts, args = catcher(lambda: parse(args, options_), help_func) if opts.pop('help', False): return help_func() - return catcher( - lambda: call_cmd(name_, func, *args, **opts), - help_func) + return catcher(lambda: call_cmd(name_, func, *args, **opts), + help_func) except Abort: return -1 @@ -419,6 +432,19 @@ return usage.replace('%name', name, 1) return name + ' ' + usage +try: + from functools import wraps +except ImportError: + def wraps(wrapped, assigned=('__module__', '__name__', '__doc__'), + updated=('__dict__',)): + def inner(wrapper): + for attr in assigned: + setattr(wrapper, attr, getattr(wrapped, attr)) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + return wrapper + return inner + # -------- # Exceptions # -------- diff -r a3feac00d151 -r ae36fb1b69a2 test_opts.py --- a/test_opts.py Thu Jul 23 16:52:29 2009 +0300 +++ b/test_opts.py Fri Jul 24 13:16:11 2009 +0300 @@ -25,7 +25,7 @@ pid_file=('', '', 'name of file to write process ID to')): '''Command with option declaration as keyword arguments - Otherwise it's the same as previons command + Otherwise it's the same as previous command ''' print locals()