add validator tests

This commit is contained in:
Emmanuel Garette 2017-12-27 15:48:49 +01:00
parent 098beb03f4
commit 1736170e43
10 changed files with 734 additions and 154 deletions

View File

@ -26,7 +26,7 @@ def return_dynval(value='val', suffix=None):
return value return value
def return_list2(suffix): def return_list2(suffix=None):
return [str(suffix), 'val2'] return [str(suffix), 'val2']

View File

@ -861,7 +861,7 @@ def test_callback_master_and_slaves_slave_callback_disabled():
api.option('val1.val1').value.set(['yes', 'yes1']) api.option('val1.val1').value.set(['yes', 'yes1'])
assert api.option('val1.val2', 0).value.get() == 'no' assert api.option('val1.val2', 0).value.get() == 'no'
api.property.add('disabled') api.property.add('disabled')
raises(ValueError, "api.option('val1.val1').value.set(['yes'])") api.option('val1.val1').value.pop(1)
def test_callback_master_and_slaves_value(): def test_callback_master_and_slaves_value():

View File

@ -0,0 +1,26 @@
"configuration objects global API"
from .autopath import do_autopath
do_autopath()
from py.test import raises
from tiramisu.option import UsernameOption
def test_username():
UsernameOption('a', '', 'string')
UsernameOption('a', '', '_string')
UsernameOption('a', '', 's_tring')
UsernameOption('a', '', 'string_')
UsernameOption('a', '', 'string$')
UsernameOption('a', '', '_string$')
raises(ValueError, "UsernameOption('a', '', 'strin$g')")
UsernameOption('a', '', 's-tring')
raises(ValueError, "UsernameOption('a', '', '-string')")
UsernameOption('a', '', 's9tring')
raises(ValueError, "UsernameOption('a', '', '9string')")
raises(ValueError, "UsernameOption('a', '', '')")
UsernameOption('a', '', 's')
UsernameOption('a', '', 's2345678901234567890123456789012')
raises(ValueError, "UsernameOption('a', '', 's23456789012345678901234567890123')")
UsernameOption('a', '', 's234567890123456789012345678901$')
raises(ValueError, "UsernameOption('a', '', 's2345678901234567890123456789012$')")

View File

