refactore carry_out_calculation + test + documentation

This commit is contained in:
Emmanuel Garette 2013-09-19 21:38:46 +02:00
parent 30ff0fb72b
commit 90ae9aa70d
5 changed files with 397 additions and 88 deletions

View file

@ -4,7 +4,7 @@ from py.test import raises
from tiramisu.setting import groups 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, SymLinkOption
from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError
@ -12,11 +12,19 @@ def return_val():
return 'val' return 'val'
def return_list(): def return_concat(*args):
return '.'.join(list(args))
def return_list(value=None):
return ['val', 'val'] return ['val', 'val']
def return_value(value): def return_list2(*args):
return list(args)
def return_value(value=None):
return value return value
@ -298,18 +306,73 @@ def test_callback():
def test_callback_value(): def test_callback_value():
val1 = StrOption('val1', "", 'val') val1 = StrOption('val1', "", 'val')
val2 = StrOption('val2', "", callback=return_value, callback_params={'': (('val1', False),)}) val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)})
maconfig = OptionDescription('rootconfig', '', [val1, val2]) val3 = StrOption('val3', "", callback=return_value, callback_params={'': ('yes',)})
val4 = StrOption('val4', "", callback=return_value, callback_params={'value': ((val1, False),)})
val5 = StrOption('val5', "", callback=return_value, callback_params={'value': ('yes',)})
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
assert cfg.val1 == 'val' assert cfg.val1 == 'val'
assert cfg.val2 == 'val' assert cfg.val2 == 'val'
assert cfg.val4 == 'val'
cfg.val1 = 'new-val' cfg.val1 = 'new-val'
assert cfg.val1 == 'new-val' assert cfg.val1 == 'new-val'
assert cfg.val2 == 'new-val' assert cfg.val2 == 'new-val'
assert cfg.val4 == 'new-val'
del(cfg.val1) del(cfg.val1)
assert cfg.val1 == 'val' assert cfg.val1 == 'val'
assert cfg.val2 == 'val' assert cfg.val2 == 'val'
assert cfg.val3 == 'yes'
assert cfg.val4 == 'val'
assert cfg.val5 == 'yes'
def test_callback_value_tuple():
val1 = StrOption('val1', "", 'val1')
val2 = StrOption('val2', "", 'val2')
val3 = StrOption('val3', "", callback=return_concat, callback_params={'': ((val1, False), (val2, False))})
val4 = StrOption('val4', "", callback=return_concat, callback_params={'': ('yes', 'no')})
raises(ValueError, "StrOption('val4', '', callback=return_concat, callback_params={'value': ('yes', 'no')})")
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1 == 'val1'
assert cfg.val2 == 'val2'
assert cfg.val3 == 'val1.val2'
assert cfg.val4 == 'yes.no'
cfg.val1 = 'new-val'
assert cfg.val3 == 'new-val.val2'
del(cfg.val1)
assert cfg.val3 == 'val1.val2'
def test_callback_value_force_permissive():
val1 = StrOption('val1', "", 'val', properties=('disabled',))
val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)})
val3 = StrOption('val3', "", callback=return_value, callback_params={'': ((val1, True),)})
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3])
cfg = Config(maconfig)
cfg.read_only()
raises(ConfigError, "cfg.val2")
assert cfg.val3 is None
def test_callback_symlink():
val1 = StrOption('val1', "", 'val')
val2 = SymLinkOption('val2', val1)
val3 = StrOption('val3', "", callback=return_value, callback_params={'': ((val2, False),)})
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1 == 'val'
assert cfg.val3 == 'val'
cfg.val1 = 'new-val'
assert cfg.val1 == 'new-val'
assert cfg.val3 == 'new-val'
del(cfg.val1)
assert cfg.val1 == 'val'
assert cfg.val3 == 'val'
def test_callback_list(): def test_callback_list():
@ -336,21 +399,28 @@ def test_callback_multi():
def test_callback_multi_value(): def test_callback_multi_value():
val1 = StrOption('val1', "", ['val'], multi=True) val1 = StrOption('val1', "", ['val'], multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': (('val1', False),)}) val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)})
maconfig = OptionDescription('rootconfig', '', [val1, val2]) val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)})
val4 = StrOption('val4', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), 'yes')})
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
assert cfg.val1 == ['val'] assert cfg.val1 == ['val']
assert cfg.val2 == ['val'] assert cfg.val2 == ['val']
assert cfg.val4 == ['val', 'yes']
cfg.val1 = ['new-val'] cfg.val1 = ['new-val']
assert cfg.val1 == ['new-val'] assert cfg.val1 == ['new-val']
assert cfg.val2 == ['new-val'] assert cfg.val2 == ['new-val']
assert cfg.val4 == ['new-val', 'yes']
cfg.val1.append('new-val2') cfg.val1.append('new-val2')
assert cfg.val1 == ['new-val', 'new-val2'] assert cfg.val1 == ['new-val', 'new-val2']
assert cfg.val2 == ['new-val', 'new-val2'] assert cfg.val2 == ['new-val', 'new-val2']
assert cfg.val4 == ['new-val', 'yes', 'new-val2', 'yes']
del(cfg.val1) del(cfg.val1)
assert cfg.val1 == ['val'] assert cfg.val1 == ['val']
assert cfg.val2 == ['val'] assert cfg.val2 == ['val']
assert cfg.val3 == ['yes']
assert cfg.val4 == ['val', 'yes']
def test_callback_multi_list(): def test_callback_multi_list():
@ -455,41 +525,67 @@ def test_callback_master_and_slaves_slave_list():
def test_callback_master_and_slaves_value(): def test_callback_master_and_slaves_value():
val1 = StrOption('val1', "", multi=True) val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': (('val1.val1', False),)}) val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)})
interface1 = OptionDescription('val1', '', [val1, val2]) val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)})
val4 = StrOption('val4', '', multi=True, default=['val10', 'val11'])
val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val4, False),)})
interface1 = OptionDescription('val1', '', [val1, val2, val3, val5])
interface1.impl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1]) maconfig = OptionDescription('rootconfig', '', [interface1, val4])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
assert cfg.val1.val1 == [] assert cfg.val1.val1 == []
assert cfg.val1.val2 == [] assert cfg.val1.val2 == []
assert cfg.val1.val3 == []
assert cfg.val1.val5 == []
# #
cfg.val1.val1 = ['val1'] cfg.val1.val1 = ['val1']
assert cfg.val1.val1 == ['val1'] assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val1'] assert cfg.val1.val2 == ['val1']
assert cfg.val1.val3 == ['yes']
assert cfg.val1.val5 == ['val10']
# #
cfg.val1.val1.append('val2') cfg.val1.val1.append('val2')
assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2'] assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11']
# #
cfg.val1.val1 = ['val1', 'val2', 'val3'] cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val1 == ['val1', 'val2', 'val3'] assert cfg.val1.val1 == ['val1', 'val2', 'val3']
assert cfg.val1.val2 == ['val1', 'val2', 'val3'] assert cfg.val1.val2 == ['val1', 'val2', 'val3']
assert cfg.val1.val3 == ['yes', 'yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11', None]
# #
cfg.val1.val1.pop(2) cfg.val1.val1.pop(2)
assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2'] assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11']
# #
cfg.val1.val2 = ['val2', 'val2'] cfg.val1.val2 = ['val2', 'val2']
cfg.val1.val3 = ['val2', 'val2']
cfg.val1.val5 = ['val2', 'val2']
assert cfg.val1.val2 == ['val2', 'val2'] assert cfg.val1.val2 == ['val2', 'val2']
assert cfg.val1.val3 == ['val2', 'val2']
assert cfg.val1.val5 == ['val2', 'val2']
# #
cfg.val1.val1.append('val3') cfg.val1.val1.append('val3')
assert cfg.val1.val2 == ['val2', 'val2', 'val3'] assert cfg.val1.val2 == ['val2', 'val2', 'val3']
assert cfg.val1.val3 == ['val2', 'val2', 'yes']
assert cfg.val1.val5 == ['val2', 'val2', None]
cfg.cfgimpl_get_settings().remove('cache')
cfg.val4 = ['val10', 'val11', 'val12']
#if value is already set, not updated !
cfg.val1.val1.pop(2)
cfg.val1.val1.append('val3')
cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val5 == ['val2', 'val2', 'val12']
def test_callback_hidden(): def test_callback_hidden():
opt1 = BoolOption('opt1', '') opt1 = BoolOption('opt1', '')
opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)}) opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)})
od1 = OptionDescription('od1', '', [opt1], properties=('hidden',)) od1 = OptionDescription('od1', '', [opt1], properties=('hidden',))
od2 = OptionDescription('od2', '', [opt2]) od2 = OptionDescription('od2', '', [opt2])
maconfig = OptionDescription('rootconfig', '', [od1, od2]) maconfig = OptionDescription('rootconfig', '', [od1, od2])
@ -502,7 +598,7 @@ def test_callback_hidden():
def test_callback_two_disabled(): def test_callback_two_disabled():
opt1 = BoolOption('opt1', '', properties=('disabled',)) opt1 = BoolOption('opt1', '', properties=('disabled',))
opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)}, properties=('disabled',)) opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('disabled',))
od1 = OptionDescription('od1', '', [opt1]) od1 = OptionDescription('od1', '', [opt1])
od2 = OptionDescription('od2', '', [opt2]) od2 = OptionDescription('od2', '', [opt2])
maconfig = OptionDescription('rootconfig', '', [od1, od2]) maconfig = OptionDescription('rootconfig', '', [od1, od2])
@ -513,7 +609,7 @@ def test_callback_two_disabled():
def test_callback_calculating_disabled(): def test_callback_calculating_disabled():
opt1 = BoolOption('opt1', '', properties=('disabled',)) opt1 = BoolOption('opt1', '', properties=('disabled',))
opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)}) opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)})
od1 = OptionDescription('od1', '', [opt1]) od1 = OptionDescription('od1', '', [opt1])
od2 = OptionDescription('od2', '', [opt2]) od2 = OptionDescription('od2', '', [opt2])
maconfig = OptionDescription('rootconfig', '', [od1, od2]) maconfig = OptionDescription('rootconfig', '', [od1, od2])
@ -524,7 +620,7 @@ def test_callback_calculating_disabled():
def test_callback_calculating_mandatory(): def test_callback_calculating_mandatory():
opt1 = BoolOption('opt1', '', properties=('disabled',)) opt1 = BoolOption('opt1', '', properties=('disabled',))
opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)}, properties=('mandatory',)) opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('mandatory',))
od1 = OptionDescription('od1', '', [opt1]) od1 = OptionDescription('od1', '', [opt1])
od2 = OptionDescription('od2', '', [opt2]) od2 = OptionDescription('od2', '', [opt2])
maconfig = OptionDescription('rootconfig', '', [od1, od2]) maconfig = OptionDescription('rootconfig', '', [od1, od2])
@ -535,10 +631,47 @@ def test_callback_calculating_mandatory():
def test_callback_two_disabled_multi(): def test_callback_two_disabled_multi():
opt1 = BoolOption('opt1', '', properties=('disabled',)) opt1 = BoolOption('opt1', '', properties=('disabled',))
opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': (('od1.opt1', False),)}, properties=('disabled',), multi=True) opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('disabled',), multi=True)
od1 = OptionDescription('od1', '', [opt1]) od1 = OptionDescription('od1', '', [opt1])
od2 = OptionDescription('od2', '', [opt2]) od2 = OptionDescription('od2', '', [opt2])
maconfig = OptionDescription('rootconfig', '', [od1, od2]) maconfig = OptionDescription('rootconfig', '', [od1, od2])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
raises(PropertiesOptionError, 'cfg.od2.opt2') raises(PropertiesOptionError, 'cfg.od2.opt2')
def test_callback_multi_list_params():
val1 = StrOption('val1', "", multi=True, default=['val1', 'val2'])
val2 = StrOption('val2', "", multi=True, callback=return_list, callback_params={'': ((val1, False),)})
oval2 = OptionDescription('val2', '', [val2])
maconfig = OptionDescription('rootconfig', '', [val1, oval2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val2.val2 == ['val', 'val', 'val', 'val']
def test_callback_multi_list_params_key():
val1 = StrOption('val1', "", multi=True, default=['val1', 'val2'])
val2 = StrOption('val2', "", multi=True, callback=return_list, callback_params={'value': ((val1, False),)})
oval2 = OptionDescription('val2', '', [val2])
maconfig = OptionDescription('rootconfig', '', [val1, oval2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val2.val2 == ['val', 'val', 'val', 'val']
def test_callback_multi_multi():
val1 = StrOption('val1', "", multi=True, default=['val1', 'val2', 'val3'])
val2 = StrOption('val2', "", multi=True, default=['val11', 'val12'])
val3 = StrOption('val3', "", default='val4')
val4 = StrOption('val4', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), (val2, False))})
val5 = StrOption('val5', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), (val3, False))})
val6 = StrOption('val6', "", multi=True, default=['val21', 'val22', 'val23'])
val7 = StrOption('val7', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), (val6, False))})
raises(ValueError, "StrOption('val8', '', multi=True, callback=return_list2, callback_params={'value': ((val1, False), (val6, False))})")
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5, val6, val7])
cfg = Config(maconfig)
cfg.read_write()
raises(ConfigError, "cfg.val4")
assert cfg.val5 == ['val1', 'val4', 'val2', 'val4', 'val3', 'val4']
assert cfg.val7 == ['val1', 'val21', 'val2', 'val22', 'val3', 'val23']

