summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/errors.py12
-rw-r--r--ipalib/public.py10
-rw-r--r--ipalib/tests/test_public.py37
3 files changed, 43 insertions, 16 deletions
diff --git a/ipalib/errors.py b/ipalib/errors.py
index 47e0a3ed..afc61dd8 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -64,11 +64,23 @@ class NormalizationError(ValidationError):
class RuleError(ValidationError):
+ """
+ Raised when a required option was not provided.
+ """
def __init__(self, name, value, rule, error):
self.rule = rule
ValidationError.__init__(self, name, value, error)
+class RequirementError(ValidationError):
+ """
+ Raised when a required option was not provided.
+ """
+ def __init__(self, name):
+ ValidationError.__init__(self, name, None,
+ 'missing required value'
+ )
+
class SetError(IPAError):
msg = 'setting %r, but NameSpace does not allow attribute setting'
diff --git a/ipalib/public.py b/ipalib/public.py
index 9677358f..4c085ba3 100644
--- a/ipalib/public.py
+++ b/ipalib/public.py
@@ -199,9 +199,13 @@ class cmd(plugable.Plugin):
def validate(self, **kw):
self.print_call('validate', kw, 1)
- for (key, value) in kw.items():
- if key in self.options:
- self.options[key].validate(value)
+ for opt in self.options:
+ value = kw.get(opt.name, None)
+ if value is None:
+ if opt.required:
+ raise errors.RequirementError(opt.name)
+ continue
+ opt.validate(value)
def execute(self, **kw):
self.print_call('execute', kw, 1)
diff --git a/ipalib/tests/test_public.py b/ipalib/tests/test_public.py
index eb19f28a..a331316d 100644
--- a/ipalib/tests/test_public.py
+++ b/ipalib/tests/test_public.py
@@ -177,7 +177,7 @@ class test_cmd(ClassChecker):
class option0(my_option):
pass
class option1(my_option):
- pass
+ required = True
class example(self.cls):
option_classes = (option0, option1)
return example
@@ -254,18 +254,30 @@ class test_cmd(ClassChecker):
Tests the `validate` method.
"""
assert 'validate' in self.cls.__public__ # Public
+
sub = self.subcls()
- for name in ('option0', 'option1'):
- okay = {
- name: name,
- 'another_option': 'some value',
- }
- fail = {
- name: 'whatever',
- 'another_option': 'some value',
- }
- sub.validate(**okay)
- raises(errors.RuleError, sub.validate, **fail)
+
+ # Check with valid args
+ okay = dict(
+ option0='option0',
+ option1='option1',
+ another_option='some value',
+ )
+ sub.validate(**okay)
+
+ # Check with an invalid arg
+ fail = dict(okay)
+ fail['option0'] = 'whatever'
+ raises(errors.RuleError, sub.validate, **fail)
+
+ # Check with a missing required arg
+ fail = dict(okay)
+ fail.pop('option1')
+ raises(errors.RequirementError, sub.validate, **fail)
+
+ # Check with missing *not* required arg
+ okay.pop('option0')
+ sub.validate(**okay)
def test_execute(self):
"""
@@ -274,7 +286,6 @@ class test_cmd(ClassChecker):
assert 'execute' in self.cls.__public__ # Public
-
def test_obj():
cls = public.obj
assert issubclass(cls, plugable.Plugin)