add Calculation to values

This commit is contained in:
Emmanuel Garette 2019-09-28 16:32:48 +02:00
parent bb2ecc94d9
commit fd50913466
17 changed files with 1274 additions and 259 deletions

View file

@ -13,7 +13,7 @@ from tiramisu.setting import groups
def teardown_function(function): def teardown_function(function):
if default_storage.is_persistent: if default_storage.is_persistent():
sessions = list_sessions() sessions = list_sessions()
if not sessions: if not sessions:
return return
@ -31,10 +31,6 @@ def return_incr():
return int(incr/2) + 1 return int(incr/2) + 1
def return_value(val):
return val
def make_description(): def make_description():
u1 = IntOption('u1', '', multi=True) u1 = IntOption('u1', '', multi=True)
u2 = IntOption('u2', '') u2 = IntOption('u2', '')
@ -296,10 +292,6 @@ def test_cache_leadership():
#DEL, insert, ... #DEL, insert, ...
def return_value(value=None):
return value
def compare(calculated, expected): def compare(calculated, expected):
assert set(calculated.keys()) == set(expected.keys()) assert set(calculated.keys()) == set(expected.keys())
for calculated_key in calculated: for calculated_key in calculated:
@ -311,88 +303,58 @@ def compare(calculated, expected):
def test_cache_callback(): def test_cache_callback():
val1 = StrOption('val1', "", 'val') val1 = StrOption('val1', "", 'val')
val2 = StrOption('val2', "", callback=return_value, callback_params=Params((ParamOption(val1),)), properties=('mandatory',)) val2 = StrOption('val2', "", Calculation(calc_value, Params(ParamOption(val1))), properties=('mandatory',))
val3 = StrOption('val3', "", callback=return_value, callback_params=Params((ParamValue('yes'),))) val3 = StrOption('val3', "", Calculation(calc_value, Params(ParamValue('yes'))))
val4 = StrOption('val4', "", callback=return_value, callback_params=Params(kwargs={'value': ParamOption(val1)})) val4 = StrOption('val4', "", Calculation(calc_value, Params(ParamOption(val1))))
val5 = StrOption('val5', "", callback=return_value, callback_params=Params(kwargs={'value': ParamValue('yes')}), multi=True) val5 = StrOption('val5', "", [Calculation(calc_value, Params(ParamValue('yes')))], multi=True)
od1 = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5]) od1 = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5])
cfg = Config(od1) cfg = Config(od1)
cfg.property.read_write() cfg.property.read_write()
cfg.value.dict() cfg.value.dict()
values = cfg._config_bag.context._impl_values_cache values = cfg._config_bag.context._impl_values_cache
settings = cfg._config_bag.context._impl_properties_cache settings = cfg._config_bag.context._impl_properties_cache
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)}}
compare(values.get_cached(), {'val1': {None: ('val', None)}, compare(values.get_cached(), {'val1': {None: ('val', None)},
'val2': {None: ('val', None)}, 'val2': {None: ('val', None)},
'val3': {None: ('yes', None)}, 'val3': {None: ('yes', None)},
'val4': {None: ('val', None)}, 'val4': {None: ('val', None)},
'val5': {None: (['yes'], None)}}) 'val5': {None: (['yes'], None)}})
cfg.option('val1').value.set('new') cfg.option('val1').value.set('new')
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)}}
compare(values.get_cached(), {'val3': {None: ('yes', None)}, compare(values.get_cached(), {'val3': {None: ('yes', None)},
'val5': {None: (['yes'], None)}}) 'val5': {None: (['yes'], None)}})
cfg.value.dict() cfg.value.dict()
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)}}
compare(values.get_cached(), {'val1': {None: ('new', None)}, compare(values.get_cached(), {'val1': {None: ('new', None)},
'val2': {None: ('new', None)}, 'val2': {None: ('new', None)},
'val3': {None: ('yes', None)}, 'val3': {None: ('yes', None)},
'val4': {None: ('new', None)}, 'val4': {None: ('new', None)},
'val5': {None: (['yes'], None)}}) 'val5': {None: (['yes'], None)}})
cfg.option('val3').value.set('new2') cfg.option('val3').value.set('new2')
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)},
# 'val3': {None: (set([]), None)}}
compare(values.get_cached(), {'val1': {None: ('new', None)}, compare(values.get_cached(), {'val1': {None: ('new', None)},
'val2': {None: ('new', None)}, 'val2': {None: ('new', None)},
'val4': {None: ('new', None)}, 'val4': {None: ('new', None)},
'val5': {None: (['yes'], None)}}) 'val5': {None: (['yes'], None)}})
cfg.value.dict() cfg.value.dict()
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)},
# 'val3': {None: (set([]), None)}}
compare(values.get_cached(), {'val1': {None: ('new', None)}, compare(values.get_cached(), {'val1': {None: ('new', None)},
'val2': {None: ('new', None)}, 'val2': {None: ('new', None)},
'val3': {None: ('new2', None)}, 'val3': {None: ('new2', None)},
'val4': {None: ('new', None)}, 'val4': {None: ('new', None)},
'val5': {None: (['yes'], None)}}) 'val5': {None: (['yes'], None)}})
cfg.option('val4').value.set('new3') cfg.option('val4').value.set('new3')
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)},
# 'val3': {None: (set([]), None)},
# 'val4': {None: (set([]), None)}}
compare(values.get_cached(), {'val1': {None: ('new', None)}, compare(values.get_cached(), {'val1': {None: ('new', None)},
'val2': {None: ('new', None)}, 'val2': {None: ('new', None)},
'val3': {None: ('new2', None)}, 'val3': {None: ('new2', None)},
'val5': {None: (['yes'], None)}}) 'val5': {None: (['yes'], None)}})
cfg.value.dict() cfg.value.dict()
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)},
# 'val3': {None: (set([]), None)},
# 'val4': {None: (set([]), None)}}
compare(values.get_cached(), {'val1': {None: ('new', None)}, compare(values.get_cached(), {'val1': {None: ('new', None)},
'val2': {None: ('new', None)}, 'val2': {None: ('new', None)},
'val3': {None: ('new2', None)}, 'val3': {None: ('new2', None)},
'val4': {None: ('new3', None)}, 'val4': {None: ('new3', None)},
'val5': {None: (['yes'], None)}}) 'val5': {None: (['yes'], None)}})
cfg.option('val5').value.set([undefined, 'new4']) cfg.option('val5').value.set([undefined, 'new4'])
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)},
# 'val3': {None: (set([]), None)},
# 'val4': {None: (set([]), None)},
# 'val5': {None: (set(['empty']), None)}}
compare(values.get_cached(), {'val1': {None: ('new', None)}, compare(values.get_cached(), {'val1': {None: ('new', None)},
'val2': {None: ('new', None)}, 'val2': {None: ('new', None)},
'val3': {None: ('new2', None)}, 'val3': {None: ('new2', None)},
'val4': {None: ('new3', None)}}) 'val4': {None: ('new3', None)}})
cfg.value.dict() cfg.value.dict()
#assert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)},
# 'val3': {None: (set([]), None)},
# 'val4': {None: (set([]), None)},
# 'val5': {None: (set(['empty']), None)}}
compare(values.get_cached(), {'val1': {None: ('new', None)}, compare(values.get_cached(), {'val1': {None: ('new', None)},
'val2': {None: ('new', None)}, 'val2': {None: ('new', None)},
'val3': {None: ('new2', None)}, 'val3': {None: ('new2', None)},
@ -447,21 +409,11 @@ def test_cache_leader_and_followers():
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}}) compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}})
assert values.get_cached() == {} assert values.get_cached() == {}
val1_val2_props = {0: (frozenset([]), None), 1: (frozenset([]), None)} val1_val2_props = {0: (frozenset([]), None), 1: (frozenset([]), None)}
#assert settings.get_cached() == {None: {None: (global_props, None)},
# 'val1': {None: (val1_props, None)},
# 'val1.val1': {None: (val1_val1_props, None)},
# 'val1.val2': val1_val2_props}
#if TIRAMISU_VERSION == 2:
# assert values.get_cached() == {'val1.val1': {None: ([None, None], None)},
# 'val1.val2': {None: ([None, 'oui'], None)}}
#else:
# assert values.get_cached() == {'val1.val1': {None: ([None, None], None)},
# 'val1.val2': {0: (None, None), 1: ('oui', None)}}
def test_cache_leader_callback(): def test_cache_leader_callback():
val1 = StrOption('val1', "", multi=True) val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params=Params(kwargs={'value': ParamOption(val1)})) val2 = StrOption('val2', "", Calculation(calc_value, Params(kwargs={'value': ParamOption(val1)})), multi=True)
interface1 = Leadership('val1', '', [val1, val2]) interface1 = Leadership('val1', '', [val1, val2])
od1 = OptionDescription('rootconfig', '', [interface1]) od1 = OptionDescription('rootconfig', '', [interface1])
cfg = Config(od1) cfg = Config(od1)
@ -487,11 +439,6 @@ def test_cache_leader_callback():
assert values.get_cached() == {} assert values.get_cached() == {}
cfg.value.dict() cfg.value.dict()
#FIXMEassert settings.get_cached() == {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)},
# 'val1': {None: (set([]), None)}}
#FIXMEassert values.get_cached() == {'val1.val1': {None: ([None], None)},
# 'val1.val2': {None: ([None], None)}
# }
def test_cache_requires(): def test_cache_requires():
@ -580,8 +527,8 @@ def test_cache_global_properties():
def test_callback_value_incr(): def test_callback_value_incr():
val1 = IntOption('val1', "", callback=return_incr, properties=('expire',)) val1 = IntOption('val1', "", Calculation(return_incr), properties=('expire',))
val2 = IntOption('val2', "", callback=return_value, callback_params=Params(kwargs={'value': ParamOption(val1)})) val2 = IntOption('val2', "", Calculation(calc_value, Params(ParamOption(val1))))
od1 = OptionDescription('rootconfig', '', [val1, val2]) od1 = OptionDescription('rootconfig', '', [val1, val2])
cfg = Config(od1) cfg = Config(od1)
assert cfg.cache.get_expiration_time() == 5 assert cfg.cache.get_expiration_time() == 5

