Skip to content
Browse files

Merge remote-tracking branch 'origin/unicode-option' into unicode-option

  • Loading branch information...
2 parents 4c8b869 + 9f642ab commit c9fac21fa78bd59b5823d78e68dcf64baf585f48 @oscarbenjamin committed May 29, 2012
Showing with 97 additions and 14 deletions.
  1. +2 −0 docs/overview.rst
  2. +26 −5 opster.py
  3. +54 −2 tests/opster.t
  4. +13 −5 tests/quit.py
  5. +2 −2 tests/subcmds.py
View
2 docs/overview.rst
@@ -57,6 +57,8 @@ the option should be parsed:
- boolean/None: ``not default`` is passed and option takes no value
- function: function is called with value and the return value is used
- list: the value is appended to this list
+- tuple: value is checked to be present in default value (i.e. tuple behaves
+ as a list of choices)
- dictionary: the value is then assumed to be in the format ``key=value`` and
is then assigned to this dictionary, :ref:`example <definitions-test>`
View
31 opster.py
@@ -206,9 +206,8 @@ def inner(*args, **opts):
return wrapper
- def add_dispatcher(self, name, dispatcher, help,
- hide=False, shortlist=False):
- '''Add another dispatcher as a subcommand'''
+ def nest(self, name, dispatcher, help, hide=False, shortlist=False):
+ '''Add another dispatcher as a subcommand.'''
dispatcher.__doc__ = help
prefix = hide and '~' or (shortlist and '^' or '')
self._cmdtable[prefix + name] = dispatcher, [], None
@@ -447,8 +446,8 @@ def Option(opt):
# Find matching _Option subclass and return instance
# nb. the order of testing matters
- for Type in (BoolOption, ListOption, DictOption,
- FuncOption, UnicodeOption, LiteralOption):
+ for Type in (BoolOption, ListOption, DictOption, FuncOption,
+ TupleOption, UnicodeOption, LiteralOption):
if Type.matches(default):
return Type(*args)
raise OpsterError('Cannot figure out type for option %s' % name)
@@ -553,6 +552,28 @@ def update_state(self, state, new):
return state
+class TupleOption(BaseOption):
+ '''Tuple option type.'''
+ type = tuple
+
+ def __init__(self, *args, **kwargs):
+ self._option = Option(('', '_', self.default[0], ''))
+
+ def default_state(self):
+ return self._option.default
+
+ def update_state(self, state, new):
+ return self._option.update_state(state, new)
+
+ def convert(self, final):
+ finalval = self._option.convert(final)
+ if finalval not in self.default:
+ msg = "unrecognised value: %r (should be one of %s)"
+ msg = msg % (final, ', '.join(str(v) for v in self.default))
+ raise getopt.GetoptError(msg)
+ return finalval
+
+
class FuncOption(BaseOption):
'''Function option type.'''
type = Callable
View
56 tests/opster.t
@@ -374,12 +374,64 @@ keyword argument 'option'``::
$ run multivalueserr.py some arguments hehe
I work! False bopt some arguments ('hehe',)
-Scripts can exit with an error message at any time by raising
+Opster can give helpful error messages if arguments are invalid::
+
+ $ run quit.py --help
+ quit.py [OPTIONS]
+
+ script that uses different algorithms and numbers of cpus
+
+ options:
+
+ -a --algo1 algorithm: slow or fast (default: fast)
+ -A --algo2 algorithm: slow or fast (default: slow)
+ -n --ncpus number of cpus to use (default: 1)
+ -h --help display help
+
+Scripts can exit with a user-defined error message at any time by raising
``command.Error``::
- $ run quit.py --algorithm=quick
+ $ run quit.py --algo1=quick
unrecognised algorithm "quick"
+Or arguments can be rejected because they are not in a tuple::
+
+ $ run quit.py --algo2=quick
+ error: unrecognised value: 'quick' (should be one of slow, fast)
+
+ quit.py [OPTIONS]
+
+ script that uses different algorithms and numbers of cpus
+
+ options:
+
+ -a --algo1 algorithm: slow or fast (default: fast)
+ -A --algo2 algorithm: slow or fast (default: slow)
+ -n --ncpus number of cpus to use (default: 1)
+ -h --help display help
+
+ $ run quit.py --ncpus=-1
+ error: unrecognised value: '-1' (should be one of 1, 2, 3, 4)
+
+ quit.py [OPTIONS]
+
+ script that uses different algorithms and numbers of cpus
+
+ options:
+
+ -a --algo1 algorithm: slow or fast (default: fast)
+ -A --algo2 algorithm: slow or fast (default: slow)
+ -n --ncpus number of cpus to use (default: 1)
+ -h --help display help
+
+Just check that the tuple options work when there's no error::
+
+ $ run quit.py --algo1=fast --algo2=slow --ncpus=3
+ algo1: fast
+ algo2: slow
+ ncpus: 3
+
+
That's all for today; see you next time!
.. _varargs:
View
18 tests/quit.py
@@ -1,13 +1,21 @@
+from __future__ import print_function
from opster import command
+NMAX = 4
+ALGOS = ('slow', 'fast')
+
@command()
-def main(algorithm=('a', 'fast', 'algorithm: slow or fast')):
+def main(algo1=('a', 'fast', 'algorithm: slow or fast'),
+ algo2=('A', ALGOS, 'algorithm: slow or fast'),
+ ncpus=('n', tuple(range(1, NMAX+1)), 'number of cpus to use')):
'''
- script that uses two possible algorithms.
+ script that uses different algorithms and numbers of cpus
'''
- if algorithm not in ('short', 'fast'):
- raise command.Error('unrecognised algorithm "{0}"'.format(algorithm))
- pass
+ if algo1 not in ALGOS:
+ raise command.Error('unrecognised algorithm "{0}"'.format(algo1))
+ print('algo1:', algo1)
+ print('algo2:', algo2)
+ print('ncpus:', ncpus)
if __name__ == "__main__":
main.command()
View
4 tests/subcmds.py
@@ -39,8 +39,8 @@ def subsubcmd(loud=('l', False, 'loudly'),
print('Showing the help:')
subsubcmd.help()
-d2.add_dispatcher('subcmd3', d3, 'Help for subcmd3')
-d.add_dispatcher('cmd', d2, 'Help for cmd')
+d2.nest('subcmd3', d3, 'Help for subcmd3')
+d.nest('cmd', d2, 'Help for cmd')
if __name__ == '__main__':
d.dispatch()

0 comments on commit c9fac21

Please sign in to comment.
Something went wrong with that request. Please try again.