View file

@ -0,0 +1,59 @@
import autopath
from py.test import raises
from tiramisu.config import Config
from tiramisu.option import StrOption, OptionDescription
from tiramisu.error import ConfigError
def return_true(value, param=None):
if value == 'val' and param in [None, 'yes']:
return True
def return_false(value, param=None):
if value == 'val' and param in [None, 'yes']:
return False
def return_val(value, param=None):
return 'val'
def test_validator():
opt1 = StrOption('opt1', '', validator=return_true, default='val')
raises(ValueError, "StrOption('opt2', '', validator=return_false, default='val')")
raises(ConfigError, "StrOption('opt3', '', validator=return_val, default='val')")
opt2 = StrOption('opt2', '', validator=return_false)
opt3 = StrOption('opt3', '', validator=return_val)
root = OptionDescription('root', '', [opt1, opt2, opt3])
cfg = Config(root)
assert cfg.opt1 == 'val'
raises(ValueError, "cfg.opt2 = 'val'")
raises(ConfigError, "cfg.opt3 = 'val'")
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')")
raises(ConfigError, "StrOption('opt3', '', validator=return_val, validator_params={'': ('yes',)}, default='val')")
opt2 = StrOption('opt2', '', validator=return_false, validator_params={'': ('yes',)})
opt3 = StrOption('opt3', '', validator=return_val, validator_params={'': ('yes',)})
root = OptionDescription('root', '', [opt1, opt2, opt3])
cfg = Config(root)
assert cfg.opt1 == 'val'
raises(ValueError, "cfg.opt2 = 'val'")
raises(ConfigError, "cfg.opt3 = 'val'")
def test_validator_params_key():
opt1 = StrOption('opt1', '', validator=return_true, validator_params={'param': ('yes',)}, default='val')
raises(TypeError, "StrOption('opt2', '', validator=return_true, validator_params={'param_unknown': ('yes',)}, default='val')")
root = OptionDescription('root', '', [opt1])
cfg = Config(root)
assert cfg.opt1 == 'val'
def test_validator_params_option():
opt0 = StrOption('opt0', '', default='val')
raises(ValueError, "opt1 = StrOption('opt1', '', validator=return_true, validator_params={'': ((opt0, False),)}, default='val')")