@ -0,0 +1,483 @@
from .autopath import do_autopath
do_autopath()
import warnings
from py.test import raises
from tiramisu import BoolOption, StrOption, OptionDescription, MasterSlaves, Config, getapi
from tiramisu.setting import groups
from tiramisu.error import ValueWarning, ConfigError
from tiramisu.i18n import _
msg_err = _('attention, "{0}" could be an invalid {1} for "{2}", {3}')
def return_true(value, param=None):
if value == 'val' and param in [None, 'yes']:
return True
raise ValueError('test error')
def return_false(value, param=None):
if value == 'val' and param in [None, 'yes']:
raise ValueError('test error')
def return_val(value, param=None):
return 'val'
def return_if_val(value):
if value != 'val':
raise ValueError('test error')
def is_context(value, context):
api = getapi(context)
api.property.pop('validator')
if not isinstance(context, Config):
raise ValueError('not context')
def value_values(value, values):
if not (value == 'val' and values == ['val'] or
value == 'val1' and values == ['val1'] or
value == 'val1' and values == ['val1', 'val2'] or
value == 'val2' and values == ['val1', 'val2'] or
value == 'val1' and values == ['val1', None]):
raise ValueError('error')
def value_values_index(value, values, index):
value_values(value, values)
if not (index == 0 or (value == 'val2' and index == 1)):
raise ValueError('error 2')
def value_values_auto(value, values, auto=False):
if auto != False:
raise ValueError('auto should be False')
if not (value == 'val' and values == ['val'] or
value == 'val1' and values == ['val1'] or
value == 'val2' and values == ['val1', 'val2'] or
value == 'val1' and values == ['val1', None]):
raise ValueError('error')
def value_values_auto2(value, values, auto=False):
if auto != False:
raise ValueError('auto should be False')
if not (value == 'val1' and values == 'val' or
value == 'val2' and values == 'val'):
raise ValueError('error')
def value_values_index2(value, values, index, auto=False):
if auto != False:
raise ValueError('auto should be False')
if not (value == 'val1' and values == ['val1'] and index == 'val' or
value == 'val1' and values == ['val1', None] and index == 'val' or
value == 'val2' and values == ['val1', 'val2'] and index == 'val'):
raise ValueError('error')
def value_empty(value, empty, values):
if not value == 'val' or empty is not False and not values == ['val']:
raise ValueError('error')
def valid_from_config(value, config):
api = getapi(config)
if api.option('opt1').value.get() != u'yes':
raise ValueError("c'est une erreur")
def test_validator():
opt1 = StrOption('opt1', '', validator=return_true, default='val')
raises(ValueError, "StrOption('opt2', '', validator=return_false, default='val')")
opt2 = StrOption('opt2', '', validator=return_false)
root = OptionDescription('root', '', [opt1, opt2])
api = getapi(Config(root))
assert api.option('opt1').value.get() == 'val'
raises(ValueError, "api.option('opt2').value.set('val')")
try:
api.option('opt2').value.set('val')
except ValueError as err:
msg = _('"{0}" is an invalid {1} for "{2}", {3}').format('val', _('string'), 'opt2', 'test error')
assert str(err) == msg
def test_validator_params():
opt1 = StrOption('opt1', '', validator=return_true, validator_params={'': ('yes',)}, default='val')
raises(ValueError, "StrOption('opt2', '', validator=return_false, validator_params={'': ('yes',)}, default='val')")
opt2 = StrOption('opt2', '', validator=return_false, validator_params={'': ('yes',)})
root = OptionDescription('root', '', [opt1, opt2])
api = getapi(Config(root))
assert api.option('opt1').value.get() == 'val'
raises(ValueError, "api.option('opt2').value.set('val')")
def test_validator_params_value_values():
opt1 = StrOption('opt1', '', validator=value_values, default=['val'], multi=True)
root = OptionDescription('root', '', [opt1])
api = getapi(Config(root))
assert api.option('opt1').value.get() == ['val']
api.option('opt1').value.set(['val1', 'val2'])
def test_validator_params_value_values_index():
opt1 = StrOption('opt1', '', validator=value_values_index, default=['val'], multi=True)
root = OptionDescription('root', '', [opt1])
api = getapi(Config(root))
assert api.option('opt1').value.get() == ['val']
api.option('opt1').value.set(['val1', 'val2'])
def test_validator_params_value_values_master():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validator=value_values)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True)
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2'])
def test_validator_params_value_values_index_master():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validator=value_values_index)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True)
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2'])
def test_validator_params_value_values_slave():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validator=value_values)
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val2')
def test_validator_params_value_values_index_slave():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validator=value_values_index)
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val2')
def test_validator_params_value_values_notmulti():
raises(ConfigError, "opt1 = StrOption('opt1', '', validator=value_values, default='val')")
def test_validator_params_value_values_kwargs_empty():
v = BoolOption('v', '', default=False)
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, default=["ip"])
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
"masque du sous-reseau",
multi=True,
validator=value_empty,
validator_params={'': ((v, False),)})
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [v, interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['ip']
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['ip', 'val'])
#cfg.ip_admin_eth0.ip_admin_eth0.append('val')
#cfg.ip_admin_eth0.netmask_admin_eth0[1] = 'val2'
def test_validator_params_value_values_kwargs():
v = BoolOption('v', '', default=False)
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, default=["ip"])
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
"masque du sous-reseau",
multi=True,
validator=value_values_auto,
validator_params={'auto': ((v, False),)})
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [v, interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['ip']
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['ip', 'val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val2')
def test_validator_params_value_values_kwargs_values():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
"masque du sous-reseau",
multi=True,
validator=value_values_auto2,
validator_params={'values': ((ip_admin_eth0, False),)})
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val2')
def test_validator_params_value_values_kwargs2():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
"masque du sous-reseau",
multi=True,
validator=value_values_index2,
validator_params={'': (['val1'],), 'index': ((ip_admin_eth0, False),)})
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val'])
def test_validator_params_value_values_kwargs_index():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
"masque du sous-reseau",
multi=True,
validator=value_values_index2,
validator_params={'index': ((ip_admin_eth0, False),)})
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val'])
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val2')
def test_validator_params_context():
opt1 = StrOption('opt1', '', validator=is_context, validator_params={'': ((None,),)}, default='val')
root = OptionDescription('root', '', [opt1])
api = getapi(Config(root))
assert 'validator' in api.property.get()
assert api.option('opt1').value.get() == 'val'
assert 'validator' in api.property.get()
def test_validator_params_context_value():
opt1 = StrOption('opt1', '', 'yes')
opt2 = StrOption('opt2', '', validator=valid_from_config, validator_params={'': ((None,),)}, default='val')
root = OptionDescription('root', '', [opt1, opt2])
api = getapi(Config(root))
assert api.option('opt1').value.get() == 'yes'
assert api.option('opt2').value.get() == 'val'
api.option('opt1').value.set('no')
raises(ValueError, "assert api.option('opt2').value.get()")
def test_validator_params_key():
opt1 = StrOption('opt1', '', validator=return_true, validator_params={'param': ('yes',)}, default='val')
raises(ConfigError, "StrOption('opt2', '', validator=return_true, validator_params={'param_unknown': ('yes',)}, default='val')")
root = OptionDescription('root', '', [opt1])
api = getapi(Config(root))
assert api.option('opt1').value.get() == 'val'
def test_validator_params_option():
opt0 = StrOption('opt0', '', default='yes')
opt1 = StrOption('opt1', '', validator=return_true, validator_params={'': ((opt0, False),)}, default='val')
r = OptionDescription('root', '', [opt0, opt1])
api = getapi(Config(r))
assert api.option('opt1').value.get() == 'val'
api.option('opt0').value.set('val')
raises(ValueError, "api.option('opt1').value.get()")
def test_validator_multi():
opt1 = StrOption('opt1', '', validator=return_if_val, multi=True)
root = OptionDescription('root', '', [opt1])
api = getapi(Config(root))
assert api.option('opt1').value.get() == []
api.option('opt1').value.set(['val'])
assert api.option('opt1').value.get() == ['val']
raises(ValueError, "api.option('opt1').value.set(['val', 'val1'])")
def test_validator_warning():
opt1 = StrOption('opt1', '', validator=return_true, default='val', warnings_only=True)
opt2 = StrOption('opt2', '', validator=return_false, warnings_only=True)
opt3 = StrOption('opt3', '', validator=return_if_val, multi=True, warnings_only=True)
root = OptionDescription('root', '', [opt1, opt2, opt3])
api = getapi(Config(root))
assert api.option('opt1').value.get() == 'val'
warnings.simplefilter("always", ValueWarning)
with warnings.catch_warnings(record=True) as w:
api.option('opt1').value.set('val')
assert w == []
#
with warnings.catch_warnings(record=True) as w:
api.option('opt2').value.set('val')
assert len(w) == 1
assert w[0].message.opt == opt2
assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2', 'test error')
#
with warnings.catch_warnings(record=True) as w:
api.option('opt3').value.set(['val'])
assert w == []
#
with warnings.catch_warnings(record=True) as w:
api.option('opt3').value.set(['val', 'val1'])
assert len(w) == 1
assert w[0].message.opt == opt3
assert str(w[0].message) == msg_err.format('val1', opt3._display_name, 'opt3', 'test error')
raises(ValueError, "api.option('opt2').value.set(1)")
#
with warnings.catch_warnings(record=True) as w:
api.option('opt2').value.set('val')
api.option('opt3').value.set(['val', 'val1', 'val'])
assert len(w) == 2
assert w[0].message.opt == opt2
assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2', 'test error')
assert w[1].message.opt == opt3
assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2', 'test error')
def test_validator_warning_disabled():
opt1 = StrOption('opt1', '', validator=return_true, default='val', warnings_only=True)
opt2 = StrOption('opt2', '', validator=return_false, warnings_only=True)
opt3 = StrOption('opt3', '', validator=return_if_val, multi=True, warnings_only=True)
root = OptionDescription('root', '', [opt1, opt2, opt3])
api = getapi(Config(root))
api.property.pop('warnings')
assert api.option('opt1').value.get() == 'val'
warnings.simplefilter("always", ValueWarning)
with warnings.catch_warnings(record=True) as w:
api.option('opt1').value.set('val')
assert w == []
#
with warnings.catch_warnings(record=True) as w:
api.option('opt2').value.set('val')
assert w == []
#
with warnings.catch_warnings(record=True) as w:
api.option('opt3').value.set(['val'])
assert w == []
#
with warnings.catch_warnings(record=True) as w:
api.option('opt3').value.set(['val', 'val1'])
assert w == []
raises(ValueError, "api.option('opt2').value.set(1)")
#
with warnings.catch_warnings(record=True) as w:
api.option('opt2').value.set('val')
api.option('opt3').value.set(['val', 'val1', 'val'])
assert w == []
def test_validator_warning_master_slave():
display_name_ip = "ip reseau autorise"
display_name_netmask = "masque du sous-reseau"
ip_admin_eth0 = StrOption('ip_admin_eth0', display_name_ip, multi=True, validator=return_false, warnings_only=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', display_name_netmask, multi=True, validator=return_if_val, warnings_only=True)
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
assert interface1.impl_get_group_type() == groups.master
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
warnings.simplefilter("always", ValueWarning)
with warnings.catch_warnings(record=True) as w:
api.option('ip_admin_eth0.ip_admin_eth0').value.set([None])
assert w == []
#
with warnings.catch_warnings(record=True) as w:
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
assert len(w) == 1
assert w[0].message.opt == netmask_admin_eth0
assert str(w[0].message) == msg_err.format('val1', netmask_admin_eth0._display_name, display_name_netmask, 'test error')
#
with warnings.catch_warnings(record=True) as w:
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error')
#
with warnings.catch_warnings(record=True) as w:
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val1', 'val1'])
#FIXME
#assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error')
#
with warnings.catch_warnings(record=True) as w:
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val', 'val1'])
#FIXME
#assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error')
#
warnings.resetwarnings()
with warnings.catch_warnings(record=True) as w:
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val1', 'val'])
#FIXME
#assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error')
def test_validator_slave_param():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
"masque du sous-reseau",
multi=True,
validator=return_true,
validator_params={'param': ((ip_admin_eth0, False),)})
interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
#interface1.impl_set_group_type(groups.master)
root = OptionDescription('root', '', [interface1])
api = getapi(Config(root))
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['yes'])
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val')
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['yes', 'yes'])
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val')
def test_validator_dependencies():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise")
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
"masque du sous-reseau",
validator=return_true,
validator_params={'param': ((ip_admin_eth0, False),)})
opt2 = StrOption('opt2', '', validator=return_false)
root = OptionDescription('root', '', [ip_admin_eth0, netmask_admin_eth0, opt2])
api = getapi(Config(root))
assert api.option('ip_admin_eth0').option.has_dependency() is False
assert api.option('netmask_admin_eth0').option.has_dependency() is True
assert api.option('opt2').option.has_dependency() is False
#
assert api.option('ip_admin_eth0').option.has_dependency(False) is True
assert api.option('netmask_admin_eth0').option.has_dependency(False) is False
assert api.option('opt2').option.has_dependency(False) is False