View file

@ -5,7 +5,7 @@ import weakref
from tiramisu import BoolOption, IntOption, StrOption, IPOption, NetmaskOption, \ from tiramisu import BoolOption, IntOption, StrOption, IPOption, NetmaskOption, \
SymLinkOption, OptionDescription, DynOptionDescription, submulti, \ SymLinkOption, OptionDescription, DynOptionDescription, submulti, \
Config, GroupConfig, MetaConfig, Params, ParamOption Config, GroupConfig, MetaConfig, Params, ParamOption, Calculation
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -242,7 +242,7 @@ def test_deref_callback():
if not IS_DEREFABLE: if not IS_DEREFABLE:
return return
a = StrOption('a', "", 'val') a = StrOption('a', "", 'val')
b = StrOption('b', "", callback=funcname, callback_params=Params((ParamOption(a),))) b = StrOption('b', "", Calculation(funcname, Params((ParamOption(a),))))
od = OptionDescription('root', '', [a, b]) od = OptionDescription('root', '', [a, b])
cfg = Config(od) cfg = Config(od)
w = weakref.ref(a) w = weakref.ref(a)

View file

@ -226,7 +226,7 @@ def test_prop_dyndescription_force_store_value():
def test_callback_dyndescription(): def test_callback_dyndescription():
st = StrOption('st', '', callback=return_dynval) st = StrOption('st', '', Calculation(return_dynval))
dod = DynOptionDescription('dod', '', [st], callback=return_list) dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod]) od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od]) od2 = OptionDescription('od', '', [od])
@ -249,7 +249,7 @@ def test_callback_dyndescription():
def test_callback_list_dyndescription(): def test_callback_list_dyndescription():
st = StrOption('st', '', callback=return_list2, multi=True) st = StrOption('st', '', Calculation(return_list2), multi=True)
dod = DynOptionDescription('dod', '', [st], callback=return_list) dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod]) od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od]) od2 = OptionDescription('od', '', [od])
@ -405,7 +405,7 @@ def test_prop_dyndescription_context():
def test_callback_dyndescription_context(): def test_callback_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True) val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', callback=return_dynval) st = StrOption('st', '', Calculation(return_dynval))
dod = DynOptionDescription('dod', '', [st], callback=return_list) dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod, val1]) od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od]) od2 = OptionDescription('od', '', [od])
@ -776,7 +776,7 @@ def test_consistency_dyndescription_default_multi2():
st2 = StrOption('st2', '', ['yes'], multi=True) st2 = StrOption('st2', '', ['yes'], multi=True)
dod = DynOptionDescription('dod', '', [st, st2], callback=return_list) dod = DynOptionDescription('dod', '', [st, st2], callback=return_list)
dod dod
raises(ValueError, "st.impl_add_consistency('not_equal', st2)") # FIXME raises(ValueError, "st.impl_add_consistency('not_equal', st2)")
def test_consistency_only_one_dyndescription(): def test_consistency_only_one_dyndescription():
@ -1282,7 +1282,7 @@ def test_leadership_submulti_dyndescription():
def test_leadership_callback_dyndescription(): def test_leadership_callback_dyndescription():
st1 = StrOption('st1', "", multi=True) st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params=Params(kwargs={'value': ParamOption(st1)})) st2 = StrOption('st2', "", Calculation(return_dynval, Params(kwargs={'value': ParamOption(st1)})), multi=True)
stm = Leadership('st1', '', [st1, st2]) stm = Leadership('st1', '', [st1, st2])
st1 = DynOptionDescription('st', '', [stm], callback=return_list) st1 = DynOptionDescription('st', '', [stm], callback=return_list)
od1 = OptionDescription('od', '', [st1]) od1 = OptionDescription('od', '', [st1])
@ -1343,7 +1343,7 @@ def test_leadership_callback_dyndescription():
def test_leadership_callback_value_dyndescription(): def test_leadership_callback_value_dyndescription():
st1 = StrOption('st1', "", multi=True) st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params=Params(kwargs={'value': ParamValue('val')})) st2 = StrOption('st2', "", Calculation(return_dynval, Params(kwargs={'value': ParamValue('val')})), multi=True)
stm = Leadership('st1', '', [st1, st2]) stm = Leadership('st1', '', [st1, st2])
st = DynOptionDescription('st', '', [stm], callback=return_list) st = DynOptionDescription('st', '', [stm], callback=return_list)
od = OptionDescription('od', '', [st]) od = OptionDescription('od', '', [st])
@ -1359,7 +1359,7 @@ def test_leadership_callback_value_dyndescription():
def test_leadership_callback_nomulti_dyndescription(): def test_leadership_callback_nomulti_dyndescription():
v11 = StrOption('v1', '', "val") v11 = StrOption('v1', '', "val")
st1 = StrOption('st1', "", multi=True) st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params=Params(ParamOption(v11))) st2 = StrOption('st2', "", Calculation(return_dynval, Params(ParamOption(v11))), multi=True)
stm = Leadership('st1', '', [st1, st2]) stm = Leadership('st1', '', [st1, st2])
stt = DynOptionDescription('st', '', [stm], callback=return_list) stt = DynOptionDescription('st', '', [stm], callback=return_list)
od1 = OptionDescription('od', '', [stt]) od1 = OptionDescription('od', '', [stt])
@ -1374,7 +1374,7 @@ def test_leadership_callback_nomulti_dyndescription():
def test_leadership_callback_samegroup_dyndescription(): def test_leadership_callback_samegroup_dyndescription():
st1 = StrOption('st1', "", multi=True) st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True) st2 = StrOption('st2', "", multi=True)
st3 = StrOption('st3', "", multi=True, callback=return_dynval, callback_params=Params(ParamOption(st2))) st3 = StrOption('st3', "", Calculation(return_dynval, Params(ParamOption(st2))), multi=True)
stm = Leadership('st1', '', [st1, st2, st3]) stm = Leadership('st1', '', [st1, st2, st3])
stt = DynOptionDescription('st', '', [stm], callback=return_list) stt = DynOptionDescription('st', '', [stm], callback=return_list)
od1 = OptionDescription('od', '', [stt]) od1 = OptionDescription('od', '', [stt])