View file

@ -23,11 +23,9 @@ from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.i18n import _ from tiramisu.i18n import _
# ____________________________________________________________ # ____________________________________________________________
def carry_out_calculation(name,
config, def carry_out_calculation(name, config, callback, callback_params,
callback, index=None, max_len=None):
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
:param name: the option name (`opt._name`) :param name: the option name (`opt._name`)
@ -40,36 +38,104 @@ def carry_out_calculation(name,
:type callback_params: dict :type callback_params: dict
:param index: if an option is multi, only calculates the nth value :param index: if an option is multi, only calculates the nth value
:type index: int :type index: int
:param max_len: max length for a multi
:type max_len: int
* if no callback_params:
=> calculate()
* if callback_params={'': ('yes',)}
=> calculate('yes')
* if callback_params={'value': ('yes',)}
=> calculate(value='yes')
* if callback_params={'': ('yes', 'no')}
=> calculate('yes', 'no')
* if callback_params={'value': ('yes', 'no')}
=> ValueError()
* if callback_params={'': ((opt1, False),)}
- a simple option:
opt1 == 11
=> calculate(11)
- a multi option:
opt1 == [1, 2, 3]
=> calculate(1)
=> calculate(2)
=> calculate(3)
* if callback_params={'value': ((opt1, False),)}
- a simple option:
opt1 == 11
=> calculate(value=11)
- a multi option:
opt1 == [1, 2, 3]
=> calculate(value=1)
=> calculate(value=2)
=> calculate(value=3)
* if callback_params={'': ((opt1, False), (opt2, False))}
- a multi option with a simple option
opt1 == [1, 2, 3]
opt2 == 11
=> calculate(1, 11)
=> calculate(2, 11)
=> calculate(3, 11)
- a multi option with an other multi option but with same length
opt1 == [1, 2, 3]
opt2 == [11, 12, 13]
callback_params={'': ((opt1, False), (opt2, False))}
=> calculate(1, 11)
=> calculate(2, 12)
=> calculate(3, 13)
- a multi option with an other multi option but with different length
opt1 == [1, 2, 3]
opt2 == [11, 12]
callback_params={'': ((opt1, False), (opt2, False))}
=> ConfigError()
* if callback_params={'value': ((opt1, False), (opt2, False))}
=> ConfigError()
If index is not None, return a value, otherwise return:
* a list if one parameters have multi option
* a value otherwise
If calculate return list, this list is extend to return value.
""" """
#callback, callback_params = option.getcallback()
#if callback_params is None:
# callback_params = {}
tcparams = {} tcparams = {}
one_is_multi = False one_is_multi = False
len_multi = 0 len_multi = 0
for key, values in callback_params.items(): for key, callbacks in callback_params.items():
for value in values: for callbk in callbacks:
if type(value) == tuple: if isinstance(callbk, tuple):
path, check_disabled = value option, force_permissive = callbk
if config is None: # get value
if check_disabled:
continue
raise ConfigError(_('no config specified but needed'))
try: try:
opt_value = config._getattr(path, force_permissive=True) path = config.cfgimpl_get_description().impl_get_path_by_opt(option)
opt = config.unwrap_from_path(path, force_permissive=True) value = config._getattr(path, force_permissive=True)
except PropertiesOptionError as err: except PropertiesOptionError as err:
if check_disabled: if force_permissive:
continue continue
raise ConfigError(_('unable to carry out a calculation, ' raise ConfigError(_('unable to carry out a calculation, '
'option {0} has properties: {1} for: ' 'option {0} has properties: {1} for: '
'{2}').format(path, err.proptype, '{2}').format(option._name, err.proptype,
name)) name))
is_multi = opt.impl_is_multi() is_multi = option.impl_is_multi()
if is_multi: if is_multi:
if opt_value is not None: if value is not None:
len_value = len(opt_value) len_value = len(value)
if len_multi != 0 and len_multi != len_value: if len_multi != 0 and len_multi != len_value:
raise ConfigError(_('unable to carry out a ' raise ConfigError(_('unable to carry out a '
'calculation, option value with' 'calculation, option value with'
@ -77,16 +143,23 @@ def carry_out_calculation(name,
'length for: {0}').format(name)) 'length for: {0}').format(name))
len_multi = len_value len_multi = len_value
one_is_multi = True one_is_multi = True
tcparams.setdefault(key, []).append((opt_value, is_multi)) tcparams.setdefault(key, []).append((value, is_multi))
else: else:
tcparams.setdefault(key, []).append((value, False)) tcparams.setdefault(key, []).append((callbk, False))
if one_is_multi: if one_is_multi:
ret = [] ret = []
if index: if index:
range_ = [index] if index < len_multi:
range_ = [index]
else:
range_ = []
ret = None
else: else:
range_ = range(len_multi) if max_len and max_len < len_multi:
range_ = range(max_len)
else:
range_ = range(len_multi)
for incr in range_: for incr in range_:
tcp = {} tcp = {}
params = [] params = []
@ -97,15 +170,9 @@ def carry_out_calculation(name,
if key == '': if key == '':
params.append(value[incr]) params.append(value[incr])
else: else:
if len(value) > incr: tcp[key] = value[incr]
tcp[key] = value[incr]
else:
tcp[key] = ''
else: else:
if key == '': params.append(value)
params.append(value)
else:
tcp[key] = value
calc = calculate(name, callback, params, tcp) calc = calculate(name, callback, params, tcp)
if index: if index:
ret = calc ret = calc
@ -114,7 +181,6 @@ def carry_out_calculation(name,
ret.extend(calc) ret.extend(calc)
else: else:
ret.append(calc) ret.append(calc)
return ret return ret
else: else:
tcp = {} tcp = {}
@ -130,7 +196,6 @@ def carry_out_calculation(name,
def calculate(name, callback, params, tcparams): def calculate(name, callback, params, tcparams):
# FIXME we don't need the option's name down there.
"""wrapper that launches the 'callback' """wrapper that launches the 'callback'
:param callback: callback name :param callback: callback name

View file

@ -26,7 +26,7 @@ from copy import copy, deepcopy
from types import FunctionType from types import FunctionType
from IPy import IP from IPy import IP
from tiramisu.error import ConflictError from tiramisu.error import ConflictError, ConfigError
from tiramisu.setting import groups, multitypes from tiramisu.setting import groups, multitypes
from tiramisu.i18n import _ from tiramisu.i18n import _
from tiramisu.autolib import carry_out_calculation from tiramisu.autolib import carry_out_calculation
@ -97,8 +97,8 @@ class BaseOption(object):
"frozen" (which has noting to do with the high level "freeze" "frozen" (which has noting to do with the high level "freeze"
propertie or "read_only" property) propertie or "read_only" property)
""" """
if not name.startswith('_state') and \ if not name.startswith('_state') and name not in ('_cache_paths',
name not in ('_cache_paths', '_consistencies'): '_consistencies'):
is_readonly = False is_readonly = False
# never change _name # never change _name
if name == '_name': if name == '_name':
@ -327,7 +327,7 @@ class Option(BaseOption):
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_args=None, callback_params=None, validator=None, validator_params=None,
properties=None): properties=None):
""" """
:param name: the option's name :param name: the option's name
@ -344,18 +344,15 @@ class Option(BaseOption):
:param callback_params: the callback's parameter :param callback_params: the callback's parameter
:param validator: the name of a function which stands for a custom :param validator: the name of a function which stands for a custom
validation of the value validation of the value
:param validator_args: the validator's parameters :param validator_params: the validator's parameters
:param properties: tuple of default properties :param properties: tuple of default properties
""" """
super(Option, self).__init__(name, doc, requires, properties) super(Option, self).__init__(name, doc, requires, properties)
self._multi = multi self._multi = multi
if validator is not None: if validator is not None:
if type(validator) != FunctionType: validate_callback(validator, validator_params, 'validator')
raise TypeError(_("validator must be a function")) self._validator = (validator, validator_params)
if validator_args is None:
validator_args = {}
self._validator = (validator, validator_args)
else: else:
self._validator = None self._validator = None
if not self._multi and default_multi is not None: if not self._multi and default_multi is not None:
@ -377,11 +374,7 @@ class Option(BaseOption):
"no callback defined" "no callback defined"
" yet for option {0}").format(name)) " yet for option {0}").format(name))
if callback is not None: if callback is not None:
if type(callback) != FunctionType: validate_callback(callback, callback_params, 'callback')
raise ValueError('callback must be a function')
if callback_params is not None and \
not isinstance(callback_params, dict):
raise ValueError('callback_params must be a dict')
self._callback = (callback, callback_params) self._callback = (callback, callback_params)
else: else:
self._callback = None self._callback = None
@ -448,11 +441,23 @@ class Option(BaseOption):
def val_validator(val): def val_validator(val):
if self._validator is not None: if self._validator is not None:
callback_params = deepcopy(self._validator[1]) if self._validator[1] is not None:
callback_params.setdefault('', []).insert(0, val) validator_params = deepcopy(self._validator[1])
return carry_out_calculation(self._name, config=context, if '' in validator_params:
callback=self._validator[0], lst = list(validator_params[''])
callback_params=callback_params) lst.insert(0, val)
validator_params[''] = tuple(lst)
else:
validator_params[''] = (val,)
else:
validator_params = {'': (val,)}
ret = carry_out_calculation(self._name, config=context,
callback=self._validator[0],
callback_params=validator_params)
if ret not in [False, True]:
raise ConfigError(_('validator should return a boolean, '
'not {0}').format(ret))
return ret
else: else:
return True return True
@ -566,7 +571,7 @@ class ChoiceOption(Option):
def __init__(self, name, doc, values, default=None, default_multi=None, def __init__(self, name, doc, values, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, open_values=False, validator=None, callback_params=None, open_values=False, validator=None,
validator_args=None, properties=()): validator_params=None, properties=()):
""" """
:param values: is a list of values the option can possibly take :param values: is a list of values the option can possibly take
""" """
@ -584,7 +589,7 @@ class ChoiceOption(Option):
requires=requires, requires=requires,
multi=multi, multi=multi,
validator=validator, validator=validator,
validator_args=validator_args, validator_params=validator_params,
properties=properties) properties=properties)
def impl_get_values(self): def impl_get_values(self):
@ -702,7 +707,7 @@ class IPOption(Option):
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_args=None, callback_params=None, validator=None, validator_params=None,
properties=None, only_private=False): properties=None, only_private=False):
self._only_private = only_private self._only_private = only_private
super(IPOption, self).__init__(name, doc, default=default, super(IPOption, self).__init__(name, doc, default=default,
@ -712,7 +717,7 @@ class IPOption(Option):
requires=requires, requires=requires,
multi=multi, multi=multi,
validator=validator, validator=validator,
validator_args=validator_args, validator_params=validator_params,
properties=properties) properties=properties)
def _validate(self, value): def _validate(self, value):
@ -738,7 +743,7 @@ class PortOption(Option):
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_args=None, callback_params=None, validator=None, validator_params=None,
properties=None, allow_range=False, allow_zero=False, properties=None, allow_range=False, allow_zero=False,
allow_wellknown=True, allow_registred=True, allow_wellknown=True, allow_registred=True,
allow_private=False): allow_private=False):
@ -772,7 +777,7 @@ class PortOption(Option):
requires=requires, requires=requires,
multi=multi, multi=multi,
validator=validator, validator=validator,
validator_args=validator_args, validator_params=validator_params,
properties=properties) properties=properties)
def _validate(self, value): def _validate(self, value):
@ -857,7 +862,7 @@ class DomainnameOption(Option):
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_args=None, callback_params=None, validator=None, validator_params=None,
properties=None, allow_ip=False, type_='domainname'): properties=None, allow_ip=False, type_='domainname'):
#netbios: for MS domain #netbios: for MS domain
#hostname: to identify the device #hostname: to identify the device
@ -876,7 +881,7 @@ class DomainnameOption(Option):
requires=requires, requires=requires,
multi=multi, multi=multi,
validator=validator, validator=validator,
validator_args=validator_args, validator_params=validator_params,
properties=properties) properties=properties)
def _validate(self, value): def _validate(self, value):
@ -1252,3 +1257,33 @@ def validate_requires_arg(requires, name):
require[3], require[4], require[5])) require[3], require[4], require[5]))
ret.append(tuple(ret_action)) ret.append(tuple(ret_action))
return frozenset(config_action.keys()), tuple(ret) return frozenset(config_action.keys()), tuple(ret)
def validate_callback(callback, callback_params, type_):
if type(callback) != FunctionType:
raise ValueError(_('{0} should be a function').format(type_))
if callback_params is not None:
if not isinstance(callback_params, dict):
raise ValueError(_('{0}_params should be a dict').format(type_))
for key, callbacks in callback_params.items():
if key != '' and len(callbacks) != 1:
raise ValueError(_('{0}_params with key {1} should not have '
'length different to 1').format(type_,
key))
if not isinstance(callbacks, tuple):
raise ValueError(_('{0}_params should be tuple for key "{1}"'
).format(type_, key))
for callbk in callbacks:
if isinstance(callbk, tuple):
option, force_permissive = callbk
if type_ == 'validator' and not force_permissive:
raise ValueError(_('validator not support tuple'))
if not isinstance(option, Option) and not \
isinstance(option, SymLinkOption):
raise ValueError(_('{0}_params should have an option '
'not a {0} for first argument'
).format(type_, type(option)))
if force_permissive not in [True, False]:
raise ValueError(_('{0}_params should have a boolean'
'not a {0} for second argument'
).format(type_, type(force_permissive)))

