mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Finished kwarg validation and extension mechanism in parameter.Param
This commit is contained in:
2
TODO
2
TODO
@@ -25,6 +25,8 @@ API chages before January 2009 simi-freeze:
|
||||
|
||||
* Implement gettext service.
|
||||
|
||||
* Add ability to register pre-op, post-op plugins per command.
|
||||
|
||||
CLI
|
||||
- Prompt for password using getpass
|
||||
- Passed the param dict to output_for_cli()
|
||||
|
||||
@@ -26,6 +26,12 @@ All constants centralised in one file.
|
||||
NULLS = (None, '', u'', tuple(), [])
|
||||
|
||||
|
||||
TYPE_ERROR = '%s: need a %r; got %r (a %r)'
|
||||
|
||||
|
||||
CALLABLE_ERROR = '%s: need a callable; got %r (a %r)'
|
||||
|
||||
|
||||
# Used for a tab (or indentation level) when formatting for CLI:
|
||||
CLI_TAB = ' ' # Two spaces
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Parameter system for command plugins.
|
||||
"""
|
||||
|
||||
from plugable import ReadOnly, lock, check_name
|
||||
from constants import NULLS
|
||||
from constants import NULLS, TYPE_ERROR, CALLABLE_ERROR
|
||||
|
||||
|
||||
def parse_param_spec(spec):
|
||||
@@ -83,15 +83,42 @@ class Param(ReadOnly):
|
||||
required=(bool, True),
|
||||
multivalue=(bool, False),
|
||||
primary_key=(bool, False),
|
||||
normalize=(callable, None),
|
||||
normalizer=(callable, None),
|
||||
default=(None, None),
|
||||
default_from=(callable, None),
|
||||
flags=(frozenset, frozenset()),
|
||||
)
|
||||
|
||||
def __init__(self, name, **overrides):
|
||||
def __init__(self, name, kwargs, **overrides):
|
||||
self.param_spec = name
|
||||
self.name = check_name(name)
|
||||
kwargs = dict(kwargs)
|
||||
assert set(self.__kwargs).intersection(kwargs) == set()
|
||||
kwargs.update(self.__kwargs)
|
||||
for (key, (kind, default)) in kwargs.iteritems():
|
||||
value = overrides.get(key, default)
|
||||
if value is None:
|
||||
if kind is bool:
|
||||
raise TypeError(
|
||||
TYPE_ERROR % (key, bool, value, type(value))
|
||||
)
|
||||
else:
|
||||
if (
|
||||
type(kind) is type and type(value) is not kind or
|
||||
type(kind) is tuple and not isinstance(value, kind)
|
||||
):
|
||||
raise TypeError(
|
||||
TYPE_ERROR % (key, kind, value, type(value))
|
||||
)
|
||||
elif kind is callable and not callable(value):
|
||||
raise TypeError(
|
||||
CALLABLE_ERROR % (key, value, type(value))
|
||||
)
|
||||
if hasattr(self, key):
|
||||
raise ValueError('kwarg %r conflicts with attribute on %s' % (
|
||||
key, self.__class__.__name__)
|
||||
)
|
||||
setattr(self, key, value)
|
||||
lock(self)
|
||||
|
||||
def normalize(self, value):
|
||||
@@ -120,7 +147,6 @@ class Param(ReadOnly):
|
||||
except StandardError:
|
||||
return value
|
||||
|
||||
|
||||
def convert(self, value):
|
||||
if value in NULLS:
|
||||
return
|
||||
@@ -178,7 +204,7 @@ class Str(Param):
|
||||
|
||||
def __init__(self, name, **overrides):
|
||||
self.type = unicode
|
||||
super(Str, self).__init__(name, **overrides)
|
||||
super(Str, self).__init__(name, {}, **overrides)
|
||||
|
||||
def _convert_scalar(self, value, index=None):
|
||||
if type(value) in (self.type, int, float, bool):
|
||||
|
||||
@@ -25,6 +25,7 @@ done
|
||||
|
||||
if [ $failures ]; then
|
||||
echo "[ Ran under $runs version(s); FAILED under $failures version(s) ]"
|
||||
echo "FAIL!"
|
||||
exit $failures
|
||||
else
|
||||
echo "[ Ran under $runs version(s); all OK ]"
|
||||
|
||||
@@ -25,6 +25,7 @@ Test the `ipalib.parameter` module.
|
||||
from tests.util import raises, ClassChecker
|
||||
from tests.data import binary_bytes, utf8_bytes, unicode_str
|
||||
from ipalib import parameter
|
||||
from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR
|
||||
|
||||
|
||||
def test_parse_param_spec():
|
||||
@@ -49,24 +50,65 @@ class test_Param(ClassChecker):
|
||||
Test the `ipalib.parameter.Param.__init__` method.
|
||||
"""
|
||||
name = 'my_param'
|
||||
o = self.cls(name)
|
||||
o = self.cls(name, {})
|
||||
assert o.name is name
|
||||
# assert o.cli_name is name
|
||||
assert o.doc == ''
|
||||
assert o.required is True
|
||||
assert o.multivalue is False
|
||||
assert o.primary_key is False
|
||||
assert o.normalizer is None
|
||||
assert o.default is None
|
||||
assert o.default_from is None
|
||||
assert o.flags == frozenset()
|
||||
assert o.__islocked__() is True
|
||||
kwarg = dict(convert=(callable, None))
|
||||
e = raises(ValueError, self.cls, name, kwarg)
|
||||
assert str(e) == "kwarg 'convert' conflicts with attribute on Param"
|
||||
class Subclass(self.cls):
|
||||
pass
|
||||
e = raises(ValueError, Subclass, name, kwarg)
|
||||
assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass"
|
||||
kwargs = dict(
|
||||
extra1=(bool, True),
|
||||
extra2=(str, 'Hello'),
|
||||
extra3=((int, float), 42),
|
||||
extra4=(callable, lambda whatever: whatever + 7),
|
||||
)
|
||||
# Check that we don't accept None if kind is bool:
|
||||
e = raises(TypeError, self.cls, 'my_param', kwargs, extra1=None)
|
||||
assert str(e) == TYPE_ERROR % ('extra1', bool, None, type(None))
|
||||
for (key, (kind, default)) in kwargs.items():
|
||||
o = self.cls('my_param', kwargs)
|
||||
# Test with a type invalid for all:
|
||||
value = object()
|
||||
overrides = {key: value}
|
||||
e = raises(TypeError, self.cls, 'my_param', kwargs, **overrides)
|
||||
if kind is callable:
|
||||
assert str(e) == CALLABLE_ERROR % (key, value, type(value))
|
||||
else:
|
||||
assert str(e) == TYPE_ERROR % (key, kind, value, type(value))
|
||||
if kind is bool:
|
||||
continue
|
||||
# Test with None:
|
||||
overrides = {key: None}
|
||||
o = self.cls('my_param', kwargs, **overrides)
|
||||
|
||||
def test_convert_scalar(self):
|
||||
"""
|
||||
Test the `ipalib.parameter.Param._convert_scalar` method.
|
||||
"""
|
||||
o = self.cls('my_param')
|
||||
o = self.cls('my_param', {})
|
||||
e = raises(NotImplementedError, o._convert_scalar, 'some value')
|
||||
assert str(e) == 'Param._convert_scalar()'
|
||||
class Subclass(self.cls):
|
||||
pass
|
||||
o = Subclass('my_param')
|
||||
o = Subclass('my_param', {})
|
||||
e = raises(NotImplementedError, o._convert_scalar, 'some value')
|
||||
assert str(e) == 'Subclass._convert_scalar()'
|
||||
|
||||
|
||||
|
||||
class test_Str(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.parameter.Str` class.
|
||||
|
||||
Reference in New Issue
Block a user