View file

@ -212,21 +212,21 @@ def test_force_store_value_leadership_sub():
def test_force_store_value_callback(): def test_force_store_value_callback():
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val) b = IntOption('int', 'Test int option', Calculation(return_val), properties=('force_store_value',))
descr = OptionDescription("int", "", [b]) descr = OptionDescription("int", "", [b])
api = Config(descr) api = Config(descr)
compare(api.value.exportation(), (('int',), (None,), (1,), ('forced',))) compare(api.value.exportation(), (('int',), (None,), (1,), ('forced',)))
def test_force_store_value_callback_params(): def test_force_store_value_callback_params():
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val2, callback_params=Params(kwargs={'value': ParamValue(2)})) b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamValue(2)})), properties=('force_store_value',))
descr = OptionDescription("int", "", [b]) descr = OptionDescription("int", "", [b])
api = Config(descr) api = Config(descr)
compare(api.value.exportation(), (('int',), (None,), (2,), ('forced',))) compare(api.value.exportation(), (('int',), (None,), (2,), ('forced',)))
def test_force_store_value_callback_params_2(): def test_force_store_value_callback_params_2():
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val3, callback_params=Params(ParamContext(), {'value': ParamValue(2)})) b = IntOption('int', 'Test int option', Calculation(return_val3, Params(ParamContext(), {'value': ParamValue(2)})), properties=('force_store_value',))
descr = OptionDescription("int", "", [b]) descr = OptionDescription("int", "", [b])
api = Config(descr) api = Config(descr)
compare(api.value.exportation(), (('int',), (None,), (2,), ('forced',))) compare(api.value.exportation(), (('int',), (None,), (2,), ('forced',)))
@ -234,7 +234,7 @@ def test_force_store_value_callback_params_2():
def test_force_store_value_callback_params_with_opt(): def test_force_store_value_callback_params_with_opt():
a = IntOption('val1', "", 2) a = IntOption('val1', "", 2)
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val2, callback_params=Params(kwargs={'value': ParamOption(a)})) b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamOption(a)})), properties=('force_store_value',))
descr = OptionDescription("int", "", [a, b]) descr = OptionDescription("int", "", [a, b])
api = Config(descr) api = Config(descr)
compare(api.value.exportation(), (('int',), (None,), (2,), ('forced',))) compare(api.value.exportation(), (('int',), (None,), (2,), ('forced',)))

View file

@ -46,7 +46,7 @@ def make_description2():
stroption2 = SymLinkOption('unicode2', stroption1) stroption2 = SymLinkOption('unicode2', stroption1)
stroption3 = StrOption('str3', 'Test string option', multi=True, stroption3 = StrOption('str3', 'Test string option', multi=True,
properties=('mandatory', )) properties=('mandatory', ))
unicode1 = UnicodeOption('unicode1', 'Test string option', callback=return_value, callback_params=Params(ParamOption(stroption)), properties=('mandatory', )) unicode1 = UnicodeOption('unicode1', 'Test string option', Calculation(return_value, Params(ParamOption(stroption))), properties=('mandatory',))
descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3, unicode1]) descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3, unicode1])
return descr return descr

View file

