Works callback/multi/master-slave

- in multi, never modify _default value
- _reset slave when _reset master
- if append None in master with callback return not a list, replace None by the value
- list support in slave
This commit is contained in:
Emmanuel Garette 2013-06-12 10:22:50 +02:00
parent ada5bfbf6c
commit 0d114001f4
4 changed files with 221 additions and 29 deletions

View file

@ -5,13 +5,21 @@ from tiramisu.setting import groups
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \ from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription StrOption, OptionDescription
from tiramisu.error import PropertiesOptionError, ConflictError from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError
def return_value(): def return_val():
return 'val' return 'val'
def return_list():
return ['val', 'val']
def return_value(value):
return value
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False) gcdummy = BoolOption('dummy', 'dummy', default=False)
@ -277,7 +285,7 @@ def test_freeze_and_has_callback():
def test_callback(): def test_callback():
val1 = StrOption('val1', "", callback=return_value) val1 = StrOption('val1', "", callback=return_val)
maconfig = OptionDescription('rootconfig', '', [val1]) maconfig = OptionDescription('rootconfig', '', [val1])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
@ -288,9 +296,115 @@ def test_callback():
assert cfg.val1 == 'val' assert cfg.val1 == 'val'
def test_callback_master_and_slaves(): def test_callback_value():
val1 = StrOption('val1', "", 'val')
val2 = StrOption('val2', "", callback=return_value, callback_params={'': (('val1', False),)})
maconfig = OptionDescription('rootconfig', '', [val1, val2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1 == 'val'
assert cfg.val2 == 'val'
cfg.val1 = 'new-val'
assert cfg.val1 == 'new-val'
assert cfg.val2 == 'new-val'
del(cfg.val1)
assert cfg.val1 == 'val'
assert cfg.val2 == 'val'
def test_callback_list():
val1 = StrOption('val1', "", callback=return_list)
maconfig = OptionDescription('rootconfig', '', [val1])
cfg = Config(maconfig)
cfg.read_write()
raises(ValueError, "cfg.val1")
def test_callback_multi():
val1 = StrOption('val1', "", callback=return_val, multi=True)
maconfig = OptionDescription('rootconfig', '', [val1])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1 == ['val']
cfg.val1 = ['new-val']
assert cfg.val1 == ['new-val']
cfg.val1.append('new-val2')
assert cfg.val1 == ['new-val', 'new-val2']
del(cfg.val1)
assert cfg.val1 == ['val']
def test_callback_multi_value():
val1 = StrOption('val1', "", ['val'], multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': (('val1', False),)})
maconfig = OptionDescription('rootconfig', '', [val1, val2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1 == ['val']
assert cfg.val2 == ['val']
cfg.val1 = ['new-val']
assert cfg.val1 == ['new-val']
assert cfg.val2 == ['new-val']
cfg.val1.append('new-val2')
assert cfg.val1 == ['new-val', 'new-val2']
assert cfg.val2 == ['new-val', 'new-val2']
del(cfg.val1)
assert cfg.val1 == ['val']
assert cfg.val2 == ['val']
def test_callback_multi_list():
val1 = StrOption('val1', "", callback=return_list, multi=True)
maconfig = OptionDescription('rootconfig', '', [val1])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1 == ['val', 'val']
cfg.val1 = ['new-val']
assert cfg.val1 == ['new-val']
cfg.val1.append('new-val2')
assert cfg.val1 == ['new-val', 'new-val2']
del(cfg.val1)
assert cfg.val1 == ['val', 'val']
def test_callback_master_and_slaves_master():
val1 = StrOption('val1', "", multi=True, callback=return_val)
val2 = StrOption('val2', "", multi=True)
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1.val1 == ['val']
cfg.val1.val1.append(None)
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == [None, None]
def test_callback_master_and_slaves_master_list():
val1 = StrOption('val1', "", multi=True, callback=return_list)
val2 = StrOption('val2', "", multi=True)
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == [None, None]
cfg.val1.val1.append(None)
assert cfg.val1.val1 == ['val', 'val', None]
assert cfg.val1.val2 == [None, None, None]
del(cfg.val1.val1)
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == [None, None]
assert cfg.val1.val1.pop(1)
assert cfg.val1.val1 == ['val']
assert cfg.val1.val2 == [None]
def test_callback_master_and_slaves_slave():
val1 = StrOption('val1', "", multi=True) val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value) val2 = StrOption('val2', "", multi=True, callback=return_val)
interface1 = OptionDescription('val1', '', [val1, val2]) interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1]) maconfig = OptionDescription('rootconfig', '', [interface1])
@ -320,3 +434,56 @@ def test_callback_master_and_slaves():
# #
cfg.val1.val1.append('val3') cfg.val1.val1.append('val3')
assert cfg.val1.val2 == ['val2', 'val2', 'val'] assert cfg.val1.val2 == ['val2', 'val2', 'val']
def test_callback_master_and_slaves_slave_list():
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_list)
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1.val2 == []
cfg.val1.val1 = ['val1', 'val2']
assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val', 'val']
cfg.val1.val1 = ['val1']
#wrong len
raises(SlaveError, 'cfg.val1.val2')
def test_callback_master_and_slaves_value():
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': (('val1.val1', False),)})
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1.val1 == []
assert cfg.val1.val2 == []
#
cfg.val1.val1 = ['val1']
assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val1']
#
cfg.val1.val1.append('val2')
assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2']
#
cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val1 == ['val1', 'val2', 'val3']
assert cfg.val1.val2 == ['val1', 'val2', 'val3']
#
cfg.val1.val1.pop(2)
assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2']
#
cfg.val1.val2 = ['val2', 'val2']
assert cfg.val1.val2 == ['val2', 'val2']
#
cfg.val1.val1.append('val3')
assert cfg.val1.val2 == ['val2', 'val2', 'val3']

View file

@ -229,8 +229,13 @@ def test_values_with_master_and_slaves_master():
cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145", "192.168.230.145"] cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145", "192.168.230.145"]
cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0'] cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']
raises(SlaveError, 'cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145"]') raises(SlaveError, 'cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145"]')
assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['255.255.255.0', '255.255.255.0']
cfg.ip_admin_eth0.ip_admin_eth0.pop(1) cfg.ip_admin_eth0.ip_admin_eth0.pop(1)
assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"] assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"]
assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['255.255.255.0']
del(cfg.ip_admin_eth0.ip_admin_eth0)
assert cfg.ip_admin_eth0.ip_admin_eth0 == []
assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
def test_values_with_master_owner(): def test_values_with_master_owner():

