From 9ee10d383dc03649c3358ab7a296872fac528ada Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 8 Aug 2008 04:47:42 +0000 Subject: [PATCH] 78: Renamed opt to option; started fleshing out cmd more --- ipalib/public.py | 47 +++++++++++++++++++++++++++++++++---- ipalib/tests/test_public.py | 21 +++++++++-------- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/ipalib/public.py b/ipalib/public.py index 2c5d31ae1..f6bad7ec9 100644 --- a/ipalib/public.py +++ b/ipalib/public.py @@ -38,7 +38,7 @@ def is_rule(obj): return callable(obj) and getattr(obj, RULE_FLAG, False) is True -class opt(plugable.ReadOnly): +class option(object): __public__ = frozenset(( 'normalize', 'validate', @@ -49,6 +49,14 @@ class opt(plugable.ReadOnly): __rules = None def normalize(self, value): + """ + Normalize an input value. The base class implementation only does + type coercion, but subclasses might do other normalization (e.g., a + str option might strip leading and trailing white-space). + + If value cannot be normalized, NormalizationError is raised, which + is a subclass of ValidationError. + """ try: return self.type(value) except (TypeError, ValueError): @@ -57,16 +65,23 @@ class opt(plugable.ReadOnly): ) def __get_rules(self): + """ + Returns the tuple of rule methods used for input validation. This + tuple is lazily initialized the first time the property is accessed. + """ if self.__rules is None: - rules = sorted( + self.__rules = tuple(sorted( self.__rules_iter(), key=lambda f: getattr(f, '__name__'), - ) - object.__setattr__(self, '_opt__rules', tuple(rules)) + )) return self.__rules rules = property(__get_rules) def __rules_iter(self): + """ + Iterates through the attributes in this instance to retrieve the + methods implemented validation rules. + """ for name in dir(self.__class__): if name.startswith('_'): continue @@ -131,7 +146,29 @@ class cmd(plugable.Plugin): return self.__opt opt = property(__get_opt) - def __call__(self, *args, **kw): + + def normalize_iter(self, kw): + for (key, value) in kw.items(): + if key in self.options: + yield ( + key, self.options[key].normalize(value) + ) + else: + yield (key, value) + + def normalize(self, **kw): + return dict(self.normalize_iter(kw)) + + def validate(self, **kw): + for (key, value) in kw.items(): + if key in self.options: + self.options.validate(value) + + + + + + def __call__(self, **kw): (args, kw) = self.normalize(*args, **kw) (args, kw) = self.autofill(*args, **kw) self.validate(*args, **kw) diff --git a/ipalib/tests/test_public.py b/ipalib/tests/test_public.py index 57cb2a77f..3ef7ad087 100644 --- a/ipalib/tests/test_public.py +++ b/ipalib/tests/test_public.py @@ -63,9 +63,9 @@ def test_is_rule(): assert not is_rule(call(None)) -class test_opt(): +class test_option(): def cls(self): - return public.opt + return public.option def sub(self): rule = public.rule @@ -85,11 +85,20 @@ class test_opt(): return 'cannot be 2' return int_opt + def test_class(self): + """ + Perform some tests on the class (not an instance). + """ + cls = self.cls() + #assert issubclass(cls, plugable.ReadOnly) + assert type(cls.rules) is property + def test_rules(self): """ Test the rules property. """ o = self.sub()() + assert len(o.rules) == 3 def get_rule(i): return getattr(o, 'rule_%d' % i) rules = tuple(get_rule(i) for i in xrange(3)) @@ -105,14 +114,6 @@ class test_opt(): e = raises(errors.RuleError, o.validate, i) assert e.error == 'cannot be %d' % i - - - - - def test_class(self): - cls = self.cls() - assert issubclass(cls, plugable.ReadOnly) - def test_normalize(self): sub = self.sub()