@ -734,7 +734,7 @@ def test_meta_properties_meta():
def test_meta_exception_meta(): def test_meta_exception_meta():
ip_admin_eth0 = NetworkOption('ip_admin_eth0', "ip", multi=True, default=['192.168.1.1']) ip_admin_eth0 = NetworkOption('ip_admin_eth0', "ip", multi=True, default=['192.168.1.1'])
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "mask", multi=True, callback=raise_exception) netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "mask", Calculation(raise_exception), multi=True)
netmask_admin_eth0.impl_add_consistency('network_netmask', ip_admin_eth0) netmask_admin_eth0.impl_add_consistency('network_netmask', ip_admin_eth0)
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
od = OptionDescription('root', '', [interface1]) od = OptionDescription('root', '', [interface1])
@ -774,7 +774,7 @@ def test_meta_properties_requires_mandatory():
kwargs={'condition': ParamOption(probes), kwargs={'condition': ParamOption(probes),
'expected': ParamValue('yes'), 'expected': ParamValue('yes'),
'default': ParamValue(None)})) 'default': ParamValue(None)}))
ip_eth0 = IPOption('ip_eth0', "ip", properties=(mandatory_property,), callback=return_condition, callback_params=Params(kwargs={'val': ParamOption(ip_address), 'condition': ParamOption(eth0_method), 'expected': ParamValue('dhcp')})) ip_eth0 = IPOption('ip_eth0', "ip", Calculation(return_condition, Params(kwargs={'val': ParamOption(ip_address), 'condition': ParamOption(eth0_method), 'expected': ParamValue('dhcp')})), properties=(mandatory_property,))
ip_gw = IPOption('ip_gw', 'gw') ip_gw = IPOption('ip_gw', 'gw')
ip_gw.impl_add_consistency('not_equal', ip_eth0) ip_gw.impl_add_consistency('not_equal', ip_eth0)
od = OptionDescription('root', '', [ip_gw, probes, eth0_method, ip_address, ip_eth0]) od = OptionDescription('root', '', [ip_gw, probes, eth0_method, ip_address, ip_eth0])
@ -792,10 +792,10 @@ def test_meta_properties_requires_mandatory():
def test_meta_callback(): def test_meta_callback():
val1 = StrOption('val1', "", 'val') val1 = StrOption('val1', "", 'val')
val2 = StrOption('val2', "", callback=return_value, callback_params=Params(ParamOption(val1))) val2 = StrOption('val2', "", Calculation(return_value, Params(ParamOption(val1))))
val3 = StrOption('val3', "", callback=return_value, callback_params=Params(ParamValue('yes'))) val3 = StrOption('val3', "", Calculation(return_value, Params(ParamValue('yes'))))
val4 = StrOption('val4', "", callback=return_value, callback_params=Params(kwargs={'value': ParamOption(val1)})) val4 = StrOption('val4', "", Calculation(return_value, Params(kwargs={'value': ParamOption(val1)})))
val5 = StrOption('val5', "", callback=return_value, callback_params=Params(kwargs={'value': ParamValue('yes')})) val5 = StrOption('val5', "", Calculation(return_value, Params(kwargs={'value': ParamValue('yes')})))
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5]) maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5])
cfg = Config(maconfig, session_id='cfg') cfg = Config(maconfig, session_id='cfg')
meta = MetaConfig([cfg]) meta = MetaConfig([cfg])
@ -816,9 +816,9 @@ def test_meta_callback():
def test_meta_callback_follower(): def test_meta_callback_follower():
val = StrOption('val', "", default='val') val = StrOption('val', "", default='val')
val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val))) val1 = StrOption('val1', "", [Calculation(return_value, Params(ParamOption(val)))], multi=True)
val3 = StrOption('val2', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val1))) val3 = StrOption('val2', "", Calculation(return_value, Params(ParamOption(val1))), multi=True)
val4 = StrOption('val3', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val1))) val4 = StrOption('val3', "", Calculation(return_value, Params(ParamOption(val1))), multi=True)
interface1 = Leadership('val1', '', [val1, val3, val4]) interface1 = Leadership('val1', '', [val1, val3, val4])
od = OptionDescription('root', '', [interface1]) od = OptionDescription('root', '', [interface1])
maconfig = OptionDescription('rootconfig', '', [val, interface1]) maconfig = OptionDescription('rootconfig', '', [val, interface1])

View file

@ -6,7 +6,7 @@ from py.test import raises
from tiramisu.setting import groups, owners from tiramisu.setting import groups, owners
from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, \ from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, \
OptionDescription, Leadership, Config, GroupConfig, MixConfig, \ OptionDescription, Leadership, Config, GroupConfig, MixConfig, \
MetaConfig, Params, ParamOption, ParamValue MetaConfig, Params, ParamOption, ParamValue, Calculation
from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -604,7 +604,7 @@ def test_mix_properties_mix():
def test_mix_exception_mix(): def test_mix_exception_mix():
ip_admin_eth0 = NetworkOption('ip_admin_eth0', "ip", multi=True, default=['192.168.1.1']) ip_admin_eth0 = NetworkOption('ip_admin_eth0', "ip", multi=True, default=['192.168.1.1'])
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "mask", multi=True, callback=raise_exception) netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "mask", Calculation(raise_exception), multi=True)
netmask_admin_eth0.impl_add_consistency('network_netmask', ip_admin_eth0) netmask_admin_eth0.impl_add_consistency('network_netmask', ip_admin_eth0)
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
od = OptionDescription('root', '', [interface1]) od = OptionDescription('root', '', [interface1])
@ -617,10 +617,10 @@ def test_mix_exception_mix():
def test_mix_callback(): def test_mix_callback():
val1 = StrOption('val1', "", 'val') val1 = StrOption('val1', "", 'val')
val2 = StrOption('val2', "", callback=return_value, callback_params=Params(ParamOption(val1))) val2 = StrOption('val2', "", Calculation(return_value, Params(ParamOption(val1))))
val3 = StrOption('val3', "", callback=return_value, callback_params=Params(ParamValue('yes'))) val3 = StrOption('val3', "", Calculation(return_value, Params(ParamValue('yes'))))
val4 = StrOption('val4', "", callback=return_value, callback_params=Params(kwargs={'value': ParamOption(val1)})) val4 = StrOption('val4', "", Calculation(return_value, Params(kwargs={'value': ParamOption(val1)})))
val5 = StrOption('val5', "", callback=return_value, callback_params=Params(kwargs={'value': ParamValue('yes')})) val5 = StrOption('val5', "", Calculation(return_value, Params(kwargs={'value': ParamValue('yes')})))
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5]) maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5])
cfg = Config(maconfig, session_id='cfg') cfg = Config(maconfig, session_id='cfg')
mix = MixConfig(maconfig, [cfg]) mix = MixConfig(maconfig, [cfg])
@ -641,9 +641,9 @@ def test_mix_callback():
def test_mix_callback_follower(): def test_mix_callback_follower():
val = StrOption('val', "", default='val') val = StrOption('val', "", default='val')
val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val))) val1 = StrOption('val1', "", [Calculation(return_value, Params(ParamOption(val)))], multi=True)
val3 = StrOption('val2', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val1))) val3 = StrOption('val2', "", Calculation(return_value, Params(ParamOption(val1))), multi=True)
val4 = StrOption('val3', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val1))) val4 = StrOption('val3', "", Calculation(return_value, Params(ParamOption(val1))), multi=True)
interface1 = Leadership('val1', '', [val1, val3, val4]) interface1 = Leadership('val1', '', [val1, val3, val4])
od = OptionDescription('root', '', [interface1]) od = OptionDescription('root', '', [interface1])
maconfig = OptionDescription('rootconfig', '', [val, interface1]) maconfig = OptionDescription('rootconfig', '', [val, interface1])

View file

