mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2026-07-29 23:58:23 -05:00
New Param: added basic rule logic
This commit is contained in:
+49
-6
@@ -183,9 +183,9 @@ class Param(ReadOnly):
|
||||
"""
|
||||
|
||||
# This is a dummy type so that most of the functionality of Param can be
|
||||
# unit tested directly without always creating a subclass; however, real
|
||||
# (direct) subclasses should *always* override this class attribute:
|
||||
type = NoneType # This isn't very useful in the real world!
|
||||
# unit tested directly without always creating a subclass; however, a real
|
||||
# (direct) subclass must *always* override this class attribute:
|
||||
type = NoneType # Ouch, this wont be very useful in the real world!
|
||||
|
||||
kwargs = (
|
||||
('cli_name', str, None),
|
||||
@@ -201,7 +201,7 @@ class Param(ReadOnly):
|
||||
# ('default', self.type, None),
|
||||
)
|
||||
|
||||
def __init__(self, name, **kw):
|
||||
def __init__(self, name, *rules, **kw):
|
||||
# We keep these values to use in __repr__():
|
||||
self.param_spec = name
|
||||
self.__kw = dict(kw)
|
||||
@@ -233,10 +233,11 @@ class Param(ReadOnly):
|
||||
if callable(df) and not isinstance(df, DefaultFrom):
|
||||
kw['default_from'] = DefaultFrom(df)
|
||||
|
||||
# Keep the copy with merged values also to use when cloning:
|
||||
# We keep this copy with merged values also to use when cloning:
|
||||
self.__clonekw = kw
|
||||
|
||||
# Perform type validation on kw:
|
||||
# Perform type validation on kw, add in class rules:
|
||||
class_rules = []
|
||||
for (key, kind, default) in self.kwargs:
|
||||
value = kw.get(key, default)
|
||||
if value is not None:
|
||||
@@ -262,7 +263,20 @@ class Param(ReadOnly):
|
||||
key, self.__class__.__name__)
|
||||
)
|
||||
setattr(self, key, value)
|
||||
rule_name = 'rule_%s' % key
|
||||
if value is not None and hasattr(self, rule_name):
|
||||
class_rules.append(getattr(self, rule_name))
|
||||
check_name(self.cli_name)
|
||||
|
||||
# Check that all the rules are callable
|
||||
self.rules = tuple(class_rules) + rules
|
||||
for rule in self.rules:
|
||||
if not callable(rule):
|
||||
raise TypeError(
|
||||
'%s: rules must be callable; got %r' % (self.nice, rule)
|
||||
)
|
||||
|
||||
# And we're done.
|
||||
lock(self)
|
||||
|
||||
def normalize(self, value):
|
||||
@@ -401,6 +415,35 @@ class Bytes(Param):
|
||||
self.nice, self.minlength)
|
||||
)
|
||||
|
||||
def rule_minlength(self, value):
|
||||
"""
|
||||
Check minlength constraint.
|
||||
"""
|
||||
if len(value) < self.minlength:
|
||||
return 'Must be at least %(minlength)d bytes long.' % dict(
|
||||
minlength=self.minlength,
|
||||
)
|
||||
|
||||
def rule_maxlength(self, value):
|
||||
"""
|
||||
Check maxlength constraint.
|
||||
"""
|
||||
if len(value) > self.maxlength:
|
||||
return 'Can be at most %(maxlength)d bytes long.' % dict(
|
||||
maxlength=self.maxlength,
|
||||
)
|
||||
|
||||
def rule_length(self, value):
|
||||
"""
|
||||
Check length constraint.
|
||||
"""
|
||||
if len(value) != self.length:
|
||||
return 'Must be exactly %(length)d bytes long.' % dict(
|
||||
length=self.length,
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
class Str(Bytes):
|
||||
"""
|
||||
|
||||
@@ -92,7 +92,7 @@ def test_parse_param_spec():
|
||||
assert f('name?') == ('name', dict(required=False, multivalue=False))
|
||||
assert f('name*') == ('name', dict(required=False, multivalue=True))
|
||||
assert f('name+') == ('name', dict(required=True, multivalue=True))
|
||||
# Make sure other "funny" endings are treated special:
|
||||
# Make sure other "funny" endings are *not* treated special:
|
||||
assert f('name^') == ('name^', dict(required=True, multivalue=False))
|
||||
|
||||
|
||||
@@ -111,6 +111,9 @@ class test_Param(ClassChecker):
|
||||
assert o.name is name
|
||||
assert o.__islocked__() is True
|
||||
|
||||
# Test default rules:
|
||||
assert o.rules == tuple()
|
||||
|
||||
# Test default kwarg values:
|
||||
assert o.cli_name is name
|
||||
assert o.doc == ''
|
||||
@@ -118,7 +121,7 @@ class test_Param(ClassChecker):
|
||||
assert o.multivalue is False
|
||||
assert o.primary_key is False
|
||||
assert o.normalizer is None
|
||||
#assert o.default is None
|
||||
assert o.default is None
|
||||
assert o.default_from is None
|
||||
assert o.flags == frozenset()
|
||||
|
||||
@@ -190,6 +193,7 @@ class test_Bytes(ClassChecker):
|
||||
"""
|
||||
o = self.cls('my_bytes')
|
||||
assert o.type is str
|
||||
assert o.rules == tuple()
|
||||
assert o.minlength is None
|
||||
assert o.maxlength is None
|
||||
assert o.length is None
|
||||
@@ -198,6 +202,7 @@ class test_Bytes(ClassChecker):
|
||||
# Test mixing length with minlength or maxlength:
|
||||
o = self.cls('my_bytes', length=5)
|
||||
assert o.length == 5
|
||||
assert len(o.rules) == 1
|
||||
permutations = [
|
||||
dict(minlength=3),
|
||||
dict(maxlength=7),
|
||||
@@ -205,6 +210,7 @@ class test_Bytes(ClassChecker):
|
||||
]
|
||||
for kw in permutations:
|
||||
o = self.cls('my_bytes', **kw)
|
||||
assert len(o.rules) == len(kw)
|
||||
for (key, value) in kw.iteritems():
|
||||
assert getattr(o, key) == value
|
||||
e = raises(ValueError, self.cls, 'my_bytes', length=5, **kw)
|
||||
|
||||
Reference in New Issue
Block a user