From 0327b83899389e38aebde9de4219f64a716e611d Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 20:36:17 -0700 Subject: New Param: all docstring examples now pass under doctests --- ipalib/__init__.py | 28 ++++++++++++++-------------- ipalib/frontend.py | 30 ++++++++++++++++-------------- ipalib/parameters.py | 26 ++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 30 deletions(-) (limited to 'ipalib') diff --git a/ipalib/__init__.py b/ipalib/__init__.py index cf2e5a6ac..40d3a744c 100644 --- a/ipalib/__init__.py +++ b/ipalib/__init__.py @@ -405,13 +405,13 @@ Defining arguments and options for your command You can define a command that will accept specific arguments and options. For example: ->>> from ipalib import Param +>>> from ipalib import Str >>> class nudge(Command): ... """Takes one argument, one option""" ... ... takes_args = ['programmer'] ... -... takes_options = [Param('stuff', default=u'documentation')] +... takes_options = [Str('stuff', default=u'documentation')] ... ... def execute(self, programmer, **kw): ... return '%s, go write more %s!' % (programmer, kw['stuff']) @@ -420,9 +420,9 @@ For example: >>> api.env.in_server = True >>> api.register(nudge) >>> api.finalize() ->>> api.Command.nudge('Jason') +>>> api.Command.nudge(u'Jason') u'Jason, go write more documentation!' ->>> api.Command.nudge('Jason', stuff='unit tests') +>>> api.Command.nudge(u'Jason', stuff=u'unit tests') u'Jason, go write more unit tests!' The ``args`` and ``options`` attributes are `plugable.NameSpace` instances @@ -431,11 +431,11 @@ containing a command's arguments and options, respectively, as you can see: >>> list(api.Command.nudge.args) # Iterates through argument names ['programmer'] >>> api.Command.nudge.args.programmer -Param('programmer') +Str('programmer') >>> list(api.Command.nudge.options) # Iterates through option names ['stuff'] >>> api.Command.nudge.options.stuff -Param('stuff', default=u'documentation') +Str('stuff', default=u'documentation') >>> api.Command.nudge.options.stuff.default u'documentation' @@ -451,7 +451,7 @@ NameSpace(<2 members>, sort=False) When calling a command, its positional arguments can also be provided as keyword arguments, and in any order. For example: ->>> api.Command.nudge(stuff='lines of code', programmer='Jason') +>>> api.Command.nudge(stuff=u'lines of code', programmer=u'Jason') u'Jason, go write more lines of code!' When a command plugin is called, the values supplied for its parameters are @@ -465,20 +465,20 @@ here is a quick teaser: ... takes_options = [ ... 'first', ... 'last', -... Param('nick', -... normalize=lambda value: value.lower(), +... Str('nick', +... normalizer=lambda value: value.lower(), ... default_from=lambda first, last: first[0] + last, ... ), -... Param('points', type=Int(), default=0), +... Int('points', default=0), ... ] ... >>> cp = create_player() >>> cp.finalize() ->>> cp.convert(points=" 1000 ") +>>> cp.convert(points=u' 1000 ') {'points': 1000} >>> cp.normalize(nick=u'NickName') {'nick': u'nickname'} ->>> cp.get_default(first='Jason', last='DeRose') +>>> cp.get_default(first=u'Jason', last=u'DeRose') {'nick': u'jderose', 'points': 0} For the full details on the parameter system, see the @@ -575,7 +575,7 @@ For example, say we setup a command like this: ... ... takes_args = ['key?'] ... -... takes_options = [Param('reverse', type=Bool(), default=False)] +... takes_options = [Flag('reverse')] ... ... def execute(self, key, **options): ... items = dict( @@ -643,7 +643,7 @@ show-items: Lastly, providing a ``key`` would result in the following: ->>> result = api.Command.show_items('city') +>>> result = api.Command.show_items(u'city') >>> api.Command.show_items.output_for_cli(textui, result, 'city', reverse=False) city = 'Berlin' diff --git a/ipalib/frontend.py b/ipalib/frontend.py index 98ecc46b1..b30205fe8 100644 --- a/ipalib/frontend.py +++ b/ipalib/frontend.py @@ -27,8 +27,7 @@ import plugable from plugable import lock, check_name import errors from errors import check_type, check_isinstance, raise_TypeError -import parameters -from parameters import create_param, Param +from parameters import create_param, Param, Str, Flag from util import make_repr @@ -53,7 +52,8 @@ class Command(plugable.Plugin): Plugins that subclass from Command are registered in the ``api.Command`` namespace. For example: - >>> api = plugable.API(Command) + >>> from ipalib import create_api + >>> api = create_api() >>> class my_command(Command): ... pass ... @@ -161,14 +161,14 @@ class Command(plugable.Plugin): >>> class my_command(Command): ... takes_options = ( - ... Param('first', normalize=lambda value: value.lower()), + ... Param('first', normalizer=lambda value: value.lower()), ... Param('last'), ... ) ... >>> c = my_command() >>> c.finalize() - >>> c.normalize(first='JOHN', last='DOE') - {'last': 'DOE', 'first': 'john'} + >>> c.normalize(first=u'JOHN', last=u'DOE') + {'last': u'DOE', 'first': u'john'} """ return dict( (k, self.params[k].normalize(v)) for (k, v) in kw.iteritems() @@ -178,10 +178,10 @@ class Command(plugable.Plugin): """ Return a dictionary of values converted to correct type. - >>> from ipalib import ipa_types + >>> from ipalib import Int >>> class my_command(Command): ... takes_args = ( - ... Param('one', type=ipa_types.Int()), + ... Int('one'), ... 'two', ... ) ... @@ -200,14 +200,15 @@ class Command(plugable.Plugin): For example: + >>> from ipalib import Str >>> class my_command(Command): - ... takes_args = [Param('color', default='Red')] + ... takes_args = [Str('color', default=u'Red')] ... >>> c = my_command() >>> c.finalize() >>> c.get_default() - {'color': 'Red'} - >>> c.get_default(color='Yellow') + {'color': u'Red'} + >>> c.get_default(color=u'Yellow') {} """ return dict(self.__get_default_iter(kw)) @@ -363,7 +364,7 @@ class LocalOrRemote(Command): """ takes_options = ( - parameters.Flag('server?', + Flag('server?', doc='Forward to server instead of running locally', ), ) @@ -562,7 +563,8 @@ class Method(Attribute, Command): say you created a `Method` plugin and its corresponding `Object` plugin like this: - >>> api = plugable.API(Command, Object, Method, Property) + >>> from ipalib import create_api + >>> api = create_api() >>> class user_add(Method): ... def run(self): ... return 'Added the user!' @@ -617,7 +619,7 @@ class Property(Attribute): 'type', )).union(Attribute.__public__) - klass = parameters.Str + klass = Str default = None default_from = None normalizer = None diff --git a/ipalib/parameters.py b/ipalib/parameters.py index ff088ff80..cf658a412 100644 --- a/ipalib/parameters.py +++ b/ipalib/parameters.py @@ -490,6 +490,7 @@ class Param(ReadOnly): :param value: A proposed value for this parameter. """ + # FIXME: this should be after 'if value is None:' if self.query: return if value is None: @@ -695,7 +696,28 @@ class Flag(Bool): super(Flag, self).__init__(name, *rules, **kw) -class Int(Param): +class Number(Param): + """ + Base class for the `Int` and `Float` parameters. + """ + + def _convert_scalar(self, value, index=None): + """ + Convert a single scalar value. + """ + if type(value) is self.type: + return value + if type(value) in (unicode, int, float): + try: + return self.type(value) + except ValueError: + pass + raise ConversionError(name=self.name, index=index, + error=ugettext(self.type_error), + ) + + +class Int(Number): """ A parameter for integer values (stored in the ``int`` type). """ @@ -704,7 +726,7 @@ class Int(Param): type_error = _('must be an integer') -class Float(Param): +class Float(Number): """ A parameter for floating-point values (stored in the ``float`` type). """ -- cgit