@ -7,7 +7,7 @@ do_autopath()
from py.test import raises from py.test import raises
from tiramisu.error import APIError, ConfigError from tiramisu.error import APIError, ConfigError
from tiramisu import IntOption, SymLinkOption, OptionDescription, Config from tiramisu import IntOption, SymLinkOption, OptionDescription, Config, Calculation
from tiramisu.setting import groups from tiramisu.setting import groups
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
from tiramisu.i18n import _ from tiramisu.i18n import _
@ -30,11 +30,11 @@ def test_option_valid_name():
# raises(ValueError, 'IntOption(" ", "")') # raises(ValueError, 'IntOption(" ", "")')
raises(ValueError, 'SymLinkOption(1, i)') raises(ValueError, 'SymLinkOption(1, i)')
i = SymLinkOption("test1", i) i = SymLinkOption("test1", i)
#
#
def test_option_with_callback(): #def test_option_with_callback_legacy():
# no default value with callback # # no default value with callback
raises(ValueError, "IntOption('test', '', default=1, callback=a_func)") # raises(ValueError, "IntOption('test', '', default=1, callback=a_func)")
def test_option_get_information(): def test_option_get_information():
@ -117,8 +117,11 @@ def test_option_multi():
raises(ValueError, "IntOption('test', '', default_multi=1)") raises(ValueError, "IntOption('test', '', default_multi=1)")
#unvalid default_multi #unvalid default_multi
raises(ValueError, "IntOption('test', '', multi=True, default_multi='yes')") raises(ValueError, "IntOption('test', '', multi=True, default_multi='yes')")
#not default_multi with callback
raises(ValueError, "IntOption('test', '', multi=True, default_multi=1, callback=a_func)")
#def test_option_multi_legacy():
# #not default_multi with callback
# #raises(ValueError, "IntOption('test', '', multi=True, default_multi=1, callback=a_func)")
def test_unknown_option(): def test_unknown_option():

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,8 @@ from py.test import raises
from tiramisu.setting import owners, groups from tiramisu.setting import owners, groups
from tiramisu import IPOption, NetworkOption, NetmaskOption, IntOption,\ from tiramisu import IPOption, NetworkOption, NetmaskOption, IntOption,\
BroadcastOption, StrOption, SymLinkOption, OptionDescription, submulti, Leadership,\ BroadcastOption, StrOption, SymLinkOption, OptionDescription, submulti, Leadership,\
Config, undefined, Params, ParamOption Config, undefined, Params, ParamOption, Calculation, ParamIndex
from tiramisu.error import ConfigError, ValueWarning, PropertiesOptionError from tiramisu.error import ConfigError, ValueWarning, PropertiesOptionError
from tiramisu.api import TIRAMISU_VERSION
import warnings import warnings
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
from tiramisu.i18n import _ from tiramisu.i18n import _
@ -469,7 +468,7 @@ def test_consistency_not_equal_multi_default1():
a = IntOption('a', '', multi=True, default=[1]) a = IntOption('a', '', multi=True, default=[1])
b = IntOption('b', '', multi=True, default=[3, 1]) b = IntOption('b', '', multi=True, default=[3, 1])
od = OptionDescription('a', '', [a, b]) od = OptionDescription('a', '', [a, b])
raises(ValueError, "b.impl_add_consistency('not_equal', a)") # FIXME raises(ValueError, "b.impl_add_consistency('not_equal', a)")
def test_consistency_not_equal_multi_default2(): def test_consistency_not_equal_multi_default2():
@ -528,9 +527,8 @@ def test_consistency_default_multi():
b = IntOption('b', '', [1, 1], multi=True) b = IntOption('b', '', [1, 1], multi=True)
c = IntOption('c', '', [1, 2], multi=True) c = IntOption('c', '', [1, 2], multi=True)
b b
raises(ValueError, "a.impl_add_consistency('not_equal', b)") # FIXME raises(ValueError, "a.impl_add_consistency('not_equal', b)")
if TIRAMISU_VERSION != 2: # FIXME raises(ValueError, "a.impl_add_consistency('not_equal', c)")
raises(ValueError, "a.impl_add_consistency('not_equal', c)")
def test_consistency_default_diff(): def test_consistency_default_diff():
@ -774,7 +772,7 @@ def return_netmask2(leader):
def test_consistency_network_netmask_multi_follower_callback(config_type): def test_consistency_network_netmask_multi_follower_callback(config_type):
a = NetworkOption('a', '', multi=True, properties=('mandatory',)) a = NetworkOption('a', '', multi=True, properties=('mandatory',))
b = NetmaskOption('b', '', callback=return_netmask, multi=True, properties=('mandatory',)) b = NetmaskOption('b', '', Calculation(return_netmask, Params(kwargs={'index': ParamIndex()})), multi=True, properties=('mandatory',))
od = Leadership('a', '', [a, b]) od = Leadership('a', '', [a, b])
b.impl_add_consistency('network_netmask', a) b.impl_add_consistency('network_netmask', a)
od2 = OptionDescription('od2', '', [od]) od2 = OptionDescription('od2', '', [od])
@ -803,7 +801,7 @@ def test_consistency_network_netmask_multi_follower_callback(config_type):
def test_consistency_network_netmask_multi_follower_callback_value(config_type): def test_consistency_network_netmask_multi_follower_callback_value(config_type):
a = NetworkOption('a', '', multi=True, properties=('mandatory',)) a = NetworkOption('a', '', multi=True, properties=('mandatory',))
b = NetmaskOption('b', '', callback=return_netmask2, callback_params=Params(ParamOption(a)), multi=True, properties=('mandatory',)) b = NetmaskOption('b', '', Calculation(return_netmask2, Params(ParamOption(a))), multi=True, properties=('mandatory',))
od = Leadership('a', '', [a, b]) od = Leadership('a', '', [a, b])
b.impl_add_consistency('network_netmask', a) b.impl_add_consistency('network_netmask', a)
od2 = OptionDescription('od2', '', [od]) od2 = OptionDescription('od2', '', [od])
@ -1029,7 +1027,7 @@ def return_val(*args, **kwargs):
def test_consistency_with_callback(config_type): def test_consistency_with_callback(config_type):
a = NetworkOption('a', '', default='192.168.1.0') a = NetworkOption('a', '', default='192.168.1.0')
b = NetmaskOption('b', '', default='255.255.255.0') b = NetmaskOption('b', '', default='255.255.255.0')
c = IPOption('c', '', callback=return_val, callback_params=Params(ParamOption(a))) c = IPOption('c', '', Calculation(return_val, Params(ParamOption(a))))
od = OptionDescription('od', '', [a, b, c]) od = OptionDescription('od', '', [a, b, c])
c.impl_add_consistency('in_network', a, b) c.impl_add_consistency('in_network', a, b)
cfg = Config(od) cfg = Config(od)
@ -1066,7 +1064,7 @@ def test_consistency_warnings_only_options_callback(config_type):
a = IPOption('a', '', warnings_only=True) a = IPOption('a', '', warnings_only=True)
b = IPOption('b', '') b = IPOption('b', '')
c = NetworkOption('c', '', default='192.168.1.0') c = NetworkOption('c', '', default='192.168.1.0')
d = NetmaskOption('d', '', callback=return_netmask2, callback_params=Params(ParamOption(c))) d = NetmaskOption('d', '', Calculation(return_netmask2, Params(ParamOption(c))))
od = OptionDescription('od', '', [a, b, c, d]) od = OptionDescription('od', '', [a, b, c, d])
a.impl_add_consistency('not_equal', b) a.impl_add_consistency('not_equal', b)
a.impl_add_consistency('in_network', c, d, transitive=False) a.impl_add_consistency('in_network', c, d, transitive=False)

View file