View file

@ -124,7 +124,7 @@ class Values(object):
return True return True
return False return False
def _getcallback_value(self, opt, index=None): def _getcallback_value(self, opt, index=None, max_len=None):
""" """
retrieves a value for the options that have a callback retrieves a value for the options that have a callback
@ -139,7 +139,7 @@ class Values(object):
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) index=index, max_len=max_len)
def __getitem__(self, opt): def __getitem__(self, opt):
"enables us to use the pythonic dictionary-like access to values" "enables us to use the pythonic dictionary-like access to values"
@ -190,6 +190,7 @@ class Values(object):
if opt.impl_has_callback() and ( if opt.impl_has_callback() and (
self._is_default_owner(path) or self._is_default_owner(path) or
(is_frozen and 'force_default_on_freeze' in setting[opt])): (is_frozen and 'force_default_on_freeze' in setting[opt])):
lenmaster = None
no_value_slave = False no_value_slave = False
if (opt.impl_is_multi() and if (opt.impl_is_multi() and
opt.impl_get_multitype() == multitypes.slave): opt.impl_get_multitype() == multitypes.slave):
@ -202,7 +203,7 @@ class Values(object):
if not no_value_slave: if not no_value_slave:
try: try:
value = self._getcallback_value(opt) value = self._getcallback_value(opt, max_len=lenmaster)
except ConfigError as config_error: except ConfigError as config_error:
value = None value = None
# should not raise PropertiesOptionError if option is # should not raise PropertiesOptionError if option is
@ -389,20 +390,27 @@ class Multi(list):
def _valid_slave(self, value): def _valid_slave(self, value):
#if slave, had values until master's one #if slave, had values until master's one
values = self.context().cfgimpl_get_values()
masterp = self.context().cfgimpl_get_description().impl_get_path_by_opt( masterp = self.context().cfgimpl_get_description().impl_get_path_by_opt(
self.opt.impl_get_master_slaves()) self.opt.impl_get_master_slaves())
mastervalue = getattr(self.context(), masterp) mastervalue = getattr(self.context(), masterp)
masterlen = len(mastervalue) masterlen = len(mastervalue)
valuelen = len(value) valuelen = len(value)
if valuelen > masterlen or (valuelen < masterlen and if valuelen > masterlen or (valuelen < masterlen and
not self.context().cfgimpl_get_values( not values._is_default_owner(self.path)):
)._is_default_owner(self.path)):
raise SlaveError(_("invalid len for the slave: {0}" raise SlaveError(_("invalid len for the slave: {0}"
" which has {1} as master").format( " which has {1} as master").format(
self.opt._name, masterp)) self.opt._name, masterp))
elif valuelen < masterlen: elif valuelen < masterlen:
for num in range(0, masterlen - valuelen): for num in range(0, masterlen - valuelen):
value.append(self.opt.impl_getdefault_multi()) if self.opt.impl_has_callback():
# if callback add a value, but this value will not change
# anymore automaticly (because this value has owner)
index = value.__len__()
value.append(values._getcallback_value(self.opt,
index=index))
else:
value.append(self.opt.impl_getdefault_multi())
#else: same len so do nothing #else: same len so do nothing
return value return value
@ -420,8 +428,17 @@ class Multi(list):
self.opt._name, slave._name)) self.opt._name, slave._name))
elif len(value_slave) < masterlen: elif len(value_slave) < masterlen:
for num in range(0, masterlen - len(value_slave)): for num in range(0, masterlen - len(value_slave)):
value_slave.append(slave.impl_getdefault_multi(), if slave.impl_has_callback():
force=True) # if callback add a value, but this value will not
# change anymore automaticly (because this value
# has owner)
index = value_slave.__len__()
value_slave.append(
values._getcallback_value(slave, index=index),
force=True)
else:
value_slave.append(slave.impl_getdefault_multi(),
force=True)
def __setitem__(self, key, value): def __setitem__(self, key, value):
self._validate(value) self._validate(value)