--- a/docs/overview.rst Wed Jan 05 20:17:20 2011 +0100
+++ b/docs/overview.rst Wed Jan 05 20:41:43 2011 +0100
@@ -34,6 +34,8 @@
- integer: value is convert to integer
- string: value is passed as is
- list: value is appended to this list
+ - dictionary: value is then assumed being in format ``key=value`` and is
+ then assigned to this dictionary
- boolean/None: ``not default`` is passed and option takes no value
Usage
--- a/opster.py Wed Jan 05 20:17:20 2011 +0100
+++ b/opster.py Wed Jan 05 20:41:43 2011 +0100
@@ -2,7 +2,7 @@
'''Command line arguments parser
'''
-import sys, traceback, getopt, types, textwrap, inspect, os
+import sys, traceback, getopt, types, textwrap, inspect, os, copy
from itertools import imap
__all__ = ['command', 'dispatch']
@@ -192,11 +192,7 @@
write('\ncommands:\n\n')
for cmd in hlplist:
doc = hlp[cmd]
- if False: # verbose?
- write(' %s:\n %s\n' % (cmd.replace('|', ', '), doc))
- else:
- write(' %-*s %s\n' % (maxlen, cmd.split('|', 1)[0],
- doc))
+ write(' %-*s %s\n' % (maxlen, cmd.split('|', 1)[0], doc))
if not cmdtable:
return err('No commands specified!\n')
@@ -251,6 +247,8 @@
write(''.join(help_options(options)))
def help_options(options):
+ '''Generator for help on options
+ '''
yield 'options:\n\n'
output = []
for o in options:
@@ -309,8 +307,8 @@
defmap[pyname] = default
# copy defaults to state
- if isinstance(default, list):
- state[pyname] = default[:]
+ if isinstance(default, (list, dict)):
+ state[pyname] = copy.copy(default)
elif hasattr(default, '__call__'):
funlist.append(pyname)
state[pyname] = None
@@ -319,8 +317,10 @@
# getopt wants indication that it takes a parameter
if not (default is None or default is True or default is False):
- if short: short += ':'
- if name: name += '='
+ if short:
+ short += ':'
+ if name:
+ name += '='
if short:
shortlist += short
if name:
@@ -335,8 +335,15 @@
if t is types.FunctionType:
del funlist[funlist.index(name)]
state[name] = defmap[name](val)
- elif t is types.ListType:
+ elif t is list:
state[name].append(val)
+ elif t is dict:
+ try:
+ k, v = val.split('=')
+ except ValueError:
+ raise ParseError(name, "wrong definition: '%s' "
+ "(should be in format KEY=VALUE)" % val)
+ state[name][k] = v
elif t in (types.NoneType, types.BooleanType):
state[name] = not defmap[name]
else:
@@ -470,7 +477,7 @@
(e.args[0], ' '.join(e.args[1])))
raise Abort()
except ParseError, e:
- err('%s: %s\n' % (e.args[0], e.args[1]))
+ err('%s: %s\n\n' % (e.args[0], e.args[1].strip()))
help_func(e.args[0])
raise Abort()
except getopt.GetoptError, e:
@@ -496,6 +503,8 @@
return inner
def call_cmd_regular(func, opts):
+ '''Wrapper for command for handling function calls from Python
+ '''
def inner(*args, **kwargs):
funcargs, _, varkw, defaults = inspect.getargspec(func)
if len(args) > len(funcargs):
--- a/tests/opster.t Wed Jan 05 20:17:20 2011 +0100
+++ b/tests/opster.t Wed Jan 05 20:41:43 2011 +0100
@@ -79,30 +79,61 @@
$ run test_opts.py
another: invalid arguments
+
test_opts.py [-l HOST] DIR
Command with option declaration as keyword arguments
options:
- -l --listen ip to listen on (default: localhost)
- -p --port port to listen on (default: 8000)
- -d --daemonize daemonize process
- --pid-file name of file to write process ID to
- -t --test testing help for a function (default: test)
- -h --help show help
+ -l --listen ip to listen on (default: localhost)
+ -p --port port to listen on (default: 8000)
+ -d --daemonize daemonize process
+ --pid-file name of file to write process ID to
+ -D --definitions just some definitions
+ -t --test testing help for a function (default: test)
+ -h --help show help
-Yeah, I've got it, I should supply some argument::
+Yeah, I've got it, I should supply some arguments::
- $ run test_opts.py right-here
+ $ run test_opts.py -d -p 5656 --listen anywhere right-here
+ {'daemonize': True,
+ 'definitions': {},
+ 'dirname': 'right-here',
+ 'listen': 'anywhere',
+ 'pid_file': '',
+ 'port': 5656,
+ 'test': 'test'}
+
+Now let's test our definitions::
+
+ $ run test_opts.py -D a=b so-what?
{'daemonize': False,
- 'dirname': 'right-here',
+ 'definitions': {'a': 'b'},
+ 'dirname': 'so-what?',
'listen': 'localhost',
'pid_file': '',
'port': 8000,
'test': 'test'}
+ $ run test_opts.py -D can-i-haz fail?
+ definitions: wrong definition: 'can-i-haz' (should be in format KEY=VALUE)
+
+ test_opts.py [-l HOST] DIR
+
+ Command with option declaration as keyword arguments
+
+ options:
+
+ -l --listen ip to listen on (default: localhost)
+ -p --port port to listen on (default: 8000)
+ -d --daemonize daemonize process
+ --pid-file name of file to write process ID to
+ -D --definitions just some definitions
+ -t --test testing help for a function (default: test)
+ -h --help show help
+
Should we check passing some invalid arguments? I think so::
@@ -115,12 +146,13 @@
options:
- -l --listen ip to listen on (default: localhost)
- -p --port port to listen on (default: 8000)
- -d --daemonize daemonize process
- --pid-file name of file to write process ID to
- -t --test testing help for a function (default: test)
- -h --help show help
+ -l --listen ip to listen on (default: localhost)
+ -p --port port to listen on (default: 8000)
+ -d --daemonize daemonize process
+ --pid-file name of file to write process ID to
+ -D --definitions just some definitions
+ -t --test testing help for a function (default: test)
+ -h --help show help
That's all for today; see you next time!
--- a/tests/test_opts.py Wed Jan 05 20:17:20 2011 +0100
+++ b/tests/test_opts.py Wed Jan 05 20:41:43 2011 +0100
@@ -7,6 +7,7 @@
port=('p', 8000, 'port to listen on'),
daemonize=('d', False, 'daemonize process'),
pid_file=('', '', 'name of file to write process ID to'),
+ definitions=('D', {}, 'just some definitions'),
test=('t', lambda x: x or 'test', 'testing help for a function')):
'''Command with option declaration as keyword arguments
'''