@ -1197,7 +1197,7 @@ def test_requires_transitive_hidden_disabled_multiple(config_type):
cfg.option('ip_address_service_web').value.get() cfg.option('ip_address_service_web').value.get()
except ConfigError as err: except ConfigError as err:
req = err req = err
error_msg = str(_('unable to carry out a calculation for "{0}", cannot access to option "{1}" because has {2} {3}').format('ip_address_service_web', 'activate_service_web', _('properties'), display_list(['hidden', 'disabled'], add_quote=True))) error_msg = str(_('unable to carry out a calculation for "{}", {}').format('ip_address_service_web', _('cannot access to {0} "{1}" because has {2} {3}').format('option', 'activate_service_web', _('properties'), display_list(['hidden', 'disabled'], add_quote=True))))
assert req, "ip_address_service_web should raise ConfigError" assert req, "ip_address_service_web should raise ConfigError"
assert str(req) == error_msg assert str(req) == error_msg
del req del req
@ -1215,7 +1215,7 @@ def test_requires_transitive_hidden_disabled_multiple(config_type):
cfg.option('ip_address_service_web').value.get() cfg.option('ip_address_service_web').value.get()
except ConfigError as err: except ConfigError as err:
req = err req = err
error_msg = str(_('unable to carry out a calculation for "{0}", cannot access to option "{1}" because has {2} {3}').format('ip_address_service_web', 'activate_service_web', _('properties'), display_list(['hidden', 'disabled'], add_quote=True))) error_msg = str(_('unable to carry out a calculation for "{}", {}').format('ip_address_service_web', _('cannot access to {0} "{1}" because has {2} {3}').format('option', 'activate_service_web', _('properties'), display_list(['hidden', 'disabled'], add_quote=True))))
assert req, "ip_address_service_web should raise RequirementError" assert req, "ip_address_service_web should raise RequirementError"
assert str(req) == error_msg assert str(req) == error_msg
del req del req

View file

@ -7,7 +7,7 @@ from py.test import raises
from tiramisu.api import TIRAMISU_VERSION from tiramisu.api import TIRAMISU_VERSION
from tiramisu.setting import groups, owners from tiramisu.setting import groups, owners
from tiramisu import StrOption, IntOption, OptionDescription, submulti, Leadership, Config, \ from tiramisu import StrOption, IntOption, OptionDescription, submulti, Leadership, Config, \
MetaConfig, undefined, Params, ParamOption MetaConfig, undefined, Params, ParamOption, Calculation
from tiramisu.error import LeadershipError from tiramisu.error import LeadershipError
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -153,7 +153,7 @@ def test_pop_submulti():
def test_callback_submulti_str(): def test_callback_submulti_str():
multi = StrOption('multi', '', multi=submulti, callback=return_val) multi = StrOption('multi', '', [[Calculation(return_val)]], multi=submulti, default_multi=[Calculation(return_val)])
od = OptionDescription('od', '', [multi]) od = OptionDescription('od', '', [multi])
api = Config(od) api = Config(od)
api.property.read_write() api.property.read_write()
@ -168,7 +168,7 @@ def test_callback_submulti_str():
def test_callback_submulti_list(): def test_callback_submulti_list():
multi = StrOption('multi', '', multi=submulti, callback=return_list) multi = StrOption('multi', '', [Calculation(return_list)], multi=submulti, default_multi=Calculation(return_list))
od = OptionDescription('od', '', [multi]) od = OptionDescription('od', '', [multi])
api = Config(od) api = Config(od)
api.property.read_write() api.property.read_write()
@ -176,16 +176,16 @@ def test_callback_submulti_list():
assert api.option('multi').value.get() == [['val', 'val']] assert api.option('multi').value.get() == [['val', 'val']]
assert api.option('multi').owner.get() == owners.default assert api.option('multi').owner.get() == owners.default
api.option('multi').value.set([['val', 'val'], undefined]) api.option('multi').value.set([['val', 'val'], undefined])
assert api.option('multi').owner.get() == owner #assert api.option('multi').owner.get() == owner
assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val']] #assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val']]
api.option('multi').value.set([['val', 'val'], undefined, undefined]) #api.option('multi').value.set([['val', 'val'], undefined, undefined])
assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val'], ['val', 'val']] #assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val'], ['val', 'val']]
api.option('multi').value.reset() #api.option('multi').value.reset()
assert api.option('multi').owner.get() == owners.default #assert api.option('multi').owner.get() == owners.default
def test_callback_submulti_list_list(): def test_callback_submulti_list_list():
multi = StrOption('multi', '', multi=submulti, callback=return_list2) multi = StrOption('multi', '', Calculation(return_list2), multi=submulti)
od = OptionDescription('od', '', [multi]) od = OptionDescription('od', '', [multi])
api = Config(od) api = Config(od)
api.property.read_write() api.property.read_write()
@ -371,7 +371,7 @@ def test_leader_is_submulti():
def test_callback_submulti(): def test_callback_submulti():
multi = StrOption('multi', '', multi=submulti) multi = StrOption('multi', '', multi=submulti)
multi2 = StrOption('multi2', '', multi=submulti, callback=return_val, callback_params=Params(ParamOption(multi))) multi2 = StrOption('multi2', '', Calculation(return_val, Params(ParamOption(multi))), multi=submulti)
od = OptionDescription('multi', '', [multi, multi2]) od = OptionDescription('multi', '', [multi, multi2])
api = Config(od) api = Config(od)
api.property.read_write() api.property.read_write()

View file

@ -111,13 +111,14 @@ def test_symlink_getproperties():
def test_symlink_getcallback(): def test_symlink_getcallback():
boolopt = BoolOption('b', '', callback=return_value) boolopt = BoolOption('b', '', Calculation(return_value))
linkopt = SymLinkOption("c", boolopt) linkopt = SymLinkOption("c", boolopt)
descr = OptionDescription('opt', '', [boolopt, linkopt]) descr = OptionDescription('opt', '', [boolopt, linkopt])
cfg = Config(descr) cfg = Config(descr)
cfg.property.read_write() cfg.property.read_write()
assert boolopt.impl_has_callback() == linkopt.impl_has_callback() == True #assert boolopt.impl_has_callback() == linkopt.impl_has_callback() == True
assert boolopt.impl_get_callback() == linkopt.impl_get_callback() == (return_value, None) #assert boolopt.impl_get_callback() == linkopt.impl_get_callback() == (return_value, None)
assert boolopt.impl_has_callback() == linkopt.impl_has_callback() == False
def test_symlink_requires(config_type): def test_symlink_requires(config_type):

View file

@ -111,7 +111,7 @@ class Calculation:
'has_index') 'has_index')
def __init__(self, def __init__(self,
function: Callable, function: Callable,
params: Optional[Params]=None, params: Params=Params(),
help_function: Optional[Callable]=None): help_function: Optional[Callable]=None):
assert isinstance(function, Callable), _('first argument ({0}) must be a function').format(function) assert isinstance(function, Callable), _('first argument ({0}) must be a function').format(function)
if help_function: if help_function:
@ -120,14 +120,11 @@ class Calculation:
else: else:
self.help_function = None self.help_function = None
self.function = function self.function = function
if params: self.params = params
self.params = params for arg in chain(self.params.args, self.params.kwargs.values()):
for arg in chain(self.params.args, self.params.kwargs.values()): if isinstance(arg, ParamIndex):
if isinstance(arg, ParamIndex): self.has_index = True
self.has_index = True break
break
else:
self.has_index = False
else: else:
self.has_index = False self.has_index = False