View File

@ -88,23 +88,25 @@ class CommonTiramisuOption(object):
slave_need_index = True slave_need_index = True
def __init__(self, def __init__(self,
name,
path, path,
index, index,
subconfig,
config_bag): config_bag):
opt = config_bag.option
if not self.allow_optiondescription and opt.impl_is_optiondescription():
raise APIError(_('option must not be an optiondescription'))
self.path = path self.path = path
self.index = index self.index = index
self.config_bag = config_bag self.config_bag = config_bag
self.name = name
self.subconfig = subconfig
if self.slave_need_index: if self.slave_need_index:
self._test_slave_index() self._test_slave_index()
if not self.allow_unrestraint: if not self.allow_unrestraint:
self._unrestraint_not_allowed(self.config_bag.force_unrestraint) self._unrestraint_not_allowed(self.config_bag.force_unrestraint)
def _test_slave_index(self): def _test_slave_index(self):
if not self.config_bag.option.impl_is_optiondescription() and self.index is None and \ option = self.get_option()
self.config_bag.option.impl_is_master_slaves('slave'): if not option.impl_is_optiondescription() and self.index is None and \
option.impl_is_master_slaves('slave'):
raise APIError('index must be set with a slave option') raise APIError('index must be set with a slave option')
def _unrestraint_not_allowed(self, force_unrestraint): def _unrestraint_not_allowed(self, force_unrestraint):
@ -121,6 +123,17 @@ class CommonTiramisuOption(object):
else: else:
super(CommonTiramisuOption, self).__getattribute__(name) super(CommonTiramisuOption, self).__getattribute__(name)
def get_option(self):
option = self.config_bag.option
if option is None:
option = self.subconfig.cfgimpl_get_description().impl_getchild(self.name,
self.config_bag,
self.subconfig)
self.config_bag.option = option
if not self.allow_optiondescription and option.impl_is_optiondescription():
raise APIError(_('option must not be an optiondescription'))
return option
def _help(self): def _help(self):
txt = [] txt = []
for func_name in dir(self): for func_name in dir(self):
@ -140,65 +153,80 @@ class TiramisuOptionOption(CommonTiramisuOption):
@count @count
def ismulti(self): def ismulti(self):
"""test if option could have multi value""" """test if option could have multi value"""
return self._opt.impl_is_multi() option = self.get_option()
return option.impl_is_multi()
@count @count
def issubmulti(self): def issubmulti(self):
"""test if option could have submulti value""" """test if option could have submulti value"""
return self._opt.impl_is_submulti() option = self.get_option()
return option.impl_is_submulti()
@count @count
def ismasterslaves(self): def ismasterslaves(self):
"""test if option is a master or a slave""" """test if option is a master or a slave"""
return self._opt.impl_is_master_slaves() option = self.get_option()
return option.impl_is_master_slaves()
@count @count
def ismaster(self): def ismaster(self):
"""test if option is a master""" """test if option is a master"""
return self._opt.impl_is_master_slaves('master') option = self.get_option()
return option.impl_is_master_slaves('master')
@count @count
def isslave(self): def isslave(self):
"""test if option is a slave""" """test if option is a slave"""
return self._opt.impl_is_master_slaves('slave') option = self.get_option()
return option.impl_is_master_slaves('slave')
@count @count
def getname(self): def getname(self):
return self._opt.impl_getname() option = self.get_option()
return option.impl_getname()
@count @count
def getdoc(self): def getdoc(self):
return self._opt.impl_get_display_name() option = self.get_option()
return option.impl_get_display_name()
@count @count
def default(self): def default(self):
return self.config_bag.option.impl_getdefault() option = self.get_option()
return option.impl_getdefault()
@count @count
def defaultmulti(self): def defaultmulti(self):
return self.config_bag.option.impl_getdefault_multi() option = self.get_option()
return option.impl_getdefault_multi()
@count @count
def has_dependency(self, self_is_dep=True): def has_dependency(self, self_is_dep=True):
return self.config_bag.option.impl_has_dependency(self_is_dep) option = self.get_option()
return option.impl_has_dependency(self_is_dep)
class TiramisuOptionOwner(CommonTiramisuOption): class TiramisuOptionOwner(CommonTiramisuOption):
"""manager option's owner""" """manager option's owner"""
def __init__(self, def __init__(self,
name,
path, path,
index, index,
subconfig,
config_bag): config_bag):
super(TiramisuOptionOwner, self).__init__(path, super(TiramisuOptionOwner, self).__init__(name,
path,
index, index,
subconfig,
config_bag) config_bag)
self.values = self.config_bag.config.cfgimpl_get_values() self.values = self.config_bag.config.cfgimpl_get_values()
@count @count
def get(self): def get(self):
"""get owner for a specified option""" """get owner for a specified option"""
self.get_option()
return self.values.getowner(self.path, return self.values.getowner(self.path,
self.index, self.index,
self.config_bag) self.config_bag)
@ -206,6 +234,7 @@ class TiramisuOptionOwner(CommonTiramisuOption):
@count @count
def isdefault(self): def isdefault(self):
"""is option has defaut value""" """is option has defaut value"""
self.get_option()
return self.values.is_default_owner(self.path, return self.values.is_default_owner(self.path,
self.index, self.index,
self.config_bag) self.config_bag)
@ -213,6 +242,7 @@ class TiramisuOptionOwner(CommonTiramisuOption):
@count @count
def set(self, owner): def set(self, owner):
"""get owner for a specified option""" """get owner for a specified option"""
self.get_option()
if TIRAMISU_VERSION == 2: if TIRAMISU_VERSION == 2:
if owner in ['default', 'forced', 'meta']: if owner in ['default', 'forced', 'meta']:
raise ConfigError() raise ConfigError()
@ -235,16 +265,21 @@ class TiramisuOptionProperty(CommonTiramisuOption):
slave_need_index = False slave_need_index = False
def __init__(self, def __init__(self,
name,
path, path,
index, index,
subconfig,
config_bag): config_bag):
super(TiramisuOptionProperty, self).__init__(path, super(TiramisuOptionProperty, self).__init__(name,
path,
index, index,
subconfig,
config_bag) config_bag)
self.settings = config_bag.config.cfgimpl_get_settings() self.settings = config_bag.config.cfgimpl_get_settings()
@count @count
def get(self): def get(self):
self.get_option()
self._test_slave_index() self._test_slave_index()
properties = self.settings.getproperties(self.path, properties = self.settings.getproperties(self.path,
self.index, self.index,
@ -256,6 +291,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
@count @count
def set(self, properties): def set(self, properties):
"""set properties for a specified option""" """set properties for a specified option"""
self.get_option()
properties = frozenset(properties) properties = frozenset(properties)
self.settings.setproperties(path=self.path, self.settings.setproperties(path=self.path,
properties=properties, properties=properties,
@ -263,6 +299,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
@count @count
def add(self, prop): def add(self, prop):
self.get_option()
self.settings.addproperty(self.path, self.settings.addproperty(self.path,
prop, prop,
self.config_bag) self.config_bag)
@ -277,6 +314,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
def reset(self): def reset(self):
"""reset all personalised properties """reset all personalised properties
""" """
self.get_option()
self.settings.reset(opt=self.config_bag.option, self.settings.reset(opt=self.config_bag.option,
path=self.path) path=self.path)
@ -300,9 +338,9 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
def get(self): def get(self):
"""get permissive value for a specified path""" """get permissive value for a specified path"""
if TIRAMISU_VERSION == 2: if TIRAMISU_VERSION == 2:
args = [self.setting_properties, self._path] args = [self.setting_properties, self.path]
else: else:
args = [self._opt, self._path] args = [self._opt, self.path]
return self.settings.getpermissive(*args) return self.settings.getpermissive(*args)
@count @count
@ -310,7 +348,7 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
if TIRAMISU_VERSION == 2: if TIRAMISU_VERSION == 2:
permissive = tuple(permissive) permissive = tuple(permissive)
self.settings.setpermissive(opt=self._opt, self.settings.setpermissive(opt=self._opt,
path=self._path, path=self.path,
permissive=permissive) permissive=permissive)
@count @count
@ -325,7 +363,8 @@ class TiramisuOptionInformation(CommonTiramisuOption):
@count @count
def get(self, name, default=undefined): def get(self, name, default=undefined):
return self.config_bag.option.impl_get_information(name, default) option = self.get_option()
return option.impl_get_information(name, default)
class TiramisuOptionValue(CommonTiramisuOption): class TiramisuOptionValue(CommonTiramisuOption):
@ -334,11 +373,12 @@ class TiramisuOptionValue(CommonTiramisuOption):
@count @count
def get(self): def get(self):
self.get_option()
self._test_slave_index() self._test_slave_index()
settings = self.config_bag.config.cfgimpl_get_settings() settings = self.config_bag.config.cfgimpl_get_settings()
value = self.config_bag.config.getattr(self.path, value = self.subconfig.getattr(self.name,
self.index, self.index,
self.config_bag) self.config_bag)
if isinstance(value, Multi): if isinstance(value, Multi):
value = list(value) value = list(value)
return value return value
@ -346,6 +386,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
@count @count
def set(self, value): def set(self, value):
"""set a value for a specified option""" """set a value for a specified option"""
self.get_option()
self._test_slave_index() self._test_slave_index()
values = self.config_bag.config.cfgimpl_get_values() values = self.config_bag.config.cfgimpl_get_values()
if isinstance(value, list): if isinstance(value, list):
@ -359,15 +400,16 @@ class TiramisuOptionValue(CommonTiramisuOption):
value = values.getdefaultvalue(self.path, value = values.getdefaultvalue(self.path,
self.index, self.index,
self.config_bag) self.config_bag)
self.config_bag.config.setattr(self.path, self.subconfig.setattr(self.name,
self.index, self.index,
value, value,
self.config_bag) self.config_bag)
@count @count
def pop(self, index): def pop(self, index):
"""pop value for a specified master values """pop value for a specified master values
""" """
self.get_option()
self._test_slave_index() self._test_slave_index()
#FIXME only for master #FIXME only for master
self.config_bag.config.delattr(self.path, self.config_bag.config.delattr(self.path,
@ -377,6 +419,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
@count @count
def reset(self): def reset(self):
"""reset value for a value""" """reset value for a value"""
self.get_option()
self._test_slave_index() self._test_slave_index()
self.config_bag.config.delattr(self.path, self.config_bag.config.delattr(self.path,
self.index, self.index,
@ -385,7 +428,8 @@ class TiramisuOptionValue(CommonTiramisuOption):
@count @count
def len(self): def len(self):
#FIXME only for slave #FIXME only for slave
subconfig_path = self._path.rsplit('.', 1)[0] self.get_option()
subconfig_path = self.path.rsplit('.', 1)[0]
subconfig = self.config.getattr(subconfig_path, subconfig = self.config.getattr(subconfig_path,
None, None,
self.config_bag) self.config_bag)
@ -393,6 +437,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
def __getattr__(self, name): def __getattr__(self, name):
if name == 'list': if name == 'list':
self.get_option()
if isinstance(self.config_bag.option, ChoiceOption): if isinstance(self.config_bag.option, ChoiceOption):
return self._list return self._list
raise APIError(_('{} allowed only for choiceoption').format(name)) raise APIError(_('{} allowed only for choiceoption').format(name))
@ -416,11 +461,15 @@ class TiramisuOption(object):
tmpl_help = ' {} {}: {}' tmpl_help = ' {} {}: {}'
def __init__(self, def __init__(self,
name,
path, path,
index, index,
subconfig,
config_bag): config_bag):
self._path = path self.name = name
self.subconfig = subconfig
self.path = path
self.index = index self.index = index
self.config_bag = config_bag self.config_bag = config_bag
self.registers = {} self.registers = {}
@ -436,8 +485,10 @@ class TiramisuOption(object):
def __getattr__(self, subfunc): def __getattr__(self, subfunc):
if subfunc in self.registers: if subfunc in self.registers:
return self.registers[subfunc](self._path, return self.registers[subfunc](self.name,
self.path,
self.index, self.index,
self.subconfig,
self.config_bag) self.config_bag)
elif subfunc == 'help': elif subfunc == 'help':
return self._help() return self._help()
@ -450,7 +501,7 @@ class TiramisuOption(object):
withvalue=undefined, withvalue=undefined,
withoption=None, withoption=None,
fullpath=False): fullpath=False):
return self.config_bag.config.getattr(self._path, return self.config_bag.config.getattr(self.path,
None, None,
self.config_bag).make_dict(config_bag=self.config_bag, self.config_bag).make_dict(config_bag=self.config_bag,
flatten=flatten, flatten=flatten,
@ -609,23 +660,18 @@ class TiramisuDispatcherOption(TiramisuContextOption):
config_bag.validate_properties = validate config_bag.validate_properties = validate
if not validate: if not validate:
config_bag.setting_properties = None config_bag.setting_properties = None
opt = config_bag.config.unwrap_from_path(path, subconfig, name = config_bag.config.cfgimpl_get_home_by_path(path,
index, config_bag)
config_bag) #opt = config_bag.config.unwrap_from_path(path,
config_bag.option = opt # index,
if index is not None and not opt.impl_is_master_slaves('slave'): # config_bag)
raise APIError('index must be set only with a slave option') #config_bag.option = opt
#if opt.impl_is_symlinkoption(): #if index is not None and not opt.impl_is_master_slaves('slave'):
# config_bag.ori_option = config_bag.option # raise APIError('index must be set only with a slave option')
# config_bag.option = opt.impl_getopt() return TiramisuOption(name,
# true_path = config_bag.option.impl_getpath(self.config_bag.config) path,
# config_bag.config.unwrap_from_path(true_path,
# index,
# config_bag)
#else:
# true_path = None
return TiramisuOption(path,
index, index,
subconfig,
config_bag) config_bag)

View File

@ -32,6 +32,7 @@ def carry_out_calculation(option,
callback_params, callback_params,
index, index,
config_bag, config_bag,
orig_value=undefined,
is_validator=False): is_validator=False):
"""a function that carries out a calculation for an option's value """a function that carries out a calculation for an option's value
@ -177,31 +178,43 @@ def carry_out_calculation(option,
sconfig_bag = config_bag.copy('nooption') sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = opt sconfig_bag.option = opt
sconfig_bag.force_permissive = True sconfig_bag.force_permissive = True
if opt == option:
sconfig_bag.validate = False
if index is not None and opt.impl_is_master_slaves() and \ if index is not None and opt.impl_is_master_slaves() and \
opt.impl_get_master_slaves().in_same_group(option): opt.impl_get_master_slaves().in_same_group(option):
if opt.impl_is_master_slaves('slave'): if opt == option:
index_ = None
with_index = False
iter_slave = True
elif opt.impl_is_master_slaves('slave'):
index_ = index index_ = index
with_index = False with_index = False
iter_slave = False
else: else:
index_ = None index_ = None
with_index = True with_index = True
iter_slave = False
else: else:
index_ = None index_ = None
with_index = False with_index = False
try: iter_slave = False
# get value if opt == option and orig_value is not undefined and \
value = context.getattr(path, (not opt.impl_is_master_slaves('slave') or index is None):
index_, value = orig_value
sconfig_bag) else:
if with_index: if opt == option:
value = value[index] sconfig_bag.validate = False
except PropertiesOptionError as err: try:
if force_permissive: # get value
continue value = context.getattr(path,
raise ConfigError(_('unable to carry out a calculation for "{}"' index_,
', {}').format(option.impl_get_display_name(), err)) sconfig_bag,
iter_slave=iter_slave)
if with_index:
value = value[index]
except PropertiesOptionError as err:
if force_permissive:
continue
raise ConfigError(_('unable to carry out a calculation for "{}"'
', {}').format(option.impl_get_display_name(), err))
if key == '': if key == '':
args.append(value) args.append(value)

View File

@ -282,29 +282,32 @@ class SubConfig(object):
value) value)
context = self._cfgimpl_get_context() context = self._cfgimpl_get_context()
if '.' in name: # pragma: optional cover if '.' in name: # pragma: optional cover
self, name = self.cfgimpl_get_home_by_path(name, raise Exception('ah non ...')
config_bag) #self, name = self.cfgimpl_get_home_by_path(name,
child = self.cfgimpl_get_description().impl_getchild(name, # config_bag)
config_bag, if config_bag.option is None:
self) config_bag.option = self.cfgimpl_get_description().impl_getchild(name,
if child.impl_is_optiondescription() or isinstance(child, SynDynOptionDescription): config_bag,
self)
if config_bag.option.impl_is_optiondescription() or \
isinstance(config_bag.option, SynDynOptionDescription):
raise TypeError(_("can't assign to an OptionDescription")) # pragma: optional cover raise TypeError(_("can't assign to an OptionDescription")) # pragma: optional cover
elif child.impl_is_symlinkoption(): elif config_bag.option.impl_is_symlinkoption():
raise TypeError(_("can't assign to a SymLinkOption")) raise TypeError(_("can't assign to a SymLinkOption"))
else: else:
subpath = self._get_subpath(name) path = self._get_subpath(name)
if config_bag.setting_properties: if config_bag.setting_properties:
self.cfgimpl_get_settings().validate_properties(subpath, context.cfgimpl_get_settings().validate_properties(path,
index, index,
config_bag) config_bag)
self.cfgimpl_get_description().impl_validate_value(child, context.cfgimpl_get_description().impl_validate_value(config_bag.option,
value, value,
self) self)
return self.cfgimpl_get_values().setvalue(subpath, return context.cfgimpl_get_values().setvalue(path,
index, index,
value, value,
config_bag, config_bag,
_commit) _commit)
def delattr(self, def delattr(self,
name, name,
@ -363,6 +366,7 @@ class SubConfig(object):
otherwise otherwise
""" """
if '.' in name: if '.' in name:
# raise Exception('je suis desole ...')
self, name = self.cfgimpl_get_home_by_path(name, self, name = self.cfgimpl_get_home_by_path(name,
config_bag) config_bag)

View File

@ -197,13 +197,16 @@ class Base(object):
kwargs = set() kwargs = set()
if add_value: if add_value:
args.add('value') args.add('value')
for param in calculator_params.keys(): if self.impl_is_dynoptiondescription():
if param == '': kwargs.add('suffix')
for idx, _ in enumerate(calculator_params['']): if calculator_params is not None:
# construct an appropriate name for param in calculator_params.keys():
args.add('param{}'.format(idx)) if param == '':
else: for idx, _ in enumerate(calculator_params['']):
kwargs.add(param) # construct an appropriate name
args.add('param{}'.format(idx))
else:
kwargs.add(param)
return args, kwargs return args, kwargs
def _build_calculator_params(self, def _build_calculator_params(self,
@ -211,65 +214,70 @@ class Base(object):
calculator_params, calculator_params,
add_value=False): add_value=False):
if calculator_params is not None: is_multi = self.impl_is_optiondescription() or self.impl_is_multi()
func_args, func_kwargs, func_positional, func_keyword = self._get_function_args(calculator) if calculator_params is None:
calculator_args, calculator_kwargs = self._get_parameters_args(calculator_params, add_value) calculator_params = {}
# remove knowned kwargs func_args, func_kwargs, func_positional, func_keyword = self._get_function_args(calculator)
common_kwargs = func_kwargs & calculator_kwargs calculator_args, calculator_kwargs = self._get_parameters_args(calculator_params, add_value)
func_kwargs -= common_kwargs # remove knowned kwargs
calculator_kwargs -= common_kwargs common_kwargs = func_kwargs & calculator_kwargs
# remove knowned calculator's kwargs in func's args func_kwargs -= common_kwargs
common = func_args & calculator_kwargs calculator_kwargs -= common_kwargs
func_args -= common # remove knowned calculator's kwargs in func's args
calculator_kwargs -= common common = func_args & calculator_kwargs
# remove unknown calculator's args in func's args func_args -= common
for idx in range(min(len(calculator_args), len(func_args))): calculator_kwargs -= common
func_args.pop() # remove unknown calculator's args in func's args
calculator_args.pop() for idx in range(min(len(calculator_args), len(func_args))):
# remove unknown calculator's args in func's kwargs func_args.pop()
calculator_args.pop()
# remove unknown calculator's args in func's kwargs
if is_multi:
func_kwargs_left = func_kwargs - {'index', 'self'} func_kwargs_left = func_kwargs - {'index', 'self'}
func_kwargs_pop = set() else:
for idx in range(min(len(calculator_args), len(func_kwargs_left))): func_kwargs_left = func_kwargs
func_kwargs_pop.add(func_kwargs_left.pop()) func_kwargs_pop = set()
calculator_args.pop() for idx in range(min(len(calculator_args), len(func_kwargs_left))):
func_kwargs -= func_kwargs_pop func_kwargs_pop.add(func_kwargs_left.pop())
if func_positional: calculator_args.pop()
calculator_args = set() func_kwargs -= func_kwargs_pop
if func_keyword: if func_positional:
calculator_kwargs = set() calculator_args = set()
if calculator_args or calculator_kwargs: if func_keyword:
# there is more args/kwargs than expected! calculator_kwargs = set()
raise ConfigError(_('cannot find those arguments "{}" in function "{}" for "{}"' if calculator_args or calculator_kwargs:
'').format(list(calculator_args | calculator_kwargs), # there is more args/kwargs than expected!
raise ConfigError(_('cannot find those arguments "{}" in function "{}" for "{}"'
'').format(list(calculator_args | calculator_kwargs),
calculator.__name__,
self.impl_get_display_name()))
has_self = False
has_index = False
if is_multi and func_args:
# there is extra args/kwargs
if not self.impl_is_optiondescription() and is_multi:
params = list(calculator_params.get('', tuple()))
if add_value:
# only for validator
has_self = True
params.append((self, False))
func_args.pop()
if func_args:
has_index = True
params.append(('index',))
func_args.pop()
if func_args:
raise ConfigError(_('missing those arguements "{}" in function "{}" for "{}"'
'').format(list(func_args),
calculator.__name__, calculator.__name__,
self.impl_get_display_name())) self.impl_get_display_name()))
has_self = False calculator_params[''] = tuple(params)
has_index = False if not self.impl_is_optiondescription() and self.impl_is_multi():
if func_args: if add_value and not has_self and 'self' in func_kwargs:
# there is extra args/kwargs # only for validator
if not self.impl_is_optiondescription() and self.impl_is_multi(): calculator_params['self'] = (self, False)
params = list(calculator_params['']) if not has_index and 'index' in func_kwargs:
if add_value: calculator_params['index'] = (('index',),)
# only for validator
has_self = True
params.append((self, False))
func_args.pop()
if func_args:
has_index = True
params.append(('index',))
func_args.pop()
if func_args:
raise ConfigError(_('missing those arguements "{}" in function "{}" for "{}"'
'').format(list(func_args),
calculator.__name__,
self.impl_get_display_name()))
calculator_params[''] = tuple(params)
if not self.impl_is_optiondescription() and self.impl_is_multi():
if add_value and not has_self and 'self' in func_kwargs:
# only for validator
calculator_params['self'] = (self, False)
if not has_index and 'index' in func_kwargs:
calculator_params['index'] = (('index',),)
return calculator_params return calculator_params
def impl_has_dependency(self, def impl_has_dependency(self,

View File

@ -97,6 +97,11 @@ class Option(OnlyOption):
_setattr(self, '_multi', _multi) _setattr(self, '_multi', _multi)
if multi is not False and default is None: if multi is not False and default is None:
default = [] default = []
super(Option, self).__init__(name,
doc,
requires=requires,
properties=properties,
is_multi=is_multi)
if validator is not None: if validator is not None:
validate_calculator(validator, validate_calculator(validator,
validator_params, validator_params,
@ -120,12 +125,6 @@ class Option(OnlyOption):
_setattr(self, '_warnings_only', warnings_only) _setattr(self, '_warnings_only', warnings_only)
if allow_empty_list is not undefined: if allow_empty_list is not undefined:
_setattr(self, '_allow_empty_list', allow_empty_list) _setattr(self, '_allow_empty_list', allow_empty_list)
super(Option, self).__init__(name,
doc,
requires=requires,
properties=properties,
is_multi=is_multi)
if is_multi and default_multi is not None: if is_multi and default_multi is not None:
def test_multi_value(value): def test_multi_value(value):
try: try:
@ -241,6 +240,7 @@ class Option(OnlyOption):
callback=validator, callback=validator,
callback_params=validator_params_, callback_params=validator_params_,
index=_index, index=_index,
orig_value=value,
config_bag=config_bag, config_bag=config_bag,
is_validator=True) is_validator=True)

View File

@ -327,7 +327,7 @@ class Values(object):
context = self._getcontext() context = self._getcontext()
owner = context.cfgimpl_get_settings().getowner() owner = context.cfgimpl_get_settings().getowner()
if 'validator' in config_bag.setting_properties and config_bag.validate: if 'validator' in config_bag.setting_properties and config_bag.validate:
if config_bag.option._has_consistencies(context): if index is not None or config_bag.option._has_consistencies(context):
# set value to a fake config when option has dependency # set value to a fake config when option has dependency
# validation will be complet in this case (consistency, ...) # validation will be complet in this case (consistency, ...)
tested_context = context._gen_fake_values() tested_context = context._gen_fake_values()