View file

@ -30,7 +30,7 @@ from tiramisu.i18n import _
# return calc_factory(name, callback, callback_params, config) # return calc_factory(name, callback, callback_params, config)
def carry_out_calculation(name, config, callback, callback_params): def carry_out_calculation(name, config, callback, callback_params, index=None):
"a function that carries out a calculation for an option's value" "a function that carries out a calculation for an option's value"
#callback, callback_params = option.getcallback() #callback, callback_params = option.getcallback()
#if callback_params is None: #if callback_params is None:
@ -71,7 +71,11 @@ def carry_out_calculation(name, config, callback, callback_params):
if one_is_multi: if one_is_multi:
ret = [] ret = []
for incr in range(len_multi): if index:
range_ = [index]
else:
range_ = range(len_multi)
for incr in range_:
tcp = {} tcp = {}
params = [] params = []
for key, couples in tcparams.items(): for key, couples in tcparams.items():
@ -91,10 +95,13 @@ def carry_out_calculation(name, config, callback, callback_params):
else: else:
tcp[key] = value tcp[key] = value
calc = calculate(name, callback, params, tcp) calc = calculate(name, callback, params, tcp)
if isinstance(calc, list): if index:
ret.extend(calc) ret = calc
else: else:
ret.append(calc) if isinstance(calc, list):
ret.extend(calc)
else:
ret.append(calc)
return ret return ret
else: else:

View file