View file

@ -32,7 +32,7 @@ from .syndynoptiondescription import SynDynLeadership
from .baseoption import BaseOption from .baseoption import BaseOption
from .option import Option from .option import Option
from ..error import RequirementError from ..error import RequirementError
from ..autolib import ParamOption from ..autolib import Calculation, ParamOption
class Leadership(OptionDescription): class Leadership(OptionDescription):
@ -69,11 +69,13 @@ class Leadership(OptionDescription):
'"{1}" is not a multi' '"{1}" is not a multi'
'').format(self.impl_get_display_name(), '').format(self.impl_get_display_name(),
child.impl_get_display_name())) child.impl_get_display_name()))
if idx != 0 and child.impl_getdefault() != []: if idx != 0:
raise ValueError(_('not allowed default value for follower option "{0}" ' default = child.impl_getdefault()
'in leadership "{1}"' if default != [] and not isinstance(default, Calculation):
'').format(child.impl_get_display_name(), raise ValueError(_('not allowed default value for follower option "{0}" '
self.impl_get_display_name())) 'in leadership "{1}"'
'').format(child.impl_get_display_name(),
self.impl_get_display_name()))
if idx != 0: if idx != 0:
# remove empty property for follower # remove empty property for follower
child_properties = list(child._properties) child_properties = list(child._properties)
@ -82,12 +84,15 @@ class Leadership(OptionDescription):
followers.append(child) followers.append(child)
child._add_dependency(self) child._add_dependency(self)
child._leadership = weakref.ref(self) child._leadership = weakref.ref(self)
callback, callback_params = leader.impl_get_callback() if __debug__:
if callback is not None and callback_params is not None: callback, callback_params = leader.impl_get_callback()
for callbk in chain(callback_params.args, callback_params.kwargs.values()): options = []
if isinstance(callbk, ParamOption) and callbk.option in followers: if callback is not None and callback_params is not None:
raise ValueError(_("callback of leader's option shall " for callbk in chain(callback_params.args, callback_params.kwargs.values()):
"not refered to a follower's ones")) if isinstance(callbk, ParamOption) and callbk.option in followers:
raise ValueError(_("callback of leader's option shall "
"not refered to a follower's ones"))
# leader should not have requires, only Leadership should have # leader should not have requires, only Leadership should have
# so move requires to Leadership # so move requires to Leadership
# if Leadership has requires too, cannot manage this move so raises # if Leadership has requires too, cannot manage this move so raises

View file

@ -22,11 +22,12 @@
import warnings import warnings
import weakref import weakref
from typing import Any, List, Callable, Optional, Dict, Union, Tuple from typing import Any, List, Callable, Optional, Dict, Union, Tuple
from itertools import chain
from .baseoption import BaseOption, submulti, STATIC_TUPLE from .baseoption import BaseOption, submulti, STATIC_TUPLE
from ..i18n import _ from ..i18n import _
from ..setting import undefined, OptionBag, Undefined from ..setting import undefined, OptionBag, Undefined
from ..autolib import carry_out_calculation, Params, ParamValue from ..autolib import Calculation, carry_out_calculation, Params, ParamValue, ParamContext, ParamOption
from ..error import (ConfigError, ValueWarning, ValueErrorWarning, PropertiesOptionError, from ..error import (ConfigError, ValueWarning, ValueErrorWarning, PropertiesOptionError,
ValueOptionError, display_list) ValueOptionError, display_list)
from .syndynoption import SynDynOption from .syndynoption import SynDynOption
@ -123,22 +124,31 @@ class Option(BaseOption):
_setattr(self, '_allow_empty_list', allow_empty_list) _setattr(self, '_allow_empty_list', allow_empty_list)
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):
if isinstance(value, Calculation):
return
try: try:
self._validate(value, self._validate(value,
undefined) undefined)
except ValueError as err: except ValueError as err:
raise ValueError(_("invalid default_multi value {0} " str_err = str(err)
"for option {1}: {2}").format(str(value), if not str_err:
self.impl_getname(), raise ValueError(_('invalid default_multi value "{0}" '
str(err))) 'for option "{1}"').format(str(value),
self.impl_get_display_name()))
else:
raise ValueError(_('invalid default_multi value "{0}" '
'for option "{1}", {2}').format(str(value),
self.impl_get_display_name(),
str_err))
if _multi is submulti: if _multi is submulti:
if not isinstance(default_multi, list): if not isinstance(default_multi, Calculation):
raise ValueError(_('invalid default_multi value "{0}" ' if not isinstance(default_multi, list):
'for option "{1}", must be a list for a submulti' raise ValueError(_('invalid default_multi value "{0}" '
'').format(str(default_multi), 'for option "{1}", must be a list for a submulti'
self.impl_get_display_name())) '').format(str(default_multi),
for value in default_multi: self.impl_get_display_name()))
test_multi_value(value) for value in default_multi:
test_multi_value(value)
else: else:
test_multi_value(default_multi) test_multi_value(default_multi)
_setattr(self, '_default_multi', default_multi) _setattr(self, '_default_multi', default_multi)
@ -151,15 +161,35 @@ class Option(BaseOption):
undefined) undefined)
self.impl_validate(default, self.impl_validate(default,
option_bag) option_bag)
self.value_dependencies(default)
if (is_multi and default != []) or \ if (is_multi and default != []) or \
(not is_multi and default is not None): (not is_multi and default is not None):
if is_multi: if is_multi and isinstance(default, list):
default = tuple(default) default = tuple(default)
_setattr(self, '_default', default) _setattr(self, '_default', default)
self._impl_set_callback(callback, self._impl_set_callback(callback,
callback_params) callback_params)
def value_dependencies(self,
value: Any) -> Any:
if isinstance(value, list):
for val in value:
if isinstance(value, list):
self.value_dependencies(val)
elif isinstance(value, Calculation):
self.value_dependency(val)
elif isinstance(value, Calculation):
self.value_dependency(value)
def value_dependency(self,
value: Any) -> Any:
for param in chain(value.params.args, value.params.kwargs.values()):
if isinstance(param, ParamContext):
self._has_calc_context = True
elif isinstance(param, ParamOption):
param.option._add_dependency(self)
#__________________________________________________________________________ #__________________________________________________________________________
# option's information # option's information
@ -195,7 +225,7 @@ class Option(BaseOption):
else: else:
default = None default = None
else: else:
if is_multi: if is_multi and isinstance(default, list):
default = list(default) default = list(default)
return default return default
@ -287,6 +317,8 @@ class Option(BaseOption):
if isinstance(_value, list): if isinstance(_value, list):
raise ValueError(_('which must not be a list').format(_value, raise ValueError(_('which must not be a list').format(_value,
self.impl_get_display_name())) self.impl_get_display_name()))
if isinstance(_value, Calculation) and config_bag is undefined:
return
if _value is not None: if _value is not None:
if check_error: if check_error:
# option validation # option validation
@ -327,11 +359,15 @@ class Option(BaseOption):
else: else:
do_validation(val, do_validation(val,
force_index) force_index)
elif isinstance(value, Calculation) and config_bag is undefined:
pass
elif not isinstance(value, list): elif not isinstance(value, list):
raise ValueError(_('which must be a list')) raise ValueError(_('which must be a list'))
elif self.impl_is_submulti(): elif self.impl_is_submulti():
for err_index, lval in enumerate(value): for err_index, lval in enumerate(value):
_is_not_unique(lval) _is_not_unique(lval)
if isinstance(lval, Calculation):
continue
if not isinstance(lval, list): if not isinstance(lval, list):
raise ValueError(_('which "{}" must be a list of list' raise ValueError(_('which "{}" must be a list of list'
'').format(lval)) '').format(lval))
@ -344,7 +380,7 @@ class Option(BaseOption):
do_validation(val, do_validation(val,
err_index) err_index)
if not is_warnings_only or not check_error: if (not is_warnings_only or not check_error) and not isinstance(value, Calculation):
self.valid_consistency(option_bag, self.valid_consistency(option_bag,
value, value,
check_error, check_error,
@ -448,9 +484,12 @@ class Option(BaseOption):
undefined, undefined,
None, None,
undefined) undefined)
self.impl_validate(self.impl_getdefault(), default = self.impl_getdefault()
if isinstance(default, tuple):
default = list(default)
self.impl_validate(default,
option_bag) option_bag)
self.impl_validate(self.impl_getdefault(), self.impl_validate(default,
option_bag, option_bag,
check_error=False) check_error=False)
if func != '_cons_not_equal': if func != '_cons_not_equal':

