summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/errors.py20
-rw-r--r--ipalib/public.py30
-rw-r--r--ipalib/tests/test_public.py36
-rw-r--r--ipalib/tests/tstutil.py9
4 files changed, 93 insertions, 2 deletions
diff --git a/ipalib/errors.py b/ipalib/errors.py
index b86ffcdb..6b1a898a 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -45,6 +45,26 @@ class IPAError(Exception):
return self.msg % self.kw
+class ValidationError(IPAError):
+ msg = 'invalid %r value %r: %s'
+
+ def __init__(self, name, value, error):
+ self.name = name
+ self.value = value
+ self.error = error
+ super(ValidationError, self).__init__(name, value, error)
+
+class NormalizationError(ValidationError):
+ def __init__(self, name, value, type):
+ self.type = type
+ super(NormalizationError, self).__init__(name, value,
+ 'not %r' % type
+ )
+
+
+
+class ValidationRuleError(ValidationError):
+ msg = '%r is invalid %r: %s'
diff --git a/ipalib/public.py b/ipalib/public.py
index e6cd278a..5806d0eb 100644
--- a/ipalib/public.py
+++ b/ipalib/public.py
@@ -24,10 +24,35 @@ and UI all use.
import re
import plugable
+import errors
+
+
+class opt(plugable.ReadOnly):
+ __public__ = frozenset((
+ 'normalize',
+ 'validate',
+ 'default',
+ 'required',
+ 'type',
+ ))
+
+ def normalize(self, value):
+ try:
+ return self.type(value)
+ except (TypeError, ValueError):
+ raise errors.NormalizationError(
+ self.__class__.__name__, value, self.type
+ )
+
+
+
+
class cmd(plugable.Plugin):
__public__ = frozenset((
+ 'normalize',
+ 'autofill',
'__call__',
'get_doc',
'opt',
@@ -63,7 +88,10 @@ class cmd(plugable.Plugin):
opt = property(__get_opt)
def __call__(self, *args, **kw):
- print repr(self)
+ (args, kw) = self.normalize(*args, **kw)
+ (args, kw) = self.autofill(*args, **kw)
+ self.validate(*args, **kw)
+
class obj(plugable.Plugin):
diff --git a/ipalib/tests/test_public.py b/ipalib/tests/test_public.py
index 0985658e..faffd02e 100644
--- a/ipalib/tests/test_public.py
+++ b/ipalib/tests/test_public.py
@@ -25,6 +25,41 @@ from tstutil import raises, getitem, no_set, no_del, read_only
from ipalib import public, plugable, errors
+def test_opt():
+ cls = public.opt
+ assert issubclass(cls, plugable.ReadOnly)
+
+ class int_opt(cls):
+ type = int
+
+ i = int_opt()
+
+ # Test with values that can't be converted:
+ nope = (
+ '7.0'
+ 'whatever',
+ object,
+ None,
+ )
+ for val in nope:
+ e = raises(errors.NormalizationError, i.normalize, val)
+ assert isinstance(e, errors.ValidationError)
+ assert e.name == 'int_opt'
+ assert e.value == val
+ assert e.error == "not <type 'int'>"
+ assert e.type is int
+ # Test with values that can be converted:
+ okay = (
+ 7,
+ 7.0,
+ 7.2,
+ 7L,
+ '7',
+ ' 7 ',
+ )
+ for val in okay:
+ assert i.normalize(val) == 7
+
def test_cmd():
cls = public.cmd
assert issubclass(cls, plugable.Plugin)
@@ -35,6 +70,7 @@ def test_obj():
assert issubclass(cls, plugable.Plugin)
+
def test_attr():
cls = public.attr
assert issubclass(cls, plugable.Plugin)
diff --git a/ipalib/tests/tstutil.py b/ipalib/tests/tstutil.py
index 12ca119d..cdac4547 100644
--- a/ipalib/tests/tstutil.py
+++ b/ipalib/tests/tstutil.py
@@ -43,10 +43,11 @@ def raises(exception, callback, *args, **kw):
raised = False
try:
callback(*args, **kw)
- except exception:
+ except exception, e:
raised = True
if not raised:
raise ExceptionNotRaised(exception)
+ return e
def getitem(obj, key):
@@ -83,3 +84,9 @@ def read_only(obj, name, value='some_new_obj'):
# Return the attribute
return getattr(obj, name)
+
+
+class ClassChecker(object):
+
+ def new(self, *args, **kw):
+ return self.cls(*args, **kw)