@ -18,6 +18,7 @@
# #
# ____________________________________________________________ # ____________________________________________________________
from time import time from time import time
from copy import copy
from tiramisu.error import ConfigError, SlaveError from tiramisu.error import ConfigError, SlaveError
from tiramisu.setting import owners, multitypes, expires_time from tiramisu.setting import owners, multitypes, expires_time
from tiramisu.autolib import carry_out_calculation from tiramisu.autolib import carry_out_calculation
@ -47,9 +48,13 @@ class Values(object):
def _get_default(self, opt): def _get_default(self, opt):
meta = self.context.cfgimpl_get_meta() meta = self.context.cfgimpl_get_meta()
if meta is not None: if meta is not None:
return meta.cfgimpl_get_values()[opt] value = meta.cfgimpl_get_values()[opt]
else: else:
return opt.impl_getdefault() value = opt.impl_getdefault()
if opt.impl_is_multi():
return copy(value)
else:
return value
def _get_value(self, opt, validate=True): def _get_value(self, opt, validate=True):
"return value or default value if not set" "return value or default value if not set"
@ -72,6 +77,9 @@ class Values(object):
opt.impl_validate(opt.impl_getdefault(), self.context, opt.impl_validate(opt.impl_getdefault(), self.context,
'validator' in setting) 'validator' in setting)
self.context.cfgimpl_reset_cache() self.context.cfgimpl_reset_cache()
if opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.master:
for slave in opt.impl_get_master_slaves():
self._reset(slave)
del(self._values[opt]) del(self._values[opt])
def _is_empty(self, opt, value): def _is_empty(self, opt, value):
@ -83,13 +91,14 @@ class Values(object):
return True return True
return False return False
def _getcallback_value(self, opt): def _getcallback_value(self, opt, index=None):
callback, callback_params = opt._callback callback, callback_params = opt._callback
if callback_params is None: if callback_params is None:
callback_params = {} callback_params = {}
return carry_out_calculation(opt._name, config=self.context, return carry_out_calculation(opt._name, config=self.context,
callback=callback, callback=callback,
callback_params=callback_params) callback_params=callback_params,
index=index)
def __getitem__(self, opt): def __getitem__(self, opt):
return self.getitem(opt) return self.getitem(opt)
@ -133,11 +142,8 @@ class Values(object):
if not no_value_slave: if not no_value_slave:
value = self._getcallback_value(opt) value = self._getcallback_value(opt)
if opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.slave: if opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.slave:
if isinstance(value, list): if not isinstance(value, list):
raise ValueError('callback must not return list ' value = [value for i in range(lenmaster)]
'in slave {0}: {1}'.format(opt._name,
value))
value = [value for i in range(lenmaster)]
if opt.impl_is_multi(): if opt.impl_is_multi():
value = Multi(value, self.context, opt, validate) value = Multi(value, self.context, opt, validate)
#suppress value if already set #suppress value if already set
@ -297,20 +303,27 @@ class Multi(list):
raise SlaveError(_("cannot append a value on a multi option {0}" raise SlaveError(_("cannot append a value on a multi option {0}"
" which is a slave").format(self.opt._name)) " which is a slave").format(self.opt._name))
elif self.opt.impl_get_multitype() == multitypes.master: elif self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.impl_get_master_slaves(): values = self.context.cfgimpl_get_values()
values = self.context.cfgimpl_get_values() if value is None and self.opt.impl_has_callback():
if not values.is_default_owner(slave): value = values._getcallback_value(self.opt)
if slave.impl_has_callback(): #Force None il return a list
dvalue = values._getcallback_value(slave) if isinstance(value, list):
else: value = None
dvalue = slave.impl_getdefault_multi()
#get multi without valid properties
values.getitem(slave, validate_properties=False).append(
dvalue, force=True)
self._validate(value) self._validate(value)
#set value without valid properties #set value without valid properties
self.context.cfgimpl_get_values()._setvalue(self.opt, self, validate_properties=not force) self.context.cfgimpl_get_values()._setvalue(self.opt, self, validate_properties=not force)
super(Multi, self).append(value) super(Multi, self).append(value)
if not force and self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.impl_get_master_slaves():
if not values.is_default_owner(slave):
if slave.impl_has_callback():
index = self.__len__() - 1
dvalue = values._getcallback_value(slave, index=index)
else:
dvalue = slave.impl_getdefault_multi()
#get multi without valid properties
values.getitem(slave, validate_properties=False).append(
dvalue, force=True)
def _validate(self, value): def _validate(self, value):
if value is not None and not self.opt._validate(value): if value is not None and not self.opt._validate(value):