View file

@ -19,7 +19,7 @@ import weakref
from typing import Optional, Any, Callable from typing import Optional, Any, Callable
from .error import ConfigError, PropertiesOptionError, RequirementError from .error import ConfigError, PropertiesOptionError, RequirementError
from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag
from .autolib import carry_out_calculation, Params from .autolib import Calculation, carry_out_calculation, Params
from .i18n import _ from .i18n import _
@ -109,6 +109,17 @@ class Values(object):
return True return True
return False return False
def _do_value_list(self,
value: Any,
option_bag: OptionBag):
for val in value:
if isinstance(val, (list, tuple)):
yield list(self._do_value_list(val, option_bag))
elif isinstance(val, Calculation):
yield val.execute(option_bag)
else:
yield val
def getvalue(self, def getvalue(self,
option_bag): option_bag):
"""actually retrieves the value """actually retrieves the value
@ -118,6 +129,7 @@ class Values(object):
:returns: value :returns: value
""" """
# get owner and value from store # get owner and value from store
# index allowed only for follower # index allowed only for follower
index = option_bag.index index = option_bag.index
@ -130,11 +142,21 @@ class Values(object):
owners.default, owners.default,
index=_index, index=_index,
with_value=True) with_value=True)
if owner != owners.default and \ if owner == owners.default or \
not ('frozen' in option_bag.properties and 'force_default_on_freeze' in option_bag.properties) and \ ('frozen' in option_bag.properties and \
not ('frozen' in option_bag.properties and self.force_to_metaconfig(option_bag)): ('force_default_on_freeze' in option_bag.properties or self.force_to_metaconfig(option_bag))):
return value value = self.getdefaultvalue(option_bag)
return self.getdefaultvalue(option_bag) else:
value = self.calc_value(option_bag, value)
return value
def calc_value(self, option_bag, value):
if isinstance(value, Calculation):
value = value.execute(option_bag)
elif isinstance(value, (list, tuple)):
value = list(self._do_value_list(value, option_bag))
self.calculate_reset_cache(option_bag, value)
return value
def getdefaultvalue(self, def getdefaultvalue(self,
option_bag): option_bag):
@ -160,34 +182,36 @@ class Values(object):
# - if option is a submulti, return a list a list # - if option is a submulti, return a list a list
# - if option is a multi, return a list # - if option is a multi, return a list
# - default value # - default value
if option_bag.option.impl_is_multi() and option_bag.index is not None: value = self.calc_value(option_bag, value)
if option_bag.option.impl_is_multi() and option_bag.index is not None and isinstance(value, (list, tuple)):
# if index, must return good value for this index # if index, must return good value for this index
if len(value) > option_bag.index: if len(value) > option_bag.index:
value = value[option_bag.index] value = value[option_bag.index]
else: else:
# no value for this index, retrieve default multi value # no value for this index, retrieve default multi value
# default_multi is already a list for submulti # default_multi is already a list for submulti
value = option_bag.option.impl_getdefault_multi() value = self.calc_value(option_bag, option_bag.option.impl_getdefault_multi())
return value return value
def calculate_reset_cache(self, option_bag, value):
if not 'expire' in option_bag.properties:
return
cache = option_bag.config_bag.context._impl_values_cache
is_cache, cache_value, validated = cache.getcache(option_bag.path,
None,
option_bag.index,
option_bag.config_bag.properties,
option_bag.properties,
'value')
if not is_cache or cache_value == value:
# calculation return same value as previous value,
# so do not invalidate cache
return
# calculated value is a new value, so reset cache
option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
def calculate_value(self, def calculate_value(self,
option_bag: OptionBag) -> Any: option_bag: OptionBag) -> Any:
def _reset_cache(_value):
if not 'expire' in option_bag.properties:
return
cache = option_bag.config_bag.context._impl_values_cache
is_cache, cache_value, validated = cache.getcache(option_bag.path,
None,
option_bag.index,
option_bag.config_bag.properties,
option_bag.properties,
'value')
if not is_cache or cache_value == _value:
# calculation return same value as previous value,
# so do not invalidate cache
return
# calculated value is a new value, so reset cache
option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
# if value has callback, calculate value # if value has callback, calculate value
callback, callback_params = option_bag.option.impl_get_callback() callback, callback_params = option_bag.option.impl_get_callback()
@ -198,11 +222,11 @@ class Values(object):
# if value is a list and index is set # if value is a list and index is set
if option_bag.option.impl_is_submulti() and (value == [] or not isinstance(value[0], list)): if option_bag.option.impl_is_submulti() and (value == [] or not isinstance(value[0], list)):
# return value only if it's a submulti and not a list of list # return value only if it's a submulti and not a list of list
_reset_cache(value) self.calculate_reset_cache(option_bag, value)
return value return value
if len(value) > option_bag.index: if len(value) > option_bag.index:
# return the value for specified index if found # return the value for specified index if found
_reset_cache(value[option_bag.index]) self.calculate_reset_cache(option_bag, value[option_bag.index])
return value[option_bag.index] return value[option_bag.index]
# there is no calculate value for this index, # there is no calculate value for this index,
# so return an other default value # so return an other default value
@ -222,7 +246,7 @@ class Values(object):
elif option_bag.option.impl_is_multi() and not isinstance(value, list) and option_bag.index is None: elif option_bag.option.impl_is_multi() and not isinstance(value, list) and option_bag.index is None:
# return a list for a multi # return a list for a multi
value = [value] value = [value]
_reset_cache(value) self.calculate_reset_cache(option_bag, value)
return value return value
return undefined return undefined