New Param: added all logic for minlength, maxlength, and length in Bytes class (which Str inherits)

This commit is contained in:
Jason Gerard DeRose
2008-12-12 03:13:58 -07:00
parent 079721da2c
commit 5272949bfd
2 changed files with 112 additions and 15 deletions

View File

@@ -203,19 +203,27 @@ class Param(ReadOnly):
def __init__(self, name, **kw):
assert type(self.type) is type
self.kwargs += (('default', self.type, None),)
self.param_spec = name
self.__kw = dict(kw)
if not ('required' in kw or 'multivalue' in kw):
(name, kw_from_spec) = parse_param_spec(name)
kw.update(kw_from_spec)
self.name = check_name(name)
self.nice = '%s(%r)' % (self.__class__.__name__, self.name)
if not set(t[0] for t in self.kwargs).issuperset(self.__kw):
extra = set(kw) - set(t[0] for t in self.kwargs)
raise TypeError(
'%s: no such kwargs: %s' % (self.nice,
', '.join(repr(k) for k in sorted(extra))
)
)
if kw.get('cli_name', None) is None:
kw['cli_name'] = self.name
df = kw.get('default_from', None)
if callable(df) and not isinstance(df, DefaultFrom):
kw['default_from'] = DefaultFrom(df)
self.__clonekw = kw
self.kwargs += (('default', self.type, None),)
for (key, kind, default) in self.kwargs:
value = kw.get(key, default)
if value is not None:
@@ -245,14 +253,12 @@ class Param(ReadOnly):
For example:
>>> param = Str('telephone',
>>> param = Param('telephone',
... normalizer=lambda value: value.replace('.', '-')
... )
>>> param.normalize(u'800.123.4567')
u'800-123-4567'
(Note that `Str` is a subclass of `Param`.)
If this `Param` instance was created with a normalizer callback and
``value`` is a unicode instance, the normalizer callback is called and
*its* return value is returned.
@@ -293,8 +299,8 @@ class Param(ReadOnly):
if self.multivalue:
if type(value) in (tuple, list):
values = filter(
lambda val: val not in NULLS,
(self._convert_scalar(v, i) for (i, v) in enumerate(value))
lambda val: val not in NULLS,
(self._convert_scalar(v, i) for (i, v) in enumerate(value))
)
if len(values) == 0:
return
@@ -336,23 +342,59 @@ class Bytes(Param):
type = str
kwargs = Param.kwargs + (
('minlength', int, None),
('maxlength', int, None),
('length', int, None),
('pattern', str, None),
)
def __init__(self, name, **kw):
kwargs = dict(
minlength=(int, None),
maxlength=(int, None),
length=(int, None),
pattern=(str, None),
)
super(Bytes, self).__init__(name, **kw)
if not (
self.length is None or
(self.minlength is None and self.maxlength is None)
):
raise ValueError(
'%s: cannot mix length with minlength or maxlength' % self.nice
)
if self.minlength is not None and self.minlength < 1:
raise ValueError(
'%s: minlength must be >= 1; got %r' % (self.nice, self.minlength)
)
if self.maxlength is not None and self.maxlength < 1:
raise ValueError(
'%s: maxlength must be >= 1; got %r' % (self.nice, self.maxlength)
)
if None not in (self.minlength, self.maxlength):
if self.minlength > self.maxlength:
raise ValueError(
'%s: minlength > maxlength (minlength=%r, maxlength=%r)' % (
self.nice, self.minlength, self.maxlength)
)
elif self.minlength == self.maxlength:
raise ValueError(
'%s: minlength == maxlength; use length=%d instead' % (
self.nice, self.minlength)
)
class Str(Param):
class Str(Bytes):
"""
"""
type = unicode
kwargs = Bytes.kwargs[:-1] + (
('pattern', unicode, None),
)
def __init__(self, name, **kw):
super(Str, self).__init__(name, **kw)

View File

@@ -149,11 +149,12 @@ class test_Param(ClassChecker):
assert str(e) == CALLABLE_ERROR % (key, value, type(value))
else:
assert str(e) == TYPE_ERROR % (key, kind, value, type(value))
# Test with None:
kw = {key: None}
Subclass('my_param', **kw)
# Test when using unknown kwargs:
def test_convert_scalar(self):
"""
Test the `ipalib.parameter.Param._convert_scalar` method.
@@ -168,6 +169,56 @@ class test_Param(ClassChecker):
assert str(e) == 'Subclass._convert_scalar()'
class test_Bytes(ClassChecker):
"""
Test the `ipalib.parameter.Bytes` class.
"""
_cls = parameter.Bytes
def test_init(self):
"""
Test the `ipalib.parameter.Bytes.__init__` method.
"""
o = self.cls('my_bytes')
assert o.type is str
assert o.minlength is None
assert o.maxlength is None
assert o.length is None
assert o.pattern is None
# Test mixing length with minlength or maxlength:
o = self.cls('my_bytes', length=5)
assert o.length == 5
permutations = [
dict(minlength=3),
dict(maxlength=7),
dict(minlength=3, maxlength=7),
]
for kw in permutations:
o = self.cls('my_bytes', **kw)
for (key, value) in kw.iteritems():
assert getattr(o, key) == value
e = raises(ValueError, self.cls, 'my_bytes', length=5, **kw)
assert str(e) == \
"Bytes('my_bytes'): cannot mix length with minlength or maxlength"
# Test when minlength or maxlength are less than 1:
e = raises(ValueError, self.cls, 'my_bytes', minlength=0)
assert str(e) == "Bytes('my_bytes'): minlength must be >= 1; got 0"
e = raises(ValueError, self.cls, 'my_bytes', maxlength=0)
assert str(e) == "Bytes('my_bytes'): maxlength must be >= 1; got 0"
# Test when minlength > maxlength:
e = raises(ValueError, self.cls, 'my_bytes', minlength=22, maxlength=15)
assert str(e) == \
"Bytes('my_bytes'): minlength > maxlength (minlength=22, maxlength=15)"
# Test when minlength == maxlength
e = raises(ValueError, self.cls, 'my_bytes', minlength=7, maxlength=7)
assert str(e) == \
"Bytes('my_bytes'): minlength == maxlength; use length=7 instead"
class test_Str(ClassChecker):
"""
Test the `ipalib.parameter.Str` class.
@@ -180,6 +231,10 @@ class test_Str(ClassChecker):
"""
o = self.cls('my_str')
assert o.type is unicode
assert o.minlength is None
assert o.maxlength is None
assert o.length is None
assert o.pattern is None
def test_convert_scalar(self):
"""