consistency is now simple validation
This commit is contained in:
parent
e62268c46a
commit
5c3a133928
37 changed files with 1163 additions and 6135 deletions
|
@ -5,11 +5,9 @@ from .autopath import do_autopath
|
|||
do_autopath()
|
||||
from .config import config_type, get_config, value_list, global_owner
|
||||
|
||||
from tiramisu.setting import owners
|
||||
from tiramisu import ChoiceOption, StrOption, OptionDescription, Config
|
||||
from tiramisu import ChoiceOption, StrOption, OptionDescription, Config, owners, Calculation, \
|
||||
undefined, Params, ParamValue, ParamOption, list_sessions
|
||||
from tiramisu.error import ConfigError
|
||||
from tiramisu import undefined, Params, ParamValue, ParamOption
|
||||
from tiramisu.storage import list_sessions
|
||||
|
||||
|
||||
def teardown_function(function):
|
||||
|
@ -58,7 +56,7 @@ def test_choiceoption(config_type):
|
|||
|
||||
|
||||
def test_choiceoption_function(config_type):
|
||||
choice = ChoiceOption('choice', '', values=return_list)
|
||||
choice = ChoiceOption('choice', '', values=Calculation(return_list))
|
||||
odesc = OptionDescription('od', '', [choice])
|
||||
cfg = Config(odesc)
|
||||
cfg.property.read_write()
|
||||
|
@ -79,7 +77,7 @@ def test_choiceoption_function(config_type):
|
|||
|
||||
|
||||
def test_choiceoption_function_error():
|
||||
choice = ChoiceOption('choice', '', values=return_error)
|
||||
choice = ChoiceOption('choice', '', values=Calculation(return_error))
|
||||
odesc = OptionDescription('od', '', [choice])
|
||||
cfg = Config(odesc)
|
||||
cfg.property.read_write()
|
||||
|
@ -87,7 +85,7 @@ def test_choiceoption_function_error():
|
|||
|
||||
|
||||
def test_choiceoption_function_error_args():
|
||||
choice = ChoiceOption('choice', '', values=return_error, values_params=Params((ParamValue('val1'),)))
|
||||
choice = ChoiceOption('choice', '', values=Calculation(return_error, Params(ParamValue('val1'))))
|
||||
odesc = OptionDescription('od', '', [choice])
|
||||
cfg = Config(odesc)
|
||||
cfg.property.read_write()
|
||||
|
@ -95,7 +93,7 @@ def test_choiceoption_function_error_args():
|
|||
|
||||
|
||||
def test_choiceoption_function_error_kwargs():
|
||||
choice = ChoiceOption('choice', '', values=return_error, values_params=Params(kwargs={'kwargs': ParamValue('val1')}))
|
||||
choice = ChoiceOption('choice', '', values=Calculation(return_error, Params(kwargs={'kwargs': ParamValue('val1')})))
|
||||
odesc = OptionDescription('od', '', [choice])
|
||||
cfg = Config(odesc)
|
||||
cfg.property.read_write()
|
||||
|
@ -103,7 +101,7 @@ def test_choiceoption_function_error_kwargs():
|
|||
|
||||
|
||||
def test_choiceoption_calc_function(config_type):
|
||||
choice = ChoiceOption('choice', "", values=return_calc_list, values_params=Params((ParamValue('val1'),)))
|
||||
choice = ChoiceOption('choice', "", values=Calculation(return_calc_list, Params(ParamValue('val1'))))
|
||||
odesc = OptionDescription('od', '', [choice])
|
||||
cfg = Config(odesc)
|
||||
cfg.property.read_write()
|
||||
|
@ -125,8 +123,7 @@ def test_choiceoption_calc_opt_function(config_type):
|
|||
str_ = StrOption('str', '', 'val1')
|
||||
choice = ChoiceOption('choice',
|
||||
"",
|
||||
values=return_calc_list,
|
||||
values_params=Params((ParamOption(str_),)))
|
||||
values=Calculation(return_calc_list, Params(ParamOption(str_))))
|
||||
odesc = OptionDescription('od', '', [str_, choice])
|
||||
cfg = Config(odesc)
|
||||
cfg.property.read_write()
|
||||
|
@ -148,8 +145,7 @@ def test_choiceoption_calc_opt_function_propertyerror():
|
|||
str_ = StrOption('str', '', 'val1', properties=('disabled',))
|
||||
choice = ChoiceOption('choice',
|
||||
"",
|
||||
values=return_calc_list,
|
||||
values_params=Params((ParamOption(str_),)))
|
||||
values=Calculation(return_calc_list, Params(ParamOption(str_))))
|
||||
odesc = OptionDescription('od', '', [str_, choice])
|
||||
cfg = Config(odesc)
|
||||
cfg.property.read_write()
|
||||
|
@ -164,14 +160,12 @@ def test_choiceoption_calc_opt_multi_function():
|
|||
choice = ChoiceOption('choice',
|
||||
"",
|
||||
default_multi='val2',
|
||||
values=return_val,
|
||||
values_params=Params((ParamOption(str_),)),
|
||||
values=Calculation(return_val, Params(ParamOption(str_))),
|
||||
multi=True)
|
||||
ch2 = ChoiceOption('ch2',
|
||||
"",
|
||||
default=['val2'],
|
||||
values=return_val,
|
||||
values_params=Params((ParamOption(str_),)),
|
||||
values=Calculation(return_val, Params(ParamOption(str_))),
|
||||
multi=True)
|
||||
odesc = OptionDescription('od', '', [str_, choice, ch2])
|
||||
cfg = Config(odesc)
|
||||
|
@ -203,14 +197,12 @@ def test_choiceoption_calc_opt_multi_function_kwargs(config_type):
|
|||
choice = ChoiceOption('choice',
|
||||
"",
|
||||
default_multi='val2',
|
||||
values=return_val,
|
||||
values_params=Params(kwargs={'val': ParamOption(str_)}),
|
||||
values=Calculation(return_val, Params(kwargs={'val': ParamOption(str_)})),
|
||||
multi=True)
|
||||
ch2 = ChoiceOption('ch2',
|
||||
"",
|
||||
default=['val2'],
|
||||
values=return_val,
|
||||
values_params=Params(kwargs={'val': ParamOption(str_)}),
|
||||
values=Calculation(return_val, Params(kwargs={'val': ParamOption(str_)})),
|
||||
multi=True)
|
||||
odesc = OptionDescription('od', '', [str_, choice, ch2])
|
||||
cfg = Config(odesc)
|
||||
|
@ -237,21 +229,12 @@ def test_choiceoption_calc_opt_multi_function_kwargs(config_type):
|
|||
raises(ValueError, "cfg.option('ch2').value.get()")
|
||||
|
||||
|
||||
def test_choiceoption_calc_invalid():
|
||||
str_ = StrOption('str', '', ['val1'], multi=True)
|
||||
str_
|
||||
raises(ValueError,
|
||||
"choice = ChoiceOption('choice', '', default_multi='val2', values=[1, 2, 3], \
|
||||
values_params=Params((ParamOption(str_),)), multi=True)")
|
||||
|
||||
|
||||
def test_choiceoption_calc_not_list():
|
||||
str_ = StrOption('str', '', 'val1')
|
||||
choice = ChoiceOption('choice',
|
||||
"",
|
||||
default_multi='val2',
|
||||
values=return_val,
|
||||
values_params=Params((ParamOption(str_),)),
|
||||
values=Calculation(return_val, Params(ParamOption(str_))),
|
||||
multi=True)
|
||||
odesc = OptionDescription('od', '', [str_, choice])
|
||||
cfg = Config(odesc)
|
||||
|
|
|
@ -139,77 +139,11 @@ def test_deref_optiondescription_config():
|
|||
assert w() is None
|
||||
|
||||
|
||||
#def test_deref_groupconfig():
|
||||
# if not IS_DEREFABLE:
|
||||
# return
|
||||
# i1 = IntOption('i1', '')
|
||||
# od1 = OptionDescription('od1', '', [i1])
|
||||
# od2 = OptionDescription('od2', '', [od1])
|
||||
# conf1 = Config(od2, 'conf1')
|
||||
# conf2 = Config(od2, 'conf2')
|
||||
# meta = GroupConfig([conf1, conf2])
|
||||
# w = weakref.ref(conf1)
|
||||
# del(conf1)
|
||||
# assert w() is not None
|
||||
# del(meta)
|
||||
# assert w() is None
|
||||
|
||||
|
||||
#def test_deref_metaconfig():
|
||||
# if not IS_DEREFABLE:
|
||||
# return
|
||||
# i1 = IntOption('i1', '')
|
||||
# od1 = OptionDescription('od1', '', [i1])
|
||||
# od2 = OptionDescription('od2', '', [od1])
|
||||
# conf1 = Config(od2, 'conf1')
|
||||
# conf2 = Config(od2, 'conf2')
|
||||
# meta = MetaConfig([conf1, conf2])
|
||||
# w = weakref.ref(conf1)
|
||||
# del(conf1)
|
||||
# assert w() is not None
|
||||
# del(meta)
|
||||
# assert w() is None
|
||||
|
||||
|
||||
def test_deref_consistency():
|
||||
if not IS_DEREFABLE:
|
||||
return
|
||||
a = IPOption('a', '')
|
||||
b = NetmaskOption('b', '')
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
b.impl_add_consistency('ip_netmask', a)
|
||||
cfg = Config(od)
|
||||
w = weakref.ref(a)
|
||||
x = weakref.ref(b)
|
||||
y = weakref.ref(od)
|
||||
z = weakref.ref(cfg)
|
||||
assert w() is not None
|
||||
assert x() is not None
|
||||
assert y() is not None
|
||||
assert z() is not None
|
||||
del(a)
|
||||
del(b)
|
||||
assert w() is not None
|
||||
assert x() is not None
|
||||
assert y() is not None
|
||||
assert z() is not None
|
||||
del(od)
|
||||
assert w() is not None
|
||||
assert x() is not None
|
||||
assert y() is not None
|
||||
assert z() is not None
|
||||
del(cfg)
|
||||
assert y() is None
|
||||
assert z() is None
|
||||
#assert w() is None
|
||||
#assert x() is None
|
||||
|
||||
|
||||
def test_deref_validator():
|
||||
if not IS_DEREFABLE:
|
||||
return
|
||||
a = StrOption('a', '', default='yes')
|
||||
b = StrOption('b', '', validator=funcname, validator_params=Params((ParamOption(a),)), default='val')
|
||||
b = StrOption('b', '', validators=[Calculation(funcname, Params(ParamOption(a)))], default='val')
|
||||
od = OptionDescription('root', '', [a, b])
|
||||
cfg = Config(od)
|
||||
w = weakref.ref(a)
|
||||
|
@ -234,8 +168,6 @@ def test_deref_validator():
|
|||
del(cfg)
|
||||
assert y() is None
|
||||
assert z() is None
|
||||
#assert w() is None
|
||||
#assert x() is None
|
||||
|
||||
|
||||
def test_deref_callback():
|
||||
|
@ -267,8 +199,6 @@ def test_deref_callback():
|
|||
del(cfg)
|
||||
assert y() is None
|
||||
assert z() is None
|
||||
#assert w() is None
|
||||
#assert x() is None
|
||||
|
||||
|
||||
def test_deref_symlink():
|
||||
|
@ -298,8 +228,6 @@ def test_deref_symlink():
|
|||
assert w() is not None
|
||||
assert x() is not None
|
||||
del(cfg)
|
||||
#assert w() is None
|
||||
#assert x() is None
|
||||
assert y() is None
|
||||
assert z() is None
|
||||
|
||||
|
@ -333,7 +261,5 @@ def test_deref_dyn():
|
|||
assert w() is not None
|
||||
assert x() is not None
|
||||
del(cfg)
|
||||
#assert w() is None
|
||||
#assert x() is None
|
||||
assert y() is None
|
||||
assert z() is None
|
||||
|
|
|
@ -9,7 +9,7 @@ from tiramisu import BoolOption, StrOption, ChoiceOption, IPOption, \
|
|||
UnicodeOption, PortOption, BroadcastOption, DomainnameOption, \
|
||||
EmailOption, URLOption, UsernameOption, FilenameOption, SymLinkOption, \
|
||||
OptionDescription, DynOptionDescription, SynDynOption, submulti, Leadership, \
|
||||
Config, Params, ParamOption, ParamValue, Calculation, calc_value
|
||||
Config, Params, ParamOption, ParamValue, ParamSuffix, ParamSelfOption, Calculation, calc_value
|
||||
from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError
|
||||
from tiramisu.storage import list_sessions
|
||||
|
||||
|
@ -28,7 +28,7 @@ def return_dynval(value='val', suffix=None):
|
|||
return value
|
||||
|
||||
|
||||
def return_list2(suffix=None):
|
||||
def return_list2(suffix):
|
||||
return [str(suffix), 'val2']
|
||||
|
||||
|
||||
|
@ -249,7 +249,7 @@ def test_callback_dyndescription():
|
|||
|
||||
|
||||
def test_callback_list_dyndescription():
|
||||
st = StrOption('st', '', Calculation(return_list2), multi=True)
|
||||
st = StrOption('st', '', Calculation(return_list2, Params(ParamSuffix())), multi=True)
|
||||
dod = DynOptionDescription('dod', '', [st], suffixes=Calculation(return_list))
|
||||
od = OptionDescription('od', '', [dod])
|
||||
od2 = OptionDescription('od', '', [od])
|
||||
|
@ -675,7 +675,7 @@ def test_requires_dyndescription2():
|
|||
|
||||
def test_validator_dyndescription():
|
||||
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
|
||||
st = StrOption('st', '', validator=return_true, validator_params=Params((ParamValue('yes'),)), default='val')
|
||||
st = StrOption('st', '', validators=[Calculation(return_true, Params((ParamSelfOption(), ParamValue('yes'))))], default='val')
|
||||
dod = DynOptionDescription('dod', '', [st], suffixes=Calculation(return_list))
|
||||
od = OptionDescription('od', '', [dod, val1])
|
||||
od2 = OptionDescription('od', '', [od])
|
||||
|
@ -735,108 +735,13 @@ def test_information_dyndescription_context():
|
|||
assert api.information.get('testcfgod') == 'val3'
|
||||
|
||||
|
||||
def test_consistency_dyndescription():
|
||||
st1 = StrOption('st', '')
|
||||
st2 = StrOption('st2', '')
|
||||
dod = DynOptionDescription('dod', '', [st1, st2], suffixes=Calculation(return_list))
|
||||
od1 = OptionDescription('od', '', [dod])
|
||||
st1.impl_add_consistency('not_equal', st2)
|
||||
od2 = OptionDescription('od', '', [od1])
|
||||
api = Config(od2)
|
||||
api.option('od.dodval1.stval1').value.set('yes')
|
||||
raises(ValueError, "api.option('od.dodval1.st2val1').value.set('yes')")
|
||||
api.option('od.dodval2.stval2').value.set('yes')
|
||||
raises(ValueError, "api.option('od.dodval2.st2val2').value.set('yes')")
|
||||
raises(ValueError, "api.option('od.dodval1.st2val1').value.set('yes')")
|
||||
api.option('od.dodval2.stval2').value.reset()
|
||||
raises(ValueError, "api.option('od.dodval1.st2val1').value.set('yes')")
|
||||
api.option('od.dodval2.st2val2').value.set('yes')
|
||||
raises(ValueError, "api.option('od.dodval2.stval2').value.set('yes')")
|
||||
#
|
||||
api.option('od.dodval1.stval1').value.reset()
|
||||
api.option('od.dodval2.st2val2').value.reset()
|
||||
api.option('od.dodval1.st2val1').value.set('yes')
|
||||
raises(ValueError, "api.option('od.dodval1.stval1').value.set('yes')")
|
||||
|
||||
|
||||
def test_consistency_dyndescription_default():
|
||||
st = StrOption('st', '', 'yes')
|
||||
st2 = StrOption('st2', '')
|
||||
dod = DynOptionDescription('dod', '', [st, st2], suffixes=Calculation(return_list))
|
||||
od = OptionDescription('od', '', [dod])
|
||||
st.impl_add_consistency('not_equal', st2)
|
||||
od2 = OptionDescription('od', '', [od])
|
||||
api = Config(od2)
|
||||
raises(ValueError, "api.option('od.dodval1.st2val1').value.set('yes')")
|
||||
raises(ValueError, "api.option('od.dodval2.st2val2').value.set('yes')")
|
||||
|
||||
|
||||
def test_consistency_dyndescription_default_multi2():
|
||||
st = StrOption('st', '', ['yes'], multi=True)
|
||||
st2 = StrOption('st2', '', ['yes'], multi=True)
|
||||
dod = DynOptionDescription('dod', '', [st, st2], suffixes=Calculation(return_list))
|
||||
dod
|
||||
# FIXME raises(ValueError, "st.impl_add_consistency('not_equal', st2)")
|
||||
|
||||
|
||||
def test_consistency_only_one_dyndescription():
|
||||
st = StrOption('st', '')
|
||||
st
|
||||
st2 = StrOption('st2', '')
|
||||
dod = DynOptionDescription('dod', '', [st2], suffixes=Calculation(return_list))
|
||||
raises(ConfigError, "st.impl_add_consistency('not_equal', st2)")
|
||||
raises(ConfigError, "st2.impl_add_consistency('not_equal', st)")
|
||||
|
||||
|
||||
def test_consistency_became_dyndescription():
|
||||
st = StrOption('st', '')
|
||||
st2 = StrOption('st2', '')
|
||||
st2.impl_add_consistency('not_equal', st)
|
||||
od = DynOptionDescription('dod', '', [st2], suffixes=Calculation(return_list))
|
||||
od2 = OptionDescription('od', '', [od, st])
|
||||
od2
|
||||
raises(ConfigError, "c = Config(od2)")
|
||||
|
||||
|
||||
def test_consistency_became_dyndescription2():
|
||||
st = StrOption('st', '')
|
||||
st2 = StrOption('st2', '')
|
||||
st.impl_add_consistency('not_equal', st2)
|
||||
od = DynOptionDescription('dod', '', [st2], suffixes=Calculation(return_list))
|
||||
od2 = OptionDescription('od', '', [od, st])
|
||||
od2
|
||||
raises(ConfigError, "c = Config(od2)")
|
||||
|
||||
|
||||
def test_consistency_external_dyndescription():
|
||||
st = StrOption('st', '')
|
||||
st1 = StrOption('st1', '')
|
||||
st2 = StrOption('st2', '')
|
||||
dod = DynOptionDescription('dod', '', [st1, st2], suffixes=Calculation(return_list))
|
||||
od = OptionDescription('od', '', [dod, st])
|
||||
od
|
||||
raises(ConfigError, "st.impl_add_consistency('not_equal', st2)")
|
||||
|
||||
|
||||
def test_consistency_notsame_dyndescription():
|
||||
st1 = StrOption('st1', '')
|
||||
st2 = StrOption('st2', '')
|
||||
dod = DynOptionDescription('dod', '', [st1, st2], suffixes=Calculation(return_list))
|
||||
tst1 = StrOption('tst1', '')
|
||||
tst2 = StrOption('tst2', '')
|
||||
tdod = DynOptionDescription('tdod', '', [tst1, tst2], suffixes=Calculation(return_list))
|
||||
od = OptionDescription('od', '', [dod, tdod])
|
||||
od
|
||||
raises(ConfigError, "st1.impl_add_consistency('not_equal', tst1)")
|
||||
|
||||
|
||||
def test_all_dyndescription():
|
||||
st = StrOption('st', '')
|
||||
ip = IPOption('ip', '')
|
||||
network = NetworkOption('network', '')
|
||||
netmask = NetmaskOption('netmask', '')
|
||||
ch = ChoiceOption('ch', '', ('val1', 'val2', 'val3'))
|
||||
ch1 = ChoiceOption('ch1', '', return_list)
|
||||
ch1 = ChoiceOption('ch1', '', Calculation(return_list))
|
||||
boo = BoolOption('boo', '')
|
||||
intr = IntOption('intr', '')
|
||||
floa = FloatOption('floa', '')
|
||||
|
@ -925,34 +830,6 @@ def test_all_dyndescription():
|
|||
assert api.option('dodval2.filenameval2').value.get() is None
|
||||
|
||||
|
||||
def test_consistency_ip_netmask_dyndescription():
|
||||
ipa = IPOption('a', '')
|
||||
netb = NetmaskOption('b', '')
|
||||
dod = DynOptionDescription('dod', '', [ipa, netb], suffixes=Calculation(return_list))
|
||||
netb.impl_add_consistency('ip_netmask', ipa)
|
||||
od1 = OptionDescription('od', '', [dod])
|
||||
cfg = Config(od1)
|
||||
cfg.option('dodval1.aval1').value.set('192.168.1.1')
|
||||
cfg.option('dodval1.bval1').value.set('255.255.255.0')
|
||||
cfg.option('dodval2.aval2').value.set('192.168.1.2')
|
||||
cfg.option('dodval2.bval2').value.set('255.255.255.128')
|
||||
cfg.option('dodval2.bval2').value.set('255.255.255.0')
|
||||
raises(ValueError, "cfg.option('dodval2.bval2').value.set('255.255.255.255')")
|
||||
|
||||
|
||||
def test_consistency_ip_in_network_dyndescription():
|
||||
neta = NetworkOption('a', '')
|
||||
netb = NetmaskOption('b', '')
|
||||
ipc = IPOption('c', '')
|
||||
dod = DynOptionDescription('dod', '', [neta, netb, ipc], suffixes=Calculation(return_list))
|
||||
ipc.impl_add_consistency('in_network', neta, netb)
|
||||
od1 = OptionDescription('od', '', [dod])
|
||||
cfg = Config(od1)
|
||||
cfg.option('dodval1.aval1').value.set('192.168.1.0')
|
||||
cfg.option('dodval1.bval1').value.set('255.255.255.0')
|
||||
cfg.option('dodval1.cval1').value.set('192.168.1.1')
|
||||
|
||||
|
||||
def test_leadership_dyndescription():
|
||||
st1 = StrOption('st1', "", multi=True)
|
||||
st2 = StrOption('st2', "", multi=True)
|
||||
|
|
|
@ -178,15 +178,6 @@ def test_force_store_value():
|
|||
compare(conf.value.exportation(), (('wantref', 'wantref2', 'wantref3'), (None, None, None), (False, False, (False,)), ('forced', 'forced', 'forced')))
|
||||
|
||||
|
||||
def test_force_store_value_no_requirement():
|
||||
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||
try:
|
||||
BoolOption('wantref', 'Test requires', default=False,
|
||||
requires=({'option': booloption, 'expected': True, 'action': 'force_store_value'},))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
def test_force_store_value_leadership_follower():
|
||||
b = IntOption('int', 'Test int option', multi=True)
|
||||
c = StrOption('str', 'Test string option', multi=True, properties=('force_store_value',))
|
||||
|
|
|
@ -330,9 +330,9 @@ def test_groups_with_leader_default_value_2(config_type):
|
|||
|
||||
|
||||
def test_groups_with_leader_hidden_in_config():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True, properties=('hidden',))
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('hidden',))
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0], properties=('hidden',))
|
||||
od = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
|
@ -412,22 +412,6 @@ def test_groups_with_leader_reset_out_of_range(config_type):
|
|||
cfg.send()
|
||||
|
||||
|
||||
def test_groups_with_leader_hidden_in_config3():
|
||||
#if leader is hidden, follower are hidden too
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True, properties=('hidden',))
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
cfg.permissive.set(frozenset(['hidden']))
|
||||
assert cfg.forcepermissive.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||
cfg.forcepermissive.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1'])
|
||||
assert cfg.forcepermissive.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
raises(PropertiesOptionError, "cfg.option('ip_admin_eth0.ip_admin_eth0').value.get()")
|
||||
raises(PropertiesOptionError, "cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
|
||||
|
||||
def test_allowed_groups():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
|
@ -449,7 +433,8 @@ def test_values_with_leader_disabled_leader(config_type):
|
|||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])
|
||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set("192.168.230.145")
|
||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.reset()
|
||||
cfg_ori.option('ip_admin_eth0.ip_admin_eth0').property.add('disabled')
|
||||
raises(LeadershipError, "cfg_ori.option('ip_admin_eth0.ip_admin_eth0').property.add('disabled')")
|
||||
cfg_ori.option('ip_admin_eth0').property.add('disabled')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
if config_type != 'tiramisu-api':
|
||||
# FIXME
|
||||
|
@ -847,49 +832,7 @@ def test_follower_not_multi():
|
|||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
||||
raises(ValueError, "Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])")
|
||||
|
||||
|
||||
def test_follower_not_same():
|
||||
ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
ip_admin_eth1 = IPOption('ip_admin_eth1', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth1 = NetmaskOption('netmask_admin_eth1', "masque du sous-réseau", multi=True)
|
||||
netmask_admin_eth1.impl_add_consistency('ip_netmask', ip_admin_eth0)
|
||||
interface1 = Leadership('interface1', '', [ip_admin_eth1, netmask_admin_eth1])
|
||||
od1 = OptionDescription('od', '', [interface0, interface1])
|
||||
maconfig = OptionDescription('toto', '', [od1])
|
||||
raises(ConfigError, "Config(maconfig)")
|
||||
|
||||
|
||||
def test_follower_not_same_not_equal():
|
||||
ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
ip_admin_eth1 = IPOption('ip_admin_eth1', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth1 = NetmaskOption('netmask_admin_eth1', "masque du sous-réseau", multi=True)
|
||||
netmask_admin_eth1.impl_add_consistency('not_equal', netmask_admin_eth0)
|
||||
interface1 = Leadership('interface1', '', [ip_admin_eth1, netmask_admin_eth1])
|
||||
od1 = OptionDescription('od', '', [interface0, interface1])
|
||||
maconfig = OptionDescription('toto', '', [od1])
|
||||
cfg = Config(maconfig)
|
||||
cfg.property.read_write()
|
||||
|
||||
|
||||
def test_follower_consistency():
|
||||
network_admin_eth1 = NetworkOption('network_admin_eth1', "ip réseau autorisé", multi=True, default=['1.1.1.1'])
|
||||
netmask_admin_eth1 = NetmaskOption('netmask_admin_eth1', "masque du sous-réseau", multi=True)
|
||||
netmask_admin_eth1.impl_add_consistency('network_netmask', network_admin_eth1)
|
||||
interface1 = Leadership('interface1', '', [network_admin_eth1, netmask_admin_eth1])
|
||||
od1 = OptionDescription('od', '', [interface1])
|
||||
maconfig = OptionDescription('toto', '', [od1])
|
||||
cfg = Config(maconfig)
|
||||
cfg.property.read_write()
|
||||
cfg.option('od.interface1.network_admin_eth1').value.set(['192.168.1.128', '192.168.2.0', '192.168.3.128'])
|
||||
cfg.option('od.interface1.netmask_admin_eth1', 0).value.set('255.255.255.128')
|
||||
cfg.option('od.interface1.netmask_admin_eth1', 1).value.set('255.255.255.0')
|
||||
cfg.option('od.interface1.netmask_admin_eth1', 2).value.set('255.255.255.128')
|
||||
cfg.option('od.interface1.network_admin_eth1').value.pop(0)
|
||||
#
|
||||
|
||||
|
||||
def test_follower_force_store_value():
|
||||
|
|
|
@ -5,7 +5,8 @@ do_autopath()
|
|||
from tiramisu.setting import groups, owners
|
||||
from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, BoolOption, ChoiceOption, \
|
||||
IPOption, OptionDescription, Leadership, Config, GroupConfig, MetaConfig, \
|
||||
Calculation, Params, ParamOption, ParamValue, calc_value
|
||||
Calculation, Params, ParamOption, ParamValue, calc_value, ParamSelfOption, \
|
||||
valid_network_netmask, valid_not_equal
|
||||
from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError
|
||||
from tiramisu.storage import list_sessions
|
||||
from .config import config_type, get_config
|
||||
|
@ -719,9 +720,8 @@ def test_meta_force_default_and_dont_change():
|
|||
|
||||
def test_meta_properties_meta():
|
||||
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, properties=('disabled',))
|
||||
netmask_admin_eth0.impl_add_consistency('network_netmask', ip_admin_eth0)
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "mask", multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(ip_admin_eth0), ParamSelfOption())))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0], properties=('disabled',))
|
||||
od = OptionDescription('root', '', [interface1])
|
||||
conf1 = Config(od, session_id='conf1')
|
||||
conf2 = Config(od, session_id='conf2')
|
||||
|
@ -734,8 +734,7 @@ def test_meta_properties_meta():
|
|||
|
||||
def test_meta_exception_meta():
|
||||
ip_admin_eth0 = NetworkOption('ip_admin_eth0', "ip", multi=True, default=['192.168.1.1'])
|
||||
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 = NetmaskOption('netmask_admin_eth0', "mask", Calculation(raise_exception), multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(ip_admin_eth0), ParamSelfOption())))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od = OptionDescription('root', '', [interface1])
|
||||
conf1 = Config(od, session_id='conf1')
|
||||
|
@ -753,8 +752,7 @@ def test_meta_properties_requires1():
|
|||
kwargs={'condition': ParamOption(opt1, todict=True),
|
||||
'expected': ParamValue(False)}))
|
||||
od2 = OptionDescription('od2', "", [opt2], properties=(disabled_property,))
|
||||
opt3 = BoolOption('opt3', '')
|
||||
opt2.impl_add_consistency('not_equal', opt3)
|
||||
opt3 = BoolOption('opt3', '', validators=[Calculation(valid_not_equal, Params((ParamOption(opt2), ParamSelfOption())))])
|
||||
od = OptionDescription('root', '', [opt1, od2, opt3])
|
||||
conf1 = Config(od, session_id='conf1')
|
||||
conf1.property.read_write()
|
||||
|
@ -775,8 +773,7 @@ def test_meta_properties_requires_mandatory():
|
|||
'expected': ParamValue('yes'),
|
||||
'default': ParamValue(None)}))
|
||||
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.impl_add_consistency('not_equal', ip_eth0)
|
||||
ip_gw = IPOption('ip_gw', 'gw', validators=[Calculation(valid_not_equal, Params((ParamOption(ip_eth0), ParamSelfOption())))])
|
||||
od = OptionDescription('root', '', [ip_gw, probes, eth0_method, ip_address, ip_eth0])
|
||||
conf1 = Config(od, session_id='conf1')
|
||||
conf1.property.read_write()
|
||||
|
|
|
@ -6,7 +6,8 @@ from py.test import raises
|
|||
from tiramisu.setting import groups, owners
|
||||
from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, \
|
||||
OptionDescription, Leadership, Config, GroupConfig, MixConfig, \
|
||||
MetaConfig, Params, ParamOption, ParamValue, Calculation
|
||||
MetaConfig, Params, ParamOption, ParamValue, ParamSelfOption, Calculation, \
|
||||
valid_network_netmask
|
||||
from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError
|
||||
from tiramisu.storage import list_sessions
|
||||
|
||||
|
@ -589,9 +590,8 @@ def test_mix_force_default_and_dont_change():
|
|||
|
||||
def test_mix_properties_mix():
|
||||
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, properties=('disabled',))
|
||||
netmask_admin_eth0.impl_add_consistency('network_netmask', ip_admin_eth0)
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "mask", multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(ip_admin_eth0), ParamSelfOption())))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0], properties=('disabled',))
|
||||
od = OptionDescription('root', '', [interface1])
|
||||
conf1 = Config(od, session_id='conf1')
|
||||
conf2 = Config(od, session_id='conf2')
|
||||
|
@ -604,8 +604,7 @@ def test_mix_properties_mix():
|
|||
|
||||
def test_mix_exception_mix():
|
||||
ip_admin_eth0 = NetworkOption('ip_admin_eth0', "ip", multi=True, default=['192.168.1.1'])
|
||||
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 = NetmaskOption('netmask_admin_eth0', "mask", Calculation(raise_exception), multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(ip_admin_eth0), ParamSelfOption())))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
od = OptionDescription('root', '', [interface1])
|
||||
conf1 = Config(od, session_id='conf1')
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@ from .config import config_type, get_config
|
|||
from py.test import raises
|
||||
|
||||
from tiramisu.setting import owners
|
||||
from tiramisu.error import PropertiesOptionError, ConfigError
|
||||
from tiramisu.error import PropertiesOptionError, ConfigError, LeadershipError
|
||||
from tiramisu import IntOption, FloatOption, StrOption, ChoiceOption, \
|
||||
BoolOption, OptionDescription, Leadership, Config, undefined
|
||||
from tiramisu.storage import list_sessions
|
||||
|
@ -163,7 +163,7 @@ def test_force_default_on_freeze_leader_frozen():
|
|||
descr = Leadership("dummy1", "", [dummy1, dummy2])
|
||||
descr = OptionDescription("root", "", [descr])
|
||||
cfg = Config(descr)
|
||||
raises(ConfigError, "cfg.option('dummy1.dummy1').property.pop('frozen')")
|
||||
raises(LeadershipError, "cfg.option('dummy1.dummy1').property.pop('frozen')")
|
||||
|
||||
|
||||
def test_force_metaconfig_on_freeze_leader_frozen():
|
||||
|
@ -172,7 +172,7 @@ def test_force_metaconfig_on_freeze_leader_frozen():
|
|||
descr = Leadership("dummy1", "", [dummy1, dummy2])
|
||||
descr = OptionDescription("root", "", [descr])
|
||||
cfg = Config(descr)
|
||||
raises(ConfigError, "cfg.option('dummy1.dummy1').property.pop('frozen')")
|
||||
raises(LeadershipError, "cfg.option('dummy1.dummy1').property.pop('frozen')")
|
||||
|
||||
|
||||
def test_force_default_on_freeze_follower(config_type):
|
||||
|
|
|
@ -10,9 +10,11 @@ from tiramisu.error import display_list, ConfigError
|
|||
from tiramisu.setting import owners, groups
|
||||
from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
|
||||
StrOption, OptionDescription, Leadership, Config, undefined, \
|
||||
Calculation, Params, ParamOption, ParamValue, ParamIndex, calc_value, calc_value_property_help
|
||||
Calculation, Params, ParamOption, ParamValue, ParamIndex, \
|
||||
calc_value, calc_value_property_help
|
||||
from tiramisu.error import PropertiesOptionError
|
||||
from tiramisu.storage import list_sessions
|
||||
import warnings
|
||||
|
||||
|
||||
def teardown_function(function):
|
||||
|
|
|
@ -5,9 +5,13 @@ from .config import config_type, get_config
|
|||
import warnings
|
||||
from py.test import raises
|
||||
|
||||
from tiramisu import BoolOption, StrOption, OptionDescription, Leadership, Config, Params, ParamValue, ParamOption, ParamContext
|
||||
from tiramisu import BoolOption, StrOption, IPOption, NetmaskOption, NetworkOption, BroadcastOption, \
|
||||
IntOption, \
|
||||
OptionDescription, Leadership, Config, Params, ParamValue, ParamOption, ParamContext, \
|
||||
ParamSelfOption, ParamIndex, Calculation, valid_ip_netmask, valid_network_netmask, \
|
||||
valid_in_network, valid_broadcast, valid_not_equal, undefined
|
||||
from tiramisu.setting import groups
|
||||
from tiramisu.error import ValueWarning, ConfigError
|
||||
from tiramisu.error import ValueWarning, ConfigError, PropertiesOptionError
|
||||
from tiramisu.i18n import _
|
||||
from tiramisu.storage import list_sessions
|
||||
|
||||
|
@ -82,15 +86,6 @@ def value_values_auto2(value, values, auto=False):
|
|||
|
||||
|
||||
|
||||
def value_values_index2(value, values, index, auto=False):
|
||||
if auto != False:
|
||||
raise ValueError('auto should be False')
|
||||
if not (value == 'val1' and values == ['val1'] and index == 'val' or
|
||||
value == 'val1' and values == ['val1', None] and index == 'val' or
|
||||
value == 'val2' and values == ['val1', 'val2'] and index == 'val'):
|
||||
raise ValueError('error')
|
||||
|
||||
|
||||
def value_empty(value, empty, values):
|
||||
if not value == 'val' or empty is not False and not values == ['val']:
|
||||
raise ValueError('error')
|
||||
|
@ -103,9 +98,9 @@ def valid_from_config(value, config):
|
|||
|
||||
|
||||
def test_validator(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=return_true, default='val')
|
||||
raises(ValueError, "StrOption('opt2', '', validator=return_false, default='val')")
|
||||
opt2 = StrOption('opt2', '', validator=return_false)
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params(ParamSelfOption()))], default='val')
|
||||
raises(ValueError, "StrOption('opt2', '', validators=[Calculation(return_false, Params(ParamSelfOption()))], default='val')")
|
||||
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params(ParamSelfOption()))])
|
||||
root = OptionDescription('root', '', [opt1, opt2])
|
||||
cfg_ori = Config(root)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
|
@ -138,9 +133,9 @@ def test_validator(config_type):
|
|||
|
||||
|
||||
def test_validator_params(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=return_true, validator_params=Params(ParamValue('yes')), default='val')
|
||||
raises(ValueError, "StrOption('opt2', '', validator=return_false, validator_params=Params(ParamValue('yes')), default='val')")
|
||||
opt2 = StrOption('opt2', '', validator=return_false, validator_params=Params(ParamValue('yes')))
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfOption(), ParamValue('yes'))))], default='val')
|
||||
raises(ValueError, "StrOption('opt2', '', validators=[Calculation(return_false, Params((ParamSelfOption(), ParamValue('yes'))))], default='val')")
|
||||
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params((ParamSelfOption(), ParamValue('yes'))))])
|
||||
root = OptionDescription('root', '', [opt1, opt2])
|
||||
cfg_ori = Config(root)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
|
@ -157,7 +152,7 @@ def test_validator_params(config_type):
|
|||
|
||||
|
||||
def test_validator_params_value_values(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=value_values, default=['val'], multi=True)
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(value_values, Params((ParamSelfOption(whole=False), ParamSelfOption())))], default=['val'], multi=True)
|
||||
root = OptionDescription('root', '', [opt1])
|
||||
cfg = Config(root)
|
||||
cfg = get_config(cfg, config_type)
|
||||
|
@ -166,7 +161,7 @@ def test_validator_params_value_values(config_type):
|
|||
|
||||
|
||||
def test_validator_params_value_values_index(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=value_values_index, default=['val'], multi=True)
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(value_values_index, Params((ParamSelfOption(whole=False), ParamSelfOption(), ParamIndex())))], default=['val'], multi=True)
|
||||
root = OptionDescription('root', '', [opt1])
|
||||
cfg = Config(root)
|
||||
cfg = get_config(cfg, config_type)
|
||||
|
@ -175,7 +170,7 @@ def test_validator_params_value_values_index(config_type):
|
|||
|
||||
|
||||
def test_validator_params_value_values_leader(config_type):
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validator=value_values)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validators=[Calculation(value_values, Params((ParamSelfOption(whole=False), ParamSelfOption())))])
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True)
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
|
@ -186,7 +181,7 @@ def test_validator_params_value_values_leader(config_type):
|
|||
|
||||
|
||||
def test_validator_params_value_values_index_leader(config_type):
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validator=value_values_index)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validators=[Calculation(value_values_index, Params((ParamSelfOption(whole=False), ParamSelfOption(), ParamIndex())))])
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True)
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
|
@ -198,7 +193,7 @@ def test_validator_params_value_values_index_leader(config_type):
|
|||
|
||||
def test_validator_params_value_values_follower(config_type):
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validator=value_values)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validators=[Calculation(value_values, Params((ParamSelfOption(), ParamSelfOption(whole=True))))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(root)
|
||||
|
@ -212,7 +207,7 @@ def test_validator_params_value_values_follower(config_type):
|
|||
|
||||
def test_validator_params_value_values_index_follower(config_type):
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validator=value_values_index)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validators=[Calculation(value_values_index, Params((ParamSelfOption(), ParamSelfOption(whole=True), ParamIndex())))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(root)
|
||||
|
@ -224,18 +219,13 @@ def test_validator_params_value_values_index_follower(config_type):
|
|||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val2')
|
||||
|
||||
|
||||
def test_validator_params_value_values_notmulti():
|
||||
raises(ConfigError, "opt1 = StrOption('opt1', '', validator=value_values, default='val')")
|
||||
|
||||
|
||||
def test_validator_params_value_values_kwargs_empty(config_type):
|
||||
v = BoolOption('v', '', default=False)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, default=["ip"])
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
|
||||
"masque du sous-reseau",
|
||||
multi=True,
|
||||
validator=value_empty,
|
||||
validator_params=Params(ParamOption(v)))
|
||||
validators=[Calculation(value_empty, Params((ParamSelfOption(), ParamOption(v))))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [v, interface1])
|
||||
cfg = Config(root)
|
||||
|
@ -252,8 +242,7 @@ def test_validator_params_value_values_kwargs(config_type):
|
|||
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
|
||||
"masque du sous-reseau",
|
||||
multi=True,
|
||||
validator=value_values_auto,
|
||||
validator_params=Params(kwargs={'auto': ParamOption(v)}))
|
||||
validators=[Calculation(value_values_auto, Params((ParamSelfOption(), ParamSelfOption(whole=True)), kwargs={'auto': ParamOption(v)}))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [v, interface1])
|
||||
cfg = Config(root)
|
||||
|
@ -269,43 +258,7 @@ def test_validator_params_value_values_kwargs_values(config_type):
|
|||
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
|
||||
"masque du sous-reseau",
|
||||
multi=True,
|
||||
validator=value_values_auto2,
|
||||
validator_params=Params(kwargs={'values': ParamOption(ip_admin_eth0)}))
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(root)
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
|
||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
|
||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val'])
|
||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val2')
|
||||
|
||||
|
||||
def test_validator_params_value_values_kwargs2(config_type):
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
|
||||
"masque du sous-reseau",
|
||||
multi=True,
|
||||
validator=value_values_index2,
|
||||
validator_params=Params(ParamValue(['val1']), {'index': ParamOption(ip_admin_eth0)}))
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(root)
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
|
||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('val1')
|
||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val'])
|
||||
|
||||
|
||||
def test_validator_params_value_values_kwargs_index(config_type):
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
|
||||
"masque du sous-reseau",
|
||||
multi=True,
|
||||
validator=value_values_index2,
|
||||
validator_params=Params(kwargs={'index': ParamOption(ip_admin_eth0)}))
|
||||
validators=[Calculation(value_values_auto2, Params(ParamSelfOption(), kwargs={'values': ParamOption(ip_admin_eth0)}))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(root)
|
||||
|
@ -318,7 +271,7 @@ def test_validator_params_value_values_kwargs_index(config_type):
|
|||
|
||||
|
||||
def test_validator_params_context():
|
||||
opt1 = StrOption('opt1', '', validator=is_context, validator_params=Params(ParamContext()), default='val')
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(is_context, Params((ParamSelfOption(), ParamContext())))], default='val')
|
||||
root = OptionDescription('root', '', [opt1])
|
||||
cfg = Config(root)
|
||||
# cfg = get_config(cfg, config_type) # ParamContext not supported
|
||||
|
@ -329,7 +282,7 @@ def test_validator_params_context():
|
|||
|
||||
def test_validator_params_context_value():
|
||||
opt1 = StrOption('opt1', '', 'yes')
|
||||
opt2 = StrOption('opt2', '', validator=valid_from_config, validator_params=Params(ParamContext()), default='val')
|
||||
opt2 = StrOption('opt2', '', validators=[Calculation(valid_from_config, Params((ParamSelfOption(), ParamContext())))], default='val')
|
||||
root = OptionDescription('root', '', [opt1, opt2])
|
||||
cfg = Config(root)
|
||||
# cfg = get_config(cfg_ori, config_type) # ParamContext not supported
|
||||
|
@ -347,8 +300,8 @@ def test_validator_params_context_value():
|
|||
|
||||
|
||||
def test_validator_params_key(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=return_true, validator_params=Params(kwargs={'param': ParamValue('yes')}), default='val')
|
||||
raises(ConfigError, "StrOption('opt2', '', validator=return_true, validator_params=Params(kwargs={'param_unknown': ParamValue('yes')}), default='val')")
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params(ParamSelfOption(), kwargs={'param': ParamValue('yes')}))], default='val')
|
||||
raises(ConfigError, "StrOption('opt2', '', validators=[Calculation(return_true, Params(ParamSelfOption(), kwargs={'param_unknown': ParamValue('yes')}))], default='val')")
|
||||
root = OptionDescription('root', '', [opt1])
|
||||
cfg = Config(root)
|
||||
cfg = get_config(cfg, config_type)
|
||||
|
@ -357,7 +310,7 @@ def test_validator_params_key(config_type):
|
|||
|
||||
def test_validator_params_option(config_type):
|
||||
opt0 = StrOption('opt0', '', default='yes')
|
||||
opt1 = StrOption('opt1', '', validator=return_true, validator_params=Params(ParamOption(opt0)), default='val')
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfOption(), ParamOption(opt0))))], default='val')
|
||||
r = OptionDescription('root', '', [opt0, opt1])
|
||||
cfg_ori = Config(r)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
|
@ -375,7 +328,7 @@ def test_validator_params_option(config_type):
|
|||
|
||||
|
||||
def test_validator_multi(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=return_if_val, multi=True)
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_if_val, Params(ParamSelfOption(whole=False)))], multi=True)
|
||||
root = OptionDescription('root', '', [opt1])
|
||||
cfg_ori = Config(root)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
|
@ -394,9 +347,9 @@ def test_validator_multi(config_type):
|
|||
|
||||
|
||||
def test_validator_warning(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=return_true, default='val', warnings_only=True)
|
||||
opt2 = StrOption('opt2', '', validator=return_false, warnings_only=True)
|
||||
opt3 = StrOption('opt3', '', validator=return_if_val, multi=True, warnings_only=True)
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params(ParamSelfOption()), warnings_only=True)], default='val')
|
||||
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params(ParamSelfOption()), warnings_only=True)])
|
||||
opt3 = StrOption('opt3', '', validators=[Calculation(return_if_val, Params(ParamSelfOption(whole=False)), warnings_only=True)], multi=True)
|
||||
root = OptionDescription('root', '', [opt1, opt2, opt3])
|
||||
cfg = Config(root)
|
||||
cfg = get_config(cfg, config_type)
|
||||
|
@ -440,9 +393,9 @@ def test_validator_warning(config_type):
|
|||
|
||||
|
||||
def test_validator_warning_disabled(config_type):
|
||||
opt1 = StrOption('opt1', '', validator=return_true, default='val', warnings_only=True)
|
||||
opt2 = StrOption('opt2', '', validator=return_false, warnings_only=True)
|
||||
opt3 = StrOption('opt3', '', validator=return_if_val, multi=True, warnings_only=True)
|
||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params(ParamSelfOption()), warnings_only=True)], default='val')
|
||||
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params(ParamSelfOption()), warnings_only=True)])
|
||||
opt3 = StrOption('opt3', '', validators=[Calculation(return_if_val, Params(ParamSelfOption(whole=False)), warnings_only=True)], multi=True)
|
||||
root = OptionDescription('root', '', [opt1, opt2, opt3])
|
||||
cfg_ori = Config(root)
|
||||
cfg_ori.property.pop('warnings')
|
||||
|
@ -485,8 +438,8 @@ def test_validator_warning_disabled(config_type):
|
|||
def test_validator_warning_leadership(config_type):
|
||||
display_name_ip = "ip reseau autorise"
|
||||
display_name_netmask = "masque du sous-reseau"
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', display_name_ip, multi=True, validator=return_false, warnings_only=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', display_name_netmask, multi=True, validator=return_if_val, warnings_only=True)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', display_name_ip, multi=True, validators=[Calculation(return_false, Params(ParamSelfOption(whole=False)), warnings_only=True)])
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', display_name_netmask, multi=True, validators=[Calculation(return_if_val, Params(ParamSelfOption()), warnings_only=True)])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
assert interface1.impl_get_group_type() == groups.leadership
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
|
@ -543,8 +496,7 @@ def test_validator_follower_param(config_type):
|
|||
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
|
||||
"masque du sous-reseau",
|
||||
multi=True,
|
||||
validator=return_true,
|
||||
validator_params=Params(kwargs={'param': ParamOption(ip_admin_eth0)}))
|
||||
validators=[Calculation(return_true, Params(ParamSelfOption(), kwargs={'param': ParamOption(ip_admin_eth0)}))])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
root = OptionDescription('root', '', [interface1])
|
||||
cfg = Config(root)
|
||||
|
@ -560,9 +512,8 @@ def test_validator_dependencies():
|
|||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise")
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0',
|
||||
"masque du sous-reseau",
|
||||
validator=return_true,
|
||||
validator_params=Params(kwargs={'param': ParamOption(ip_admin_eth0)}))
|
||||
opt2 = StrOption('opt2', '', validator=return_false)
|
||||
validators=[Calculation(return_true, Params(ParamSelfOption(whole=False), kwargs={'param': ParamOption(ip_admin_eth0)}))])
|
||||
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params(ParamSelfOption(whole=False)))])
|
||||
root = OptionDescription('root', '', [ip_admin_eth0, netmask_admin_eth0, opt2])
|
||||
cfg = Config(root)
|
||||
assert cfg.option('ip_admin_eth0').option.has_dependency() is False
|
||||
|
@ -572,3 +523,611 @@ def test_validator_dependencies():
|
|||
assert cfg.option('ip_admin_eth0').option.has_dependency(False) is True
|
||||
assert cfg.option('netmask_admin_eth0').option.has_dependency(False) is False
|
||||
assert cfg.option('opt2').option.has_dependency(False) is False
|
||||
|
||||
|
||||
def test_validator_ip_netmask(config_type):
|
||||
a = IPOption('a', '')
|
||||
b = NetmaskOption('b', '', validators=[Calculation(valid_ip_netmask, Params((ParamOption(a, todict=True), ParamSelfOption())))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg_ori = Config(od)
|
||||
cfg = cfg_ori
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('a').value.set('192.168.1.1')
|
||||
cfg.option('b').value.set('255.255.255.0')
|
||||
cfg.option('a').value.set('192.168.1.2')
|
||||
cfg.option('b').value.set('255.255.255.128')
|
||||
cfg.option('b').value.set('255.255.255.0')
|
||||
cfg.option('a').value.set('192.168.1.0')
|
||||
raises(ValueError, "cfg.option('b').value.get()")
|
||||
cfg.option('a').value.set('192.168.1.255')
|
||||
raises(ValueError, "cfg.option('b').value.get()")
|
||||
cfg.option('a').value.reset()
|
||||
cfg.option('b').value.reset()
|
||||
cfg.option('a').value.set('192.168.1.255')
|
||||
raises(ValueError, "cfg.option('b').value.set('255.255.255.0')")
|
||||
#
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.add('demoting_error_warning')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('b').value.set('255.255.255.0')
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_network_netmask(config_type):
|
||||
a = NetworkOption('a', '')
|
||||
b = NetmaskOption('b', '', validators=[Calculation(valid_network_netmask, Params((ParamOption(a, todict=True), ParamSelfOption())))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg_ori = Config(od)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('a').value.set('192.168.1.1')
|
||||
cfg.option('b').value.set('255.255.255.255')
|
||||
cfg.option('b').value.reset()
|
||||
cfg.option('a').value.set('192.168.1.0')
|
||||
cfg.option('b').value.set('255.255.255.0')
|
||||
cfg.option('a').value.set('192.168.1.1')
|
||||
raises(ValueError, "cfg.option('b').value.get()")
|
||||
#
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.add('demoting_error_warning')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('a').value.set('192.168.1.1')
|
||||
assert len(w) == 0
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('b').value.get()
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_ip_in_network(config_type):
|
||||
a = NetworkOption('a', '')
|
||||
b = NetmaskOption('b', '')
|
||||
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))))])
|
||||
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))), warnings_only=True)])
|
||||
od = OptionDescription('od', '', [a, b, c, d])
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
cfg = Config(od)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a').value.set('192.168.1.0')
|
||||
cfg.option('b').value.set('255.255.255.0')
|
||||
cfg.option('c').value.set('192.168.1.1')
|
||||
raises(ValueError, "cfg.option('c').value.set('192.168.2.1')")
|
||||
raises(ValueError, "cfg.option('c').value.set('192.168.1.0')")
|
||||
raises(ValueError, "cfg.option('c').value.set('192.168.1.255')")
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('d').value.set('192.168.2.1')
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_ip_in_network_cidr(config_type):
|
||||
a = NetworkOption('a', '', cidr=True)
|
||||
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
||||
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=True)])
|
||||
od = OptionDescription('od', '', [a, c, d])
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
cfg = Config(od)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a').value.set('192.168.1.0/24')
|
||||
cfg.option('c').value.set('192.168.1.1')
|
||||
raises(ValueError, "cfg.option('c').value.set('192.168.2.1')")
|
||||
raises(ValueError, "cfg.option('c').value.set('192.168.1.0')")
|
||||
raises(ValueError, "cfg.option('c').value.set('192.168.1.255')")
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('d').value.set('192.168.2.1')
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_ip_netmask_multi(config_type):
|
||||
a = IPOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_ip_netmask, Params((ParamOption(a, todict=True), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg_ori = Config(od2)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.a').value.set(['192.168.1.2'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.128')
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.get()")
|
||||
#
|
||||
cfg.option('a.a').value.set(['192.168.1.2'])
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.add('demoting_error_warning')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('a.b', 0).value.get()
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_network_netmask_multi(config_type):
|
||||
a = NetworkOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.255')
|
||||
cfg.option('a.b', 0).value.reset()
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.get()")
|
||||
|
||||
|
||||
def test_validator_network_netmask_multi_follower_default_multi(config_type):
|
||||
a = NetworkOption('a', '', default_multi=u'192.168.1.0', multi=True, properties=('mandatory',))
|
||||
b = NetmaskOption('b', '', default_multi=u'255.255.255.0', multi=True, properties=('mandatory',), validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_write()
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a.a').value.set([undefined])
|
||||
assert cfg.option('a.a').value.get() == ['192.168.1.0']
|
||||
assert cfg.option('a.b', 0).value.get() == '255.255.255.0'
|
||||
|
||||
|
||||
def test_validator_network_netmask_multi_follower_default(config_type):
|
||||
a = NetworkOption('a', '', multi=True, properties=('mandatory',))
|
||||
b = NetmaskOption('b', '', default_multi=u'255.255.255.0', multi=True, properties=('mandatory',), validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg_ori = Config(od2)
|
||||
cfg_ori.property.read_write()
|
||||
cfg_ori.property.pop('cache')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert cfg.option('a.a').value.get() == []
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.read_only()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert cfg.option('a.a').value.get() == [u'192.168.1.0']
|
||||
assert cfg.option('a.b', 0).value.get() == u'255.255.255.0'
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.read_write()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('a.a').value.set([u'192.168.1.0', u'192.168.1.1'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.set([u'192.168.1.0'])")
|
||||
raises(ValueError, "cfg.option('a.b', 1).value.set([u'192.168.1.1'])")
|
||||
cfg.option('a.a').value.set(['192.168.1.0', undefined])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.b', 1).value.set('255.255.255.255')
|
||||
cfg.option('a.a').value.set([u'192.168.1.0', u'192.168.1.1'])
|
||||
|
||||
|
||||
def return_netmask(*args, **kwargs):
|
||||
return u'255.255.255.0'
|
||||
|
||||
|
||||
def return_netmask2(leader):
|
||||
if leader is not None:
|
||||
if leader.endswith('2.1'):
|
||||
return u'255.255.255.0'
|
||||
if not leader.endswith('.0'):
|
||||
return u'255.255.255.255'
|
||||
return u'255.255.255.0'
|
||||
|
||||
|
||||
def test_validator_network_netmask_multi_follower_callback(config_type):
|
||||
a = NetworkOption('a', '', multi=True, properties=('mandatory',))
|
||||
b = NetmaskOption('b', '', Calculation(return_netmask, Params(kwargs={'index': ParamIndex()})), multi=True, properties=('mandatory',), validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg_ori = Config(od2)
|
||||
cfg_ori.property.read_write()
|
||||
cfg_ori.property.pop('cache')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert cfg.option('a.a').value.get() == []
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.read_only()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert cfg.option('a.a').value.get() == [u'192.168.1.0']
|
||||
assert cfg.option('a.b', 0).value.get() == '255.255.255.0'
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.read_write()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('a.a').value.set([u'192.168.1.0', u'192.168.1.1'])
|
||||
cfg.option('a.b', 0).value.get()
|
||||
raises(ValueError, "cfg.option('a.b', 1).value.get()")
|
||||
cfg.option('a.a').value.set(['192.168.1.0', undefined])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.b', 1).value.set('255.255.255.255')
|
||||
cfg.option('a.a').value.set(['192.168.1.0', '192.168.1.1'])
|
||||
|
||||
|
||||
def test_validator_network_netmask_multi_follower_callback_value(config_type):
|
||||
a = NetworkOption('a', '', multi=True, properties=('mandatory',))
|
||||
b = NetmaskOption('b', '', Calculation(return_netmask2, Params(ParamOption(a))), multi=True, properties=('mandatory',), validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_write()
|
||||
cfg.property.pop('cache')
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('a.a').value.get() == []
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
assert cfg.option('a.a').value.get() == ['192.168.1.0']
|
||||
assert cfg.option('a.b', 0).value.get() == '255.255.255.0'
|
||||
cfg.option('a.a').value.set(['192.168.1.0', '192.168.2.1'])
|
||||
assert cfg.option('a.b', 0).value.get() == '255.255.255.0'
|
||||
raises(ValueError, "cfg.option('a.b', 1).value.get()")
|
||||
cfg.option('a.a').value.pop(1)
|
||||
#
|
||||
assert cfg.option('a.a').value.get() == [u'192.168.1.0']
|
||||
assert cfg.option('a.b', 0).value.get() == '255.255.255.0'
|
||||
cfg.option('a.a').value.set(['192.168.2.1'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.get()")
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
#
|
||||
assert cfg.option('a.a').value.get() == [u'192.168.1.0']
|
||||
assert cfg.option('a.b', 0).value.get() == '255.255.255.0'
|
||||
cfg.option('a.a').value.set(['192.168.1.0', '192.168.1.1'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.b', 1).value.set('255.255.255.255')
|
||||
|
||||
|
||||
def test_validator_ip_netmask_multi_leader(config_type):
|
||||
a = IPOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_ip_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.a').value.set(['192.168.1.2'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.128')
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.get()")
|
||||
cfg.option('a.a').value.set(['192.168.1.128'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.set('255.255.255.128')")
|
||||
cfg.option('a.a').value.set(['192.168.1.2', '192.168.1.3'])
|
||||
|
||||
|
||||
def test_validator_network_netmask_multi_leader(config_type):
|
||||
a = NetworkOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.255')
|
||||
cfg.option('a.b', 0).value.reset()
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.get()")
|
||||
|
||||
|
||||
def test_validator_broadcast(config_type):
|
||||
a = NetworkOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
c = BroadcastOption('c', '', multi=True, validators=[Calculation(valid_broadcast, Params((ParamOption(a), ParamOption(b), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b, c])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg = get_config(cfg, config_type)
|
||||
#first, test network_netmask
|
||||
cfg.option('a.a').value.set(['192.168.1.128'])
|
||||
raises(ValueError, "cfg.option('a.a').value.set(['255.255.255.0'])")
|
||||
#
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.c', 0).value.set('192.168.1.255')
|
||||
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.get()")
|
||||
raises(ValueError, "cfg.option('a.c', 0).value.get()")
|
||||
#
|
||||
cfg.option('a.a').value.set(['192.168.1.0', '192.168.2.128'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.b', 1).value.set('255.255.255.128')
|
||||
cfg.option('a.c', 0).value.set('192.168.1.255')
|
||||
cfg.option('a.c', 1).value.set('192.168.2.255')
|
||||
raises(ValueError, "cfg.option('a.c', 1).value.set('192.168.2.128')")
|
||||
cfg.option('a.c', 1).value.set('192.168.2.255')
|
||||
|
||||
|
||||
def test_validator_broadcast_warnings(config_type):
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
a = NetworkOption('a', '', properties=('mandatory', 'disabled'))
|
||||
b = NetmaskOption('b', '', properties=('mandatory', 'disabled'), validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())), warnings_only=True)])
|
||||
od = OptionDescription('a', '', [a, b])
|
||||
cfg_ori = Config(od)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('a').value.set('192.168.1.4')
|
||||
cfg.option('b').value.set('255.255.255.0')
|
||||
assert len(w) == 1
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.read_write()
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
list(cfg.value.mandatory())
|
||||
assert len(w) == 0
|
||||
|
||||
|
||||
def test_validator_broadcast_default_1():
|
||||
a = NetworkOption('a', '', '192.168.1.0')
|
||||
b = NetmaskOption('b', '', '255.255.255.128')
|
||||
c = BroadcastOption('c', '', '192.168.2.127', validators=[Calculation(valid_broadcast, Params((ParamOption(a), ParamOption(b), ParamSelfOption())))])
|
||||
od = OptionDescription('a', '', [a, b, c])
|
||||
cfg = Config(od)
|
||||
raises(ValueError, "cfg.value.dict()")
|
||||
|
||||
|
||||
def test_validator_broadcast_default_2():
|
||||
a = NetworkOption('a', '', '192.168.1.0')
|
||||
b = NetmaskOption('b', '', '255.255.255.128')
|
||||
d = BroadcastOption('d', '', '192.168.1.127', validators=[Calculation(valid_broadcast, Params((ParamOption(a), ParamOption(b), ParamSelfOption())))])
|
||||
od = OptionDescription('a', '', [a, b, d])
|
||||
cfg = Config(od)
|
||||
assert cfg.value.dict()
|
||||
|
||||
|
||||
def test_validator_not_all(config_type):
|
||||
a = NetworkOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
c = BroadcastOption('c', '', multi=True)
|
||||
od = Leadership('a', '', [a, b, c])
|
||||
od = OptionDescription('od2', '', [od])
|
||||
cfg = Config(od)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||
cfg.option('a.c', 0).value.set('192.168.1.255')
|
||||
|
||||
|
||||
def test_validator_network_netmask_mandatory(config_type):
|
||||
a = NetworkOption('a', '', multi=True, properties=('mandatory',), default=[u'0.0.0.0'])
|
||||
b = NetmaskOption('b', '', multi=True, properties=('mandatory',), default_multi=u'0.0.0.0', validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_only()
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.value.dict()
|
||||
|
||||
|
||||
def test_validator_has_dependency():
|
||||
a = IPOption('a', '')
|
||||
b = NetmaskOption('b', '', validators=[Calculation(valid_ip_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg = Config(od)
|
||||
assert cfg.option('a').option.has_dependency() is False
|
||||
assert cfg.option('b').option.has_dependency() is True
|
||||
assert cfg.option('a').option.has_dependency(False) is True
|
||||
assert cfg.option('b').option.has_dependency(False) is False
|
||||
|
||||
|
||||
def test_validator_warnings_only_more_option(config_type):
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '')
|
||||
d = IntOption('d', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))), warnings_only=True)])
|
||||
od = OptionDescription('od', '', [a, b, d])
|
||||
cfg = Config(od)
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('a').value.set(1)
|
||||
cfg.option('b').value.set(1)
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('d').value.get()
|
||||
assert w == []
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('d').value.set(1)
|
||||
assert w != []
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_error_prefix():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg = Config(od)
|
||||
cfg.option('a').value.set(1)
|
||||
try:
|
||||
cfg.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
assert str(err) == _('"{0}" is an invalid {1} for "{2}"').format('1', _('integer'), 'b') + ', ' + _('value is identical to {}').format('"a"')
|
||||
try:
|
||||
cfg.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
err.prefix = ''
|
||||
assert str(err) == _('value is identical to {}').format('"a"')
|
||||
|
||||
|
||||
def test_validator_warnings_only_option(config_type):
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '', warnings_only=True, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg_ori = Config(od)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
cfg.option('a').value.set(1)
|
||||
raises(ValueError, "cfg.option('b').value.set(1)")
|
||||
|
||||
|
||||
def test_validator_not_equal(config_type):
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg_ori = Config(od)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
assert cfg.option('a').value.get() is None
|
||||
assert cfg.option('b').value.get() is None
|
||||
cfg.option('a').value.set(1)
|
||||
cfg.option('a').value.reset()
|
||||
cfg.option('a').value.set(1)
|
||||
raises(ValueError, "cfg.option('b').value.set(1)")
|
||||
cfg.option('b').value.set(2)
|
||||
#
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.add('demoting_error_warning')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('b').value.set(1)
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_not_equal_leadership(config_type):
|
||||
a = IntOption('a', '', multi=True)
|
||||
b = IntOption('b', '', multi=True, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('b', '', [od])
|
||||
cfg = Config(od2)
|
||||
cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('a.a').value.get() == []
|
||||
cfg.option('a.a').value.set([1])
|
||||
cfg.option('a.a').value.reset()
|
||||
cfg.option('a.a').value.set([1])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.set(1)")
|
||||
cfg.option('a.b', 0).value.set(2)
|
||||
cfg.option('a.a').value.reset()
|
||||
cfg.option('a.a').value.set([1])
|
||||
cfg.value.dict()
|
||||
|
||||
|
||||
def test_validator_not_equal_leadership_default():
|
||||
a = IntOption('a', '', multi=True)
|
||||
b = IntOption('b', '', multi=True, default_multi=1, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||
od = Leadership('a', '', [a, b])
|
||||
od2 = OptionDescription('a', '', [od])
|
||||
cfg = Config(od2)
|
||||
# FIXME cfg = get_config(cfg, config_type)
|
||||
assert cfg.option('a.a').value.get() == []
|
||||
cfg.option('a.a').value.set([1])
|
||||
raises(ValueError, "cfg.option('a.b', 0).value.get()")
|
||||
cfg.option('a.a').value.set([2])
|
||||
cfg.option('a.a').value.reset()
|
||||
cfg.option('a.a').value.set([2])
|
||||
#
|
||||
cfg.property.add('demoting_error_warning')
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('a.b', 0).value.set(2)
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_default_diff():
|
||||
a = IntOption('a', '', 3)
|
||||
b = IntOption('b', '', 1, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg = Config(od)
|
||||
# FIXME cfg = get_config(cfg, config_type)
|
||||
cfg.option('b').value.set(2)
|
||||
cfg.option('a').value.set(1)
|
||||
owner = cfg.owner.get()
|
||||
assert cfg.option('b').owner.get() == owner
|
||||
raises(ValueError, "cfg.option('b').value.reset()")
|
||||
assert cfg.option('b').owner.get() == owner
|
||||
#
|
||||
cfg.property.add('demoting_error_warning')
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('b').value.reset()
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_validator_permissive(config_type):
|
||||
a = IntOption('a', '', 1, properties=('hidden',))
|
||||
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
cfg.permissive.set(frozenset(['hidden']))
|
||||
cfg = get_config(cfg, config_type)
|
||||
raises(ValueError, "cfg.option('b').value.set(1)")
|
||||
cfg.option('b').value.set(2)
|
||||
|
||||
|
||||
def test_validator_disabled(config_type):
|
||||
a = IntOption('a', '', 1, properties=('disabled',))
|
||||
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True, raisepropertyerror=True))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
cfg = get_config(cfg, config_type)
|
||||
raises(PropertiesOptionError, "cfg.option('b').value.set(1)")
|
||||
|
||||
|
||||
def test_consistency_disabled_transitive(config_type):
|
||||
a = IntOption('a', '', 1, properties=('disabled',))
|
||||
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True, notraisepropertyerror=True))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
cfg = get_config(cfg, config_type)
|
||||
cfg.option('b').value.set(1)
|
||||
|
||||
|
||||
def test_consistency_double_warnings(config_type):
|
||||
a = IntOption('a', '', 1)
|
||||
b = IntOption('b', '', 1)
|
||||
c = IntOption('c', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=True), Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(b, todict=True))), warnings_only=True)])
|
||||
od = OptionDescription('od', '', [a, b, c])
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
od2 = OptionDescription('od2', '', [od])
|
||||
cfg_ori = Config(od2)
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('od.c').value.set(1)
|
||||
assert w != []
|
||||
if config_type == 'tiramisu-api':
|
||||
# in this case warnings is for '"a" and "b"'
|
||||
assert len(w) == 1
|
||||
else:
|
||||
# in this cas one warnings is for "a" and the second for "b"
|
||||
assert len(w) == 2
|
||||
cfg.option('od.a').value.set(2)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('od.c').value.get()
|
||||
assert len(w) == 1
|
||||
#
|
||||
if config_type == 'tiramisu-api':
|
||||
cfg.send()
|
||||
cfg_ori.property.pop('warnings')
|
||||
cfg = get_config(cfg_ori, config_type)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.option('od.c').value.set(1)
|
||||
assert w == []
|
||||
|
||||
|
||||
def test_consistency_warnings_error(config_type):
|
||||
a = IntOption('a', '', 1)
|
||||
b = IntOption('b', '', 1)
|
||||
c = IntOption('c', '', validators=[
|
||||
Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=True),
|
||||
Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(b, todict=True))))
|
||||
])
|
||||
od = OptionDescription('od', '', [a, b, c])
|
||||
warnings.simplefilter("always", ValueWarning)
|
||||
cfg = Config(od)
|
||||
cfg = get_config(cfg, config_type)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
raises(ValueError, "cfg.option('c').value.set(1)")
|
||||
assert w == []
|
||||
|
||||
|
||||
def test_consistency_not_equal_has_dependency():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '', )
|
||||
b = IntOption('b', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
cfg = Config(od)
|
||||
assert cfg.option('a').option.has_dependency() is False
|
||||
assert cfg.option('b').option.has_dependency() is True
|
||||
assert cfg.option('a').option.has_dependency(False) is True
|
||||
assert cfg.option('b').option.has_dependency(False) is False
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -88,21 +88,21 @@ def test_slots_option_readonly():
|
|||
p = URLOption('p', '')
|
||||
q = FilenameOption('q', '')
|
||||
m = OptionDescription('m', '', [a, b, c, d, e, g, h, i, j, k, l, o, p, q])
|
||||
a._requires = (((a,),),)
|
||||
b._requires = (((a,),),)
|
||||
c._requires = (((a,),),)
|
||||
d._requires = (((a,),),)
|
||||
e._requires = (((a,),),)
|
||||
g._requires = (((a,),),)
|
||||
h._requires = (((a,),),)
|
||||
i._requires = (((a,),),)
|
||||
j._requires = (((a,),),)
|
||||
k._requires = (((a,),),)
|
||||
l._requires = (((a,),),)
|
||||
m._requires = (((a,),),)
|
||||
o._requires = (((a,),),)
|
||||
p._requires = (((a,),),)
|
||||
q._requires = (((a,),),)
|
||||
a._name = 'a'
|
||||
b._name = 'b'
|
||||
c._name = 'c'
|
||||
d._name = 'd'
|
||||
e._name = 'e'
|
||||
g._name = 'g'
|
||||
h._name = 'h'
|
||||
i._name = 'i'
|
||||
j._name = 'j'
|
||||
k._name = 'k'
|
||||
l._name = 'l'
|
||||
m._name = 'm'
|
||||
o._name = 'o'
|
||||
p._name = 'p'
|
||||
q._name = 'q'
|
||||
Config(m)
|
||||
raises(AttributeError, "a._requires = 'a'")
|
||||
raises(AttributeError, "b._requires = 'b'")
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Configuration management library written in python
|
||||
"""
|
||||
from .function import tiramisu_copy, calc_value, calc_value_property_help
|
||||
from .autolib import Calculation, Params, ParamOption, ParamSelfOption, ParamValue, ParamIndex, ParamContext
|
||||
from .function import calc_value, calc_value_property_help, valid_ip_netmask, \
|
||||
valid_network_netmask, valid_in_network, valid_broadcast, \
|
||||
valid_not_equal
|
||||
from .autolib import Calculation, Params, ParamOption, ParamSelfOption, ParamValue, \
|
||||
ParamIndex, ParamContext, ParamSuffix
|
||||
from .option import *
|
||||
from .error import APIError
|
||||
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
||||
|
@ -32,6 +35,7 @@ allfuncs = ['Calculation',
|
|||
'ParamValue',
|
||||
'ParamIndex',
|
||||
'ParamContext',
|
||||
'ParamSuffix',
|
||||
'MetaConfig',
|
||||
'MixConfig',
|
||||
'GroupConfig',
|
||||
|
@ -44,9 +48,13 @@ allfuncs = ['Calculation',
|
|||
'Storage',
|
||||
'list_sessions',
|
||||
'delete_session',
|
||||
'tiramisu_copy',
|
||||
'calc_value',
|
||||
'calc_value_property_help']
|
||||
'calc_value_property_help',
|
||||
'valid_ip_netmask',
|
||||
'valid_network_netmask',
|
||||
'valid_in_network',
|
||||
'valid_broadcast',
|
||||
]
|
||||
allfuncs.extend(all_options)
|
||||
del(all_options)
|
||||
__all__ = tuple(allfuncs)
|
||||
|
|
|
@ -196,11 +196,6 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
|||
option = self._option_bag.option
|
||||
return option.impl_has_dependency(self_is_dep)
|
||||
|
||||
def requires(self):
|
||||
"""Get requires for an option"""
|
||||
option = self._option_bag.option
|
||||
return option.impl_getrequires()
|
||||
|
||||
def isoptiondescription(self):
|
||||
"""Test if option is an optiondescription"""
|
||||
option = self._option_bag.option
|
||||
|
@ -274,11 +269,6 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
|||
ret = value
|
||||
return ret
|
||||
|
||||
def consistencies(self):
|
||||
"""Get consistencies for an option (not for optiondescription)"""
|
||||
option = self._option_bag.option
|
||||
return option.get_consistencies()
|
||||
|
||||
def callbacks(self):
|
||||
"""Get callbacks for an option (not for optiondescription)"""
|
||||
option = self._option_bag.option
|
||||
|
|
|
@ -84,10 +84,14 @@ class ParamOption(Param):
|
|||
|
||||
|
||||
class ParamSelfOption(Param):
|
||||
__slots__ = ('todict',)
|
||||
__slots__ = ('todict', 'whole')
|
||||
def __init__(self,
|
||||
todict: bool=False) -> None:
|
||||
todict: bool=False,
|
||||
whole: bool=undefined) -> None:
|
||||
"""whole: send all value for a multi, not only indexed value"""
|
||||
self.todict = todict
|
||||
if whole is not undefined:
|
||||
self.whole = whole
|
||||
|
||||
|
||||
class ParamValue(Param):
|
||||
|
@ -104,15 +108,21 @@ class ParamIndex(Param):
|
|||
__slots__ = tuple()
|
||||
|
||||
|
||||
class ParamSuffix(Param):
|
||||
__slots__ = tuple()
|
||||
|
||||
|
||||
class Calculation:
|
||||
__slots__ = ('function',
|
||||
'params',
|
||||
'help_function',
|
||||
'has_index')
|
||||
'has_index',
|
||||
'warnings_only')
|
||||
def __init__(self,
|
||||
function: Callable,
|
||||
params: Params=Params(),
|
||||
help_function: Optional[Callable]=None):
|
||||
help_function: Optional[Callable]=None,
|
||||
warnings_only: bool=False):
|
||||
assert isinstance(function, Callable), _('first argument ({0}) must be a function').format(function)
|
||||
if help_function:
|
||||
assert isinstance(help_function, Callable), _('help_function ({0}) must be a function').format(help_function)
|
||||
|
@ -127,19 +137,22 @@ class Calculation:
|
|||
break
|
||||
else:
|
||||
self.has_index = False
|
||||
if warnings_only is True:
|
||||
self.warnings_only = warnings_only
|
||||
|
||||
def execute(self,
|
||||
option_bag: OptionBag,
|
||||
leadership_must_have_index: bool=False) -> Any:
|
||||
if leadership_must_have_index and not self.has_index:
|
||||
leadership_must_have_index = False
|
||||
leadership_must_have_index: bool=False,
|
||||
orig_value: Any=undefined,
|
||||
allow_raises=False) -> Any:
|
||||
return carry_out_calculation(option_bag.option,
|
||||
callback=self.function,
|
||||
callback_params=self.params,
|
||||
index=option_bag.index,
|
||||
config_bag=option_bag.config_bag,
|
||||
fromconsistency=option_bag.fromconsistency,
|
||||
leadership_must_have_index=leadership_must_have_index)
|
||||
leadership_must_have_index=leadership_must_have_index,
|
||||
orig_value=orig_value,
|
||||
allow_raises=allow_raises)
|
||||
|
||||
def help(self,
|
||||
option_bag: OptionBag,
|
||||
|
@ -147,14 +160,11 @@ class Calculation:
|
|||
if not self.help_function:
|
||||
return self.execute(option_bag,
|
||||
leadership_must_have_index=leadership_must_have_index)
|
||||
if leadership_must_have_index and not self.has_index:
|
||||
leadership_must_have_index = False
|
||||
return carry_out_calculation(option_bag.option,
|
||||
callback=self.help_function,
|
||||
callback_params=self.params,
|
||||
index=option_bag.index,
|
||||
config_bag=option_bag.config_bag,
|
||||
fromconsistency=option_bag.fromconsistency,
|
||||
leadership_must_have_index=leadership_must_have_index)
|
||||
|
||||
|
||||
|
@ -167,49 +177,58 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
|
|||
index: Optional[int],
|
||||
orig_value,
|
||||
config_bag: ConfigBag,
|
||||
fromconsistency: List,
|
||||
leadership_must_have_index: bool) -> Any:
|
||||
"""replace Param by true value"""
|
||||
if isinstance(callbk, ParamValue):
|
||||
return callbk.value
|
||||
if isinstance(callbk, ParamIndex):
|
||||
return index
|
||||
if config_bag is undefined:
|
||||
return undefined
|
||||
if isinstance(callbk, ParamContext):
|
||||
# Not an option, set full context
|
||||
return config_bag.context.duplicate(force_values=get_default_values_storages(),
|
||||
force_settings=get_default_settings_storages())
|
||||
if isinstance(callbk, ParamSelfOption):
|
||||
opt = option
|
||||
else:
|
||||
# it's ParamOption
|
||||
opt = callbk.option
|
||||
if opt.issubdyn():
|
||||
opt = opt.to_dynoption(option.rootpath,
|
||||
option.impl_getsuffix())
|
||||
path = opt.impl_getpath()
|
||||
is_follower = opt.impl_is_follower()
|
||||
if leadership_must_have_index and opt.impl_get_leadership() and index is None:
|
||||
raise Break()
|
||||
if index is not None and opt.impl_get_leadership() and \
|
||||
opt.impl_get_leadership().in_same_group(option):
|
||||
if opt == option:
|
||||
index_ = None
|
||||
with_index = False
|
||||
elif is_follower:
|
||||
index_ = index
|
||||
with_index = False
|
||||
else:
|
||||
index_ = None
|
||||
with_index = True
|
||||
else:
|
||||
index_ = None
|
||||
with_index = False
|
||||
if opt == option and orig_value is not undefined and \
|
||||
(not is_follower or index is None):
|
||||
value = orig_value
|
||||
else:
|
||||
def calc_index(callbk, index, same_leadership):
|
||||
if index is not None:
|
||||
if hasattr(callbk, 'whole'):
|
||||
whole = callbk.whole
|
||||
else:
|
||||
# if value is same_leadership, follower are isolate by default
|
||||
# otherwise option is a whole option
|
||||
whole = not same_leadership
|
||||
if not whole:
|
||||
return index
|
||||
return None
|
||||
|
||||
def calc_self(callbk, option, index, value, config_bag):
|
||||
# index must be apply only if follower
|
||||
is_follower = option.impl_is_follower()
|
||||
apply_index = calc_index(callbk, index, is_follower)
|
||||
if value is undefined or (apply_index is None and is_follower):
|
||||
if config_bag is undefined:
|
||||
return undefined
|
||||
path = option.impl_getpath()
|
||||
option_bag = get_option_bag(config_bag, option, path, apply_index)
|
||||
option_bag.config_bag.unrestraint()
|
||||
option_bag.config_bag.remove_validation()
|
||||
# if we are in properties calculation, cannot calculated properties
|
||||
option_bag.properties = config_bag.context.cfgimpl_get_settings().getproperties(option_bag,
|
||||
apply_requires=False)
|
||||
new_value = get_value(callbk, option_bag, path)
|
||||
if apply_index is None and is_follower:
|
||||
new_value[index] = value
|
||||
value = new_value
|
||||
elif apply_index is not None and not is_follower:
|
||||
value = value[apply_index]
|
||||
return value
|
||||
|
||||
def get_value(callbk, option_bag, path):
|
||||
try:
|
||||
# get value
|
||||
value = config_bag.context.getattr(path,
|
||||
option_bag)
|
||||
except PropertiesOptionError as err:
|
||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||
if callbk.notraisepropertyerror or callbk.raisepropertyerror:
|
||||
raise err
|
||||
raise ConfigError(_('unable to carry out a calculation for "{}"'
|
||||
', {}').format(option.impl_get_display_name(), err), err)
|
||||
except ValueError as err:
|
||||
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err))
|
||||
return value
|
||||
|
||||
def get_option_bag(config_bag, opt, path, index_):
|
||||
# don't validate if option is option that we tried to validate
|
||||
config_bag = config_bag.copy()
|
||||
config_bag.properties = config_bag.true_properties - {'warnings'}
|
||||
|
@ -220,29 +239,64 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
|
|||
path,
|
||||
index_,
|
||||
config_bag)
|
||||
if fromconsistency:
|
||||
option_bag.fromconsistency = fromconsistency.copy()
|
||||
if opt == option:
|
||||
option_bag.config_bag.unrestraint()
|
||||
option_bag.config_bag.remove_validation()
|
||||
# if we are in properties calculation, cannot calculated properties
|
||||
option_bag.properties = config_bag.context.cfgimpl_get_settings().getproperties(option_bag,
|
||||
apply_requires=False)
|
||||
try:
|
||||
# get value
|
||||
value = config_bag.context.getattr(path,
|
||||
option_bag)
|
||||
if with_index:
|
||||
value = value[index]
|
||||
except PropertiesOptionError as err:
|
||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||
if callbk.notraisepropertyerror or callbk.raisepropertyerror:
|
||||
raise err
|
||||
raise ConfigError(_('unable to carry out a calculation for "{}"'
|
||||
', {}').format(option.impl_get_display_name(), err), err)
|
||||
return option_bag
|
||||
|
||||
if isinstance(callbk, ParamValue):
|
||||
return callbk.value
|
||||
|
||||
if isinstance(callbk, ParamIndex):
|
||||
return index
|
||||
|
||||
if isinstance(callbk, ParamSuffix):
|
||||
if not option.issubdyn():
|
||||
raise ConfigError('option "{}" is not in a dynoptiondescription'.format(option.impl_get_display_name()))
|
||||
return option.impl_getsuffix()
|
||||
|
||||
if isinstance(callbk, ParamContext):
|
||||
if config_bag is undefined:
|
||||
return undefined
|
||||
# Not an option, set full context
|
||||
return config_bag.context.duplicate(force_values=get_default_values_storages(),
|
||||
force_settings=get_default_settings_storages())
|
||||
if isinstance(callbk, ParamSelfOption):
|
||||
if leadership_must_have_index and option.impl_get_leadership() and index is None:
|
||||
raise Break()
|
||||
value = calc_self(callbk, option, index, orig_value, config_bag)
|
||||
if not callbk.todict:
|
||||
return value
|
||||
return {'name': option.impl_get_display_name(),
|
||||
'value': value}
|
||||
|
||||
# it's ParamOption
|
||||
callbk_option = callbk.option
|
||||
if callbk_option.issubdyn():
|
||||
callbk_option = callbk_option.to_dynoption(option.rootpath,
|
||||
option.impl_getsuffix())
|
||||
if leadership_must_have_index and callbk_option.impl_get_leadership() and index is None:
|
||||
raise Break()
|
||||
if config_bag is undefined:
|
||||
return undefined
|
||||
if index is not None and callbk_option.impl_get_leadership() and \
|
||||
callbk_option.impl_get_leadership().in_same_group(option):
|
||||
if not callbk_option.impl_is_follower():
|
||||
# leader
|
||||
index_ = None
|
||||
with_index = True
|
||||
else:
|
||||
# follower
|
||||
index_ = index
|
||||
with_index = False
|
||||
else:
|
||||
index_ = None
|
||||
with_index = False
|
||||
path = callbk_option.impl_getpath()
|
||||
option_bag = get_option_bag(config_bag, callbk_option, path, index_)
|
||||
value = get_value(callbk, option_bag, path)
|
||||
if with_index:
|
||||
value = value[index]
|
||||
if not callbk.todict:
|
||||
return value
|
||||
return {'name': opt.impl_get_display_name(),
|
||||
return {'name': callbk_option.impl_get_display_name(),
|
||||
'value': value}
|
||||
|
||||
|
||||
|
@ -251,10 +305,9 @@ def carry_out_calculation(option,
|
|||
callback_params: Optional[Params],
|
||||
index: Optional[int],
|
||||
config_bag: Optional[ConfigBag],
|
||||
fromconsistency: List,
|
||||
orig_value=undefined,
|
||||
leadership_must_have_index: bool=False,
|
||||
is_validator: int=False):
|
||||
allow_raises: int=False):
|
||||
"""a function that carries out a calculation for an option's value
|
||||
|
||||
:param option: the option
|
||||
|
@ -265,109 +318,16 @@ def carry_out_calculation(option,
|
|||
:type callback_params: dict
|
||||
:param index: if an option is multi, only calculates the nth value
|
||||
:type index: int
|
||||
:param is_validator: to know if carry_out_calculation is used to validate a value
|
||||
:param allow_raises: to know if carry_out_calculation is used to validate a value
|
||||
|
||||
The callback_params is a dict. Key is used to build args (if key is '')
|
||||
and kwargs (otherwise). Values are tuple of:
|
||||
- values
|
||||
- tuple with option and boolean's force_permissive (True when don't raise
|
||||
if PropertiesOptionError)
|
||||
Values could have multiple values only when key is ''.
|
||||
|
||||
* if no callback_params:
|
||||
=> calculate(<function func at 0x2092320>, [], {})
|
||||
|
||||
* if callback_params={'': ('yes',)}
|
||||
=> calculate(<function func at 0x2092320>, ['yes'], {})
|
||||
|
||||
* if callback_params={'value': ('yes',)}
|
||||
=> calculate(<function func at 0x165b320>, [], {'value': 'yes'})
|
||||
|
||||
* if callback_params={'': ('yes', 'no')}
|
||||
=> calculate('yes', 'no')
|
||||
|
||||
* if callback_params={'value': ('yes', 'no')}
|
||||
=> ValueError()
|
||||
|
||||
* if callback_params={'': (['yes', 'no'],)}
|
||||
=> calculate(<function func at 0x176b320>, ['yes', 'no'], {})
|
||||
|
||||
* if callback_params={'value': ('yes', 'no')}
|
||||
=> raises ValueError()
|
||||
|
||||
* if callback_params={'': ((opt1, False),)}
|
||||
|
||||
- a simple option:
|
||||
opt1 == 11
|
||||
=> calculate(<function func at 0x1cea320>, [11], {})
|
||||
|
||||
- a multi option and not leadership
|
||||
opt1 == [1, 2, 3]
|
||||
=> calculate(<function func at 0x223c320>, [[1, 2, 3]], {})
|
||||
|
||||
- option is leader or follower of opt1:
|
||||
opt1 == [1, 2, 3]
|
||||
=> calculate(<function func at 0x223c320>, [1], {})
|
||||
=> calculate(<function func at 0x223c320>, [2], {})
|
||||
=> calculate(<function func at 0x223c320>, [3], {})
|
||||
|
||||
- opt is a leader or follower but not related to option:
|
||||
opt1 == [1, 2, 3]
|
||||
=> calculate(<function func at 0x11b0320>, [[1, 2, 3]], {})
|
||||
|
||||
* if callback_params={'value': ((opt1, False),)}
|
||||
|
||||
- a simple option:
|
||||
opt1 == 11
|
||||
=> calculate(<function func at 0x17ff320>, [], {'value': 11})
|
||||
|
||||
- a multi option:
|
||||
opt1 == [1, 2, 3]
|
||||
=> calculate(<function func at 0x1262320>, [], {'value': [1, 2, 3]})
|
||||
|
||||
* if callback_params={'': ((opt1, False), (opt2, False))}
|
||||
|
||||
- two single options
|
||||
opt1 = 11
|
||||
opt2 = 12
|
||||
=> calculate(<function func at 0x217a320>, [11, 12], {})
|
||||
|
||||
- a multi option with a simple option
|
||||
opt1 == [1, 2, 3]
|
||||
opt2 == 12
|
||||
=> calculate(<function func at 0x2153320>, [[1, 2, 3], 12], {})
|
||||
|
||||
- a multi option with an other multi option but with same length
|
||||
opt1 == [1, 2, 3]
|
||||
opt2 == [11, 12, 13]
|
||||
=> calculate(<function func at 0x1981320>, [[1, 2, 3], [11, 12, 13]], {})
|
||||
|
||||
- a multi option with an other multi option but with different length
|
||||
opt1 == [1, 2, 3]
|
||||
opt2 == [11, 12]
|
||||
=> calculate(<function func at 0x2384320>, [[1, 2, 3], [11, 12]], {})
|
||||
|
||||
- a multi option without value with a simple option
|
||||
opt1 == []
|
||||
opt2 == 11
|
||||
=> calculate(<function func at 0xb65320>, [[], 12], {})
|
||||
|
||||
* if callback_params={'value': ((opt1, False), (opt2, False))}
|
||||
=> raises ValueError()
|
||||
|
||||
If index is not undefined, 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.
|
||||
"""
|
||||
Values could have multiple values only when key is ''."""
|
||||
args = []
|
||||
kwargs = {}
|
||||
# if callback_params has a callback, launch several time calculate()
|
||||
if option.issubdyn():
|
||||
#FIXME why here? should be a ParamSuffix !
|
||||
kwargs['suffix'] = option.impl_getsuffix()
|
||||
if callback_params:
|
||||
for callbk in callback_params.args:
|
||||
try:
|
||||
|
@ -376,7 +336,6 @@ def carry_out_calculation(option,
|
|||
index,
|
||||
orig_value,
|
||||
config_bag,
|
||||
fromconsistency,
|
||||
leadership_must_have_index)
|
||||
if value is undefined:
|
||||
return undefined
|
||||
|
@ -395,7 +354,6 @@ def carry_out_calculation(option,
|
|||
index,
|
||||
orig_value,
|
||||
config_bag,
|
||||
fromconsistency,
|
||||
leadership_must_have_index)
|
||||
if value is undefined:
|
||||
return undefined
|
||||
|
@ -409,7 +367,7 @@ def carry_out_calculation(option,
|
|||
continue
|
||||
ret = calculate(option,
|
||||
callback,
|
||||
is_validator,
|
||||
allow_raises,
|
||||
args,
|
||||
kwargs)
|
||||
if isinstance(ret, list) and not option.impl_is_dynoptiondescription() and \
|
||||
|
@ -434,7 +392,7 @@ def carry_out_calculation(option,
|
|||
|
||||
def calculate(option,
|
||||
callback: Callable,
|
||||
is_validator: bool,
|
||||
allow_raises: bool,
|
||||
args,
|
||||
kwargs):
|
||||
"""wrapper that launches the 'callback'
|
||||
|
@ -447,7 +405,7 @@ def calculate(option,
|
|||
try:
|
||||
return callback(*args, **kwargs)
|
||||
except ValueError as err:
|
||||
if is_validator:
|
||||
if allow_raises:
|
||||
raise err
|
||||
error = err
|
||||
except Exception as err:
|
||||
|
|
|
@ -48,8 +48,7 @@ class SubConfig(object):
|
|||
descr,
|
||||
context,
|
||||
config_bag,
|
||||
subpath=None,
|
||||
fromconsistency=None):
|
||||
subpath=None):
|
||||
""" Configuration option management class
|
||||
|
||||
:param descr: describes the configuration schema
|
||||
|
@ -82,8 +81,6 @@ class SubConfig(object):
|
|||
full_leaderpath,
|
||||
None,
|
||||
cconfig_bag)
|
||||
if fromconsistency:
|
||||
moption_bag.fromconsistency = fromconsistency
|
||||
value = self.getattr(leaderpath,
|
||||
moption_bag)
|
||||
self._impl_length = len(value)
|
||||
|
@ -179,8 +176,7 @@ class SubConfig(object):
|
|||
|
||||
def cfgimpl_get_home_by_path(self,
|
||||
path,
|
||||
config_bag,
|
||||
fromconsistency=None):
|
||||
config_bag):
|
||||
""":returns: tuple (config, name)"""
|
||||
path = path.split('.')
|
||||
for step in path[:-1]:
|
||||
|
@ -193,8 +189,6 @@ class SubConfig(object):
|
|||
subpath,
|
||||
None,
|
||||
config_bag)
|
||||
if fromconsistency is not None:
|
||||
option_bag.fromconsistency = fromconsistency
|
||||
self = self.get_subconfig(option_bag)
|
||||
assert isinstance(self, SubConfig), _('unknown option {}').format(path[-1])
|
||||
return self, path[-1]
|
||||
|
@ -253,17 +247,11 @@ class SubConfig(object):
|
|||
|
||||
def get_subconfig(self,
|
||||
option_bag):
|
||||
if option_bag.fromconsistency:
|
||||
fromconsistency = option_bag.fromconsistency.copy()
|
||||
else:
|
||||
fromconsistency = None
|
||||
|
||||
self.cfgimpl_get_settings().validate_properties(option_bag)
|
||||
return SubConfig(option_bag.option,
|
||||
self._impl_context,
|
||||
option_bag.config_bag,
|
||||
option_bag.path,
|
||||
fromconsistency)
|
||||
option_bag.path)
|
||||
|
||||
def getattr(self,
|
||||
name,
|
||||
|
@ -276,13 +264,8 @@ class SubConfig(object):
|
|||
"""
|
||||
config_bag = option_bag.config_bag
|
||||
if '.' in name:
|
||||
if option_bag.fromconsistency:
|
||||
fromconsistency = option_bag.fromconsistency.copy()
|
||||
else:
|
||||
fromconsistency = None
|
||||
self, name = self.cfgimpl_get_home_by_path(name,
|
||||
config_bag,
|
||||
fromconsistency)
|
||||
config_bag)
|
||||
|
||||
option = option_bag.option
|
||||
if option.impl_is_symlinkoption():
|
||||
|
@ -309,8 +292,7 @@ class SubConfig(object):
|
|||
length,
|
||||
option_bag.index))
|
||||
if option.impl_is_follower() and option_bag.index is None:
|
||||
needs_re_verify_follower_properties = option_bag.option.impl_getrequires() or \
|
||||
self.cfgimpl_get_settings().has_properties_index(option_bag)
|
||||
needs_re_verify_follower_properties = self.cfgimpl_get_settings().has_properties_index(option_bag)
|
||||
value = []
|
||||
for idx in range(length):
|
||||
soption_bag = OptionBag()
|
||||
|
@ -318,7 +300,6 @@ class SubConfig(object):
|
|||
option_bag.path,
|
||||
idx,
|
||||
config_bag)
|
||||
soption_bag.fromconsistency = option_bag.fromconsistency.copy()
|
||||
try:
|
||||
value.append(self.getattr(name,
|
||||
soption_bag,
|
||||
|
@ -860,7 +841,6 @@ class KernelGroupConfig(_CommonConfig):
|
|||
err.proptype,
|
||||
err._settings,
|
||||
err._opt_type,
|
||||
err._requires,
|
||||
err._name,
|
||||
err._orig_opt))
|
||||
except (ValueError, LeadershipError, AttributeError) as err:
|
||||
|
@ -1069,7 +1049,6 @@ class KernelMixConfig(KernelGroupConfig):
|
|||
err.proptype,
|
||||
err._settings,
|
||||
err._opt_type,
|
||||
err._requires,
|
||||
err._name,
|
||||
err._orig_opt))
|
||||
except (ValueError, LeadershipError, AttributeError) as err:
|
||||
|
|
|
@ -58,12 +58,10 @@ class PropertiesOptionError(AttributeError):
|
|||
proptype,
|
||||
settings,
|
||||
opt_type=None,
|
||||
requires=None,
|
||||
name=None,
|
||||
orig_opt=None):
|
||||
if opt_type:
|
||||
self._opt_type = opt_type
|
||||
self._requires = requires
|
||||
self._name = name
|
||||
self._orig_opt = orig_opt
|
||||
else:
|
||||
|
@ -71,7 +69,6 @@ class PropertiesOptionError(AttributeError):
|
|||
self._opt_type = 'optiondescription'
|
||||
else:
|
||||
self._opt_type = 'option'
|
||||
self._requires = option_bag.option.impl_getrequires()
|
||||
self._name = option_bag.option.impl_get_display_name()
|
||||
self._orig_opt = None
|
||||
self._option_bag = option_bag
|
||||
|
@ -84,30 +81,21 @@ class PropertiesOptionError(AttributeError):
|
|||
self._orig_opt = opt
|
||||
|
||||
def __str__(self):
|
||||
#this part is a bit slow, so only execute when display
|
||||
# this part is a bit slow, so only execute when display
|
||||
if self.msg is not None:
|
||||
return self.msg
|
||||
if self._settings is None:
|
||||
return 'error'
|
||||
req = self._settings.apply_requires(self._option_bag,
|
||||
True)
|
||||
if req != {}:
|
||||
only_one = len(req) == 1
|
||||
msg = []
|
||||
for action, msg_ in req.items():
|
||||
msg.append('"{0}" ({1})'.format(action, display_list(msg_, add_quote=False)))
|
||||
msg = display_list(msg, add_quote=False)
|
||||
else:
|
||||
properties = list(self._settings.calc_raises_properties(self._option_bag,
|
||||
apply_requires=False))
|
||||
for property_ in self._settings.get_calculated_properties(self._option_bag):
|
||||
properties.append(property_.help(self._option_bag))
|
||||
properties = list(self._settings.calc_raises_properties(self._option_bag,
|
||||
apply_requires=False))
|
||||
for property_ in self._settings.get_calculated_properties(self._option_bag):
|
||||
properties.append(property_.help(self._option_bag))
|
||||
|
||||
if not properties:
|
||||
# if proptype == ['mandatory']
|
||||
properties = self.proptype
|
||||
only_one = len(properties) == 1
|
||||
msg = display_list(properties, add_quote=True)
|
||||
if not properties:
|
||||
# if proptype == ['mandatory']
|
||||
properties = self.proptype
|
||||
only_one = len(properties) == 1
|
||||
msg = display_list(properties, add_quote=True)
|
||||
if only_one:
|
||||
prop_msg = _('property')
|
||||
else:
|
||||
|
@ -125,7 +113,7 @@ class PropertiesOptionError(AttributeError):
|
|||
self._name,
|
||||
prop_msg,
|
||||
msg))
|
||||
del self._requires, self._opt_type, self._name
|
||||
del self._opt_type, self._name
|
||||
del self._settings, self._orig_opt
|
||||
return self.msg
|
||||
|
||||
|
@ -150,13 +138,6 @@ class ConflictError(Exception):
|
|||
|
||||
#____________________________________________________________
|
||||
# miscellaneous exceptions
|
||||
class RequirementError(Exception):
|
||||
"""a recursive loop occurs in the requirements tree
|
||||
requires
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class LeadershipError(Exception):
|
||||
"problem with a leadership's value length"
|
||||
pass
|
||||
|
|
|
@ -14,13 +14,144 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from typing import Any, List, Optional
|
||||
from operator import add, mul, sub, truediv
|
||||
from ipaddress import ip_address, ip_interface, ip_network
|
||||
from .i18n import _
|
||||
from .setting import undefined
|
||||
from .error import display_list
|
||||
|
||||
|
||||
def tiramisu_copy(val): # pragma: no cover
|
||||
return val
|
||||
def valid_network_netmask(network: str,
|
||||
netmask: str):
|
||||
"""FIXME
|
||||
"""
|
||||
if isinstance(network, dict):
|
||||
network_value = network['value']
|
||||
network_display_name = '({})'.format(network['name'])
|
||||
else:
|
||||
network_value = network
|
||||
network_display_name = ''
|
||||
if None in [network_value, netmask]:
|
||||
return
|
||||
try:
|
||||
ip_network('{0}/{1}'.format(network_value, netmask))
|
||||
except ValueError:
|
||||
raise ValueError(_('network "{0}" {1}does not match with this netmask').format(network_value,
|
||||
network_display_name))
|
||||
|
||||
def valid_ip_netmask(ip: str,
|
||||
netmask: str):
|
||||
if isinstance(ip, dict):
|
||||
ip_value = ip['value']
|
||||
ip_display_name = '({})'.format(ip['name'])
|
||||
else:
|
||||
ip_value = ip
|
||||
ip_display_name = ''
|
||||
if None in [ip_value, netmask]:
|
||||
return
|
||||
ip_netmask = ip_interface('{0}/{1}'.format(ip_value, netmask))
|
||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||
raise ValueError(_('IP \"{0}\" {1}with this netmask is in fact a network address').format(ip_value, ip_display_name))
|
||||
elif ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||
raise ValueError(_('IP \"{0}\" {1}with this netmask is in fact a broacast address').format(ip_value, ip_display_name))
|
||||
|
||||
|
||||
# FIXME CIDR ?
|
||||
def valid_broadcast(network: 'NetworkOption',
|
||||
netmask: 'NetmaskOption',
|
||||
broadcast: 'BroadcastOption'):
|
||||
if isinstance(network, dict):
|
||||
network_value = network['value']
|
||||
network_display_name = ' ({})'.format(network['name'])
|
||||
else:
|
||||
network_value = network
|
||||
network_display_name = ''
|
||||
if isinstance(netmask, dict):
|
||||
netmask_value = netmask['value']
|
||||
netmask_display_name = ' ({})'.format(netmask['name'])
|
||||
else:
|
||||
netmask_value = netmask
|
||||
netmask_display_name = ''
|
||||
if ip_network('{0}/{1}'.format(network, netmask)).broadcast_address != ip_address(broadcast):
|
||||
raise ValueError(_('broadcast invalid with network {0}{1} and netmask {2}{3}'
|
||||
'').format(network_value,
|
||||
network_display_name,
|
||||
netmask_value,
|
||||
netmask_display_name))
|
||||
|
||||
|
||||
def valid_in_network(ip,
|
||||
network,
|
||||
netmask=None):
|
||||
if isinstance(network, dict):
|
||||
network_value = network['value']
|
||||
network_display_name = ' ({})'.format(network['name'])
|
||||
else:
|
||||
network_value = network
|
||||
network_display_name = ''
|
||||
if netmask is None:
|
||||
network_obj = ip_network('{0}'.format(network_value))
|
||||
else:
|
||||
if isinstance(netmask, dict):
|
||||
netmask_value = netmask['value']
|
||||
netmask_display_name = ' ({})'.format(netmask['name'])
|
||||
else:
|
||||
netmask_value = netmask
|
||||
netmask_display_name = ''
|
||||
network_obj = ip_network('{0}/{1}'.format(network_value,
|
||||
netmask_value))
|
||||
if ip_interface(ip) not in network_obj:
|
||||
if netmask is None:
|
||||
msg = _('this IP is not in network {0}{1}').format(network_value,
|
||||
network_display_name)
|
||||
else:
|
||||
msg = _('this IP is not in network {0}{1} with netmask {2}{3}').format(network_value,
|
||||
network_display_name,
|
||||
netmask_value,
|
||||
netmask_display_name)
|
||||
raise ValueError(msg)
|
||||
|
||||
# test if ip is not network/broadcast IP
|
||||
ip_netmask = ip_interface('{0}/{1}'.format(ip, network_obj.netmask))
|
||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||
if netmask is None:
|
||||
msg = _('this IP with the network {0}{1} is in fact a network address').format(network_value,
|
||||
network_display_name)
|
||||
else:
|
||||
msg = _('this IP with the netmask {0}{1} is in fact a network address').format(netmask_value,
|
||||
netmask_display_name)
|
||||
raise ValueError(msg)
|
||||
elif ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||
if netmask is None:
|
||||
msg = _('this IP with the network {0}{1} is in fact a broadcast address').format(network_value,
|
||||
network_display_name)
|
||||
else:
|
||||
msg = _('this IP with the netmask {0}{1} is in fact a broadcast address').format(netmask_value,
|
||||
netmask_display_name)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
def valid_not_equal(*values):
|
||||
equal = set()
|
||||
for idx, val in enumerate(values[1:]):
|
||||
if isinstance(val, dict):
|
||||
if 'propertyerror' in val:
|
||||
continue
|
||||
tval = val['value']
|
||||
else:
|
||||
tval = val
|
||||
if values[0] == tval is not None:
|
||||
if isinstance(val, dict):
|
||||
if equal is True:
|
||||
equal = set()
|
||||
equal.add(val['name'])
|
||||
elif not equal:
|
||||
equal = True
|
||||
if equal:
|
||||
if equal is not True:
|
||||
msg = _('value is identical to {}').format(display_list(list(equal), add_quote=True))
|
||||
else:
|
||||
msg = _('value is identical')
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class CalcValue:
|
||||
|
|
|
@ -51,14 +51,8 @@ class Base:
|
|||
__slots__ = ('_name',
|
||||
'_path',
|
||||
'_informations',
|
||||
#calcul
|
||||
'_subdyn',
|
||||
'_requires',
|
||||
'_properties',
|
||||
'_calc_properties',
|
||||
#
|
||||
'_consistencies',
|
||||
#other
|
||||
'_has_dependency',
|
||||
'_dependencies',
|
||||
'_has_calc_context',
|
||||
|
@ -68,19 +62,10 @@ class Base:
|
|||
def __init__(self,
|
||||
name: str,
|
||||
doc: str,
|
||||
requires=None,
|
||||
properties=None,
|
||||
is_multi: bool=False) -> None:
|
||||
if not valid_name(name):
|
||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||
if requires is not None:
|
||||
calc_properties, requires = validate_requires_arg(self,
|
||||
is_multi,
|
||||
requires,
|
||||
name)
|
||||
else:
|
||||
calc_properties = frozenset()
|
||||
requires = undefined
|
||||
if properties is None:
|
||||
properties = frozenset()
|
||||
elif isinstance(properties, tuple):
|
||||
|
@ -92,153 +77,18 @@ class Base:
|
|||
assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
|
||||
' must be a frozenset').format(type(properties),
|
||||
name)
|
||||
self.validate_properties(name,
|
||||
calc_properties,
|
||||
properties)
|
||||
_setattr = object.__setattr__
|
||||
_setattr(self, '_name', name)
|
||||
_setattr(self, '_informations', {'doc': doc})
|
||||
if calc_properties is not undefined:
|
||||
_setattr(self, '_calc_properties', calc_properties)
|
||||
if requires is not undefined:
|
||||
_setattr(self, '_requires', requires)
|
||||
if properties:
|
||||
_setattr(self, '_properties', properties)
|
||||
|
||||
def validate_properties(self,
|
||||
name: str,
|
||||
calc_properties: FrozenSet[str],
|
||||
properties: FrozenSet[str]) -> None:
|
||||
set_forbidden_properties = calc_properties & properties
|
||||
if set_forbidden_properties != frozenset():
|
||||
raise ValueError(_('conflict: properties already set in requirement {0} for {1}'
|
||||
'').format(display_list(set_forbidden_properties, add_quote=True),
|
||||
name))
|
||||
assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
|
||||
' must be a frozenset').format(type(properties),
|
||||
name)
|
||||
for prop in properties:
|
||||
if not isinstance(prop, str):
|
||||
if not isinstance(prop, Calculation):
|
||||
raise ValueError(_('invalid property type {0} for {1}, must be a string or a Calculation').format(type(prop), name))
|
||||
params = prop.params
|
||||
for param in chain(params.args, params.kwargs.values()):
|
||||
for param in chain(prop.params.args, prop.params.kwargs.values()):
|
||||
if isinstance(param, ParamOption):
|
||||
param.option._add_dependency(self)
|
||||
|
||||
def _get_function_args(self,
|
||||
function: Callable) -> Tuple[Set[str], Set[str], bool, bool]:
|
||||
args = set()
|
||||
kwargs = set()
|
||||
positional = False
|
||||
keyword = False
|
||||
for param in signature(function).parameters.values():
|
||||
if param.kind == param.VAR_POSITIONAL:
|
||||
positional = True
|
||||
elif param.kind == param.VAR_KEYWORD:
|
||||
keyword = True
|
||||
elif param.default is param.empty:
|
||||
args.add(param.name)
|
||||
else:
|
||||
kwargs.add(param.name)
|
||||
return args, kwargs, positional, keyword
|
||||
|
||||
def _get_parameters_args(self,
|
||||
calculator_params: Optional[Params],
|
||||
add_value: bool) -> Tuple[Set[str], Set[str]]:
|
||||
args = set()
|
||||
kwargs = set()
|
||||
# add value as first argument
|
||||
if add_value:
|
||||
args.add('value')
|
||||
if self.impl_is_dynoptiondescription():
|
||||
kwargs.add('suffix')
|
||||
if calculator_params:
|
||||
for idx in range(len(calculator_params.args)):
|
||||
# construct an appropriate name
|
||||
args.add('param{}'.format(idx))
|
||||
for param in calculator_params.kwargs:
|
||||
kwargs.add(param)
|
||||
return args, kwargs
|
||||
|
||||
def _build_calculator_params(self,
|
||||
calculator: Callable,
|
||||
calculator_params: Optional[Params],
|
||||
type_: str,
|
||||
add_value: bool=False) -> Union[None, Params]:
|
||||
"""
|
||||
:add_value: add value as first argument for validator
|
||||
"""
|
||||
assert isinstance(calculator, Callable), _('{0} must be a function').format(type_)
|
||||
if calculator_params is not None:
|
||||
assert isinstance(calculator_params, Params), _('{0}_params must be a params'
|
||||
'').format(type_)
|
||||
for param in chain(calculator_params.args, calculator_params.kwargs.values()):
|
||||
if isinstance(param, ParamContext):
|
||||
self._has_calc_context = True
|
||||
elif isinstance(param, ParamOption):
|
||||
param.option._add_dependency(self)
|
||||
if type_ == 'validator':
|
||||
self._has_dependency = True
|
||||
is_multi = self.impl_is_optiondescription() or self.impl_is_multi()
|
||||
func_args, func_kwargs, func_positional, func_keyword = self._get_function_args(calculator)
|
||||
calculator_args, calculator_kwargs = self._get_parameters_args(calculator_params, add_value)
|
||||
# remove knowned kwargs
|
||||
common_kwargs = func_kwargs & calculator_kwargs
|
||||
func_kwargs -= common_kwargs
|
||||
calculator_kwargs -= common_kwargs
|
||||
# remove knowned calculator's kwargs in func's args
|
||||
common = func_args & calculator_kwargs
|
||||
func_args -= common
|
||||
calculator_kwargs -= common
|
||||
# remove unknown calculator's args in func's args
|
||||
for idx in range(min(len(calculator_args), len(func_args))):
|
||||
func_args.pop()
|
||||
calculator_args.pop()
|
||||
# remove unknown calculator's args in func's kwargs
|
||||
if is_multi:
|
||||
func_kwargs_left = func_kwargs - {'index', 'self'}
|
||||
else:
|
||||
func_kwargs_left = func_kwargs
|
||||
func_kwargs_pop = set()
|
||||
for idx in range(min(len(calculator_args), len(func_kwargs_left))):
|
||||
func_kwargs_pop.add(func_kwargs_left.pop())
|
||||
calculator_args.pop()
|
||||
func_kwargs -= func_kwargs_pop
|
||||
# func_positional or keyword is True, so assume all args or kwargs are satisfy
|
||||
if func_positional:
|
||||
calculator_args = set()
|
||||
if func_keyword:
|
||||
calculator_kwargs = set()
|
||||
if calculator_args or calculator_kwargs:
|
||||
# there is more args/kwargs than expected!
|
||||
raise ConfigError(_('cannot find those arguments "{}" in function "{}" for "{}"'
|
||||
'').format(display_list(list(calculator_args | calculator_kwargs)),
|
||||
calculator.__name__,
|
||||
self.impl_get_display_name()))
|
||||
has_index = False
|
||||
if is_multi and func_args and not self.impl_is_dynoptiondescription():
|
||||
if calculator_params is None:
|
||||
calculator_params = Params()
|
||||
params = list(calculator_params.args)
|
||||
if add_value:
|
||||
# only for validator
|
||||
params.append(ParamOption(self))
|
||||
func_args.pop()
|
||||
if func_args:
|
||||
has_index = True
|
||||
params.append(ParamIndex())
|
||||
func_args.pop()
|
||||
calculator_params.args = tuple(params)
|
||||
if func_args:
|
||||
raise ConfigError(_('missing those arguments "{}" in function "{}" for "{}"'
|
||||
'').format(display_list(list(func_args)),
|
||||
calculator.__name__,
|
||||
self.impl_get_display_name()))
|
||||
if not self.impl_is_dynoptiondescription() and is_multi and \
|
||||
not has_index and 'index' in func_kwargs:
|
||||
calculator_params.kwargs['index'] = ParamIndex()
|
||||
return calculator_params
|
||||
_setattr = object.__setattr__
|
||||
_setattr(self, '_name', name)
|
||||
_setattr(self, '_informations', {'doc': doc})
|
||||
if properties:
|
||||
_setattr(self, '_properties', properties)
|
||||
|
||||
def impl_has_dependency(self,
|
||||
self_is_dep: bool=True) -> bool:
|
||||
|
@ -323,9 +173,6 @@ class Base:
|
|||
def getsubdyn(self):
|
||||
return self._subdyn()
|
||||
|
||||
def impl_getrequires(self):
|
||||
return getattr(self, '_requires', STATIC_TUPLE)
|
||||
|
||||
def impl_get_callback(self):
|
||||
call = getattr(self, '_val_call', (None, None))[1]
|
||||
if call is None:
|
||||
|
@ -373,7 +220,6 @@ class Base:
|
|||
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
|
||||
" read-only").format(self.__class__.__name__,
|
||||
self,
|
||||
#self.impl_getname(),
|
||||
key))
|
||||
self._informations[key] = value
|
||||
|
||||
|
@ -445,181 +291,3 @@ class BaseOption(Base):
|
|||
|
||||
def impl_is_symlinkoption(self) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def validate_requires_arg(new_option: BaseOption,
|
||||
multi: bool,
|
||||
requires: List[dict],
|
||||
name: str) -> Tuple[FrozenSet, Tuple]:
|
||||
"""check malformed requirements
|
||||
and tranform dict to internal tuple
|
||||
|
||||
:param requires: have a look at the
|
||||
:meth:`tiramisu.setting.Settings.apply_requires` method to
|
||||
know more about
|
||||
the description of the requires dictionary
|
||||
"""
|
||||
def get_option(require):
|
||||
if 'option' in require:
|
||||
option = require['option']
|
||||
if option == 'self':
|
||||
option = new_option
|
||||
if __debug__:
|
||||
if not isinstance(option, BaseOption):
|
||||
raise ValueError(_('malformed requirements '
|
||||
'must be an option in option {0}').format(name))
|
||||
if not multi and option.impl_is_multi():
|
||||
raise ValueError(_('malformed requirements '
|
||||
'multi option must not set '
|
||||
'as requires of non multi option {0}').format(name))
|
||||
option._add_dependency(new_option)
|
||||
else:
|
||||
callback = require['callback']
|
||||
callback_params = new_option._build_calculator_params(callback,
|
||||
require.get('callback_params'),
|
||||
'callback')
|
||||
option = (callback, callback_params)
|
||||
return option
|
||||
|
||||
def _set_expected(action,
|
||||
inverse,
|
||||
transitive,
|
||||
same_action,
|
||||
option,
|
||||
expected,
|
||||
operator):
|
||||
if inverse not in ret_requires[action]:
|
||||
ret_requires[action][inverse] = ([(option, [expected])], action, inverse, transitive, same_action, operator)
|
||||
else:
|
||||
for exp in ret_requires[action][inverse][0]:
|
||||
if exp[0] == option:
|
||||
exp[1].append(expected)
|
||||
break
|
||||
else:
|
||||
ret_requires[action][inverse][0].append((option, [expected]))
|
||||
|
||||
def set_expected(require,
|
||||
ret_requires):
|
||||
expected = require['expected']
|
||||
inverse = get_inverse(require)
|
||||
transitive = get_transitive(require)
|
||||
same_action = get_sameaction(require)
|
||||
operator = get_operator(require)
|
||||
if isinstance(expected, list):
|
||||
for exp in expected:
|
||||
if __debug__ and set(exp.keys()) != {'option', 'value'}:
|
||||
raise ValueError(_('malformed requirements expected must have '
|
||||
'option and value for option {0}').format(name))
|
||||
option = get_option(exp)
|
||||
if __debug__:
|
||||
try:
|
||||
option._validate(exp['value'], undefined)
|
||||
except ValueError as err:
|
||||
raise ValueError(_('malformed requirements expected value '
|
||||
'must be valid for option {0}'
|
||||
': {1}').format(name, err))
|
||||
_set_expected(action,
|
||||
inverse,
|
||||
transitive,
|
||||
same_action,
|
||||
option,
|
||||
exp['value'],
|
||||
operator)
|
||||
else:
|
||||
option = get_option(require)
|
||||
if __debug__ and not isinstance(option, tuple) and expected is not None:
|
||||
try:
|
||||
option._validate(expected, undefined)
|
||||
except ValueError as err:
|
||||
raise ValueError(_('malformed requirements expected value '
|
||||
'must be valid for option {0}'
|
||||
': {1}').format(name, err))
|
||||
_set_expected(action,
|
||||
inverse,
|
||||
transitive,
|
||||
same_action,
|
||||
option,
|
||||
expected,
|
||||
operator)
|
||||
|
||||
def get_action(require):
|
||||
action = require['action']
|
||||
if action == 'force_store_value':
|
||||
raise ValueError(_("malformed requirements for option: {0}"
|
||||
" action cannot be force_store_value"
|
||||
).format(name))
|
||||
return action
|
||||
|
||||
def get_inverse(require):
|
||||
inverse = require.get('inverse', False)
|
||||
if inverse not in [True, False]:
|
||||
raise ValueError(_('malformed requirements for option: {0}'
|
||||
' inverse must be boolean'))
|
||||
return inverse
|
||||
|
||||
def get_transitive(require):
|
||||
transitive = require.get('transitive', True)
|
||||
if transitive not in [True, False]:
|
||||
raise ValueError(_('malformed requirements for option: {0}'
|
||||
' transitive must be boolean'))
|
||||
return transitive
|
||||
|
||||
def get_sameaction(require):
|
||||
same_action = require.get('same_action', True)
|
||||
if same_action not in [True, False]:
|
||||
raise ValueError(_('malformed requirements for option: {0}'
|
||||
' same_action must be boolean'))
|
||||
return same_action
|
||||
|
||||
def get_operator(require):
|
||||
operator = require.get('operator', 'or')
|
||||
if operator not in ['and', 'or']:
|
||||
raise ValueError(_('malformed requirements for option: "{0}"'
|
||||
' operator must be "or" or "and"').format(operator))
|
||||
return operator
|
||||
|
||||
|
||||
ret_requires = {}
|
||||
config_action = set()
|
||||
|
||||
# start parsing all requires given by user (has dict)
|
||||
# transforme it to a tuple
|
||||
for require in requires:
|
||||
if __debug__:
|
||||
if not isinstance(require, dict):
|
||||
raise ValueError(_("malformed requirements type for option:"
|
||||
" {0}, must be a dict").format(name))
|
||||
valid_keys = ('option', 'expected', 'action', 'inverse', 'transitive',
|
||||
'same_action', 'operator', 'callback', 'callback_params')
|
||||
unknown_keys = frozenset(require.keys()) - frozenset(valid_keys)
|
||||
if unknown_keys != frozenset():
|
||||
raise ValueError(_('malformed requirements for option: {0}'
|
||||
' unknown keys {1}, must only '
|
||||
'{2}').format(name,
|
||||
unknown_keys,
|
||||
valid_keys))
|
||||
# {'expected': ..., 'option': ..., 'action': ...}
|
||||
# {'expected': [{'option': ..., 'value': ...}, ...}], 'action': ...}
|
||||
# {'expected': ..., 'callback': ..., 'action': ...}
|
||||
if not 'expected' in require or not 'action' in require or \
|
||||
not (isinstance(require['expected'], list) or \
|
||||
'option' in require or \
|
||||
'callback' in require):
|
||||
raise ValueError(_("malformed requirements for option: {0}"
|
||||
" require must have option, expected and"
|
||||
" action keys").format(name))
|
||||
action = get_action(require)
|
||||
config_action.add(action)
|
||||
if action not in ret_requires:
|
||||
ret_requires[action] = {}
|
||||
set_expected(require, ret_requires)
|
||||
|
||||
# transform dict to tuple
|
||||
ret = []
|
||||
for requires in ret_requires.values():
|
||||
ret_action = []
|
||||
for require in requires.values():
|
||||
ret_action.append((tuple(require[0]), require[1],
|
||||
require[2], require[3], require[4], require[5]))
|
||||
ret.append(tuple(ret_action))
|
||||
return frozenset(config_action), tuple(ret)
|
||||
|
|
|
@ -46,22 +46,3 @@ class BroadcastOption(Option):
|
|||
ip_address(value)
|
||||
except ValueError:
|
||||
raise ValueError()
|
||||
|
||||
def _cons_broadcast(self,
|
||||
current_opt,
|
||||
opts,
|
||||
vals,
|
||||
warnings_only,
|
||||
context):
|
||||
if len(vals) != 3:
|
||||
raise ConfigError(_('invalid broadcast consistency, a network and a netmask are needed'))
|
||||
if None in vals:
|
||||
return
|
||||
broadcast, network, netmask = vals
|
||||
if ip_network('{0}/{1}'.format(network, netmask)).broadcast_address != ip_address(broadcast):
|
||||
raise ValueError(_('broadcast "{4}" invalid with network {0}/{1} ("{2}"/"{3}")'
|
||||
'').format(network,
|
||||
netmask,
|
||||
opts[1].impl_get_display_name(),
|
||||
opts[2].impl_get_display_name(),
|
||||
broadcast))
|
||||
|
|
|
@ -23,7 +23,7 @@ from types import FunctionType
|
|||
from ..setting import undefined
|
||||
from ..i18n import _
|
||||
from .option import Option
|
||||
from ..autolib import carry_out_calculation
|
||||
from ..autolib import carry_out_calculation, Calculation
|
||||
from ..error import ConfigError, display_list
|
||||
|
||||
|
||||
|
@ -41,83 +41,44 @@ class ChoiceOption(Option):
|
|||
doc,
|
||||
values,
|
||||
default=None,
|
||||
values_params=None,
|
||||
default_multi=None,
|
||||
requires=None,
|
||||
multi=False,
|
||||
callback=None,
|
||||
callback_params=None,
|
||||
validator=None,
|
||||
validator_params=None,
|
||||
validators=None,
|
||||
properties=None,
|
||||
warnings_only=False):
|
||||
|
||||
"""
|
||||
:param values: is a list of values the option can possibly take
|
||||
"""
|
||||
if isinstance(values, FunctionType):
|
||||
values_params = self._build_calculator_params(values,
|
||||
values_params,
|
||||
'values')
|
||||
if values_params:
|
||||
self._choice_values_params = values_params
|
||||
else:
|
||||
if values_params is not None:
|
||||
raise ValueError(_('values is not a function, so values_params must be None'))
|
||||
if not isinstance(values, tuple):
|
||||
raise TypeError(_('values must be a tuple or a function for {0}'
|
||||
).format(name))
|
||||
if not isinstance(values, (Calculation, tuple)):
|
||||
raise TypeError(_('values must be a tuple or a calculation for {0}'
|
||||
).format(name))
|
||||
self._choice_values = values
|
||||
super(ChoiceOption, self).__init__(name,
|
||||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
requires=requires,
|
||||
multi=multi,
|
||||
validator=validator,
|
||||
validator_params=validator_params,
|
||||
validators=validators,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only)
|
||||
|
||||
def get_callback(self):
|
||||
values = self._choice_values
|
||||
if isinstance(values, FunctionType):
|
||||
return (values, getattr(self, '_choice_values_params', {}))
|
||||
else:
|
||||
return (None, None)
|
||||
|
||||
def impl_get_values(self,
|
||||
option_bag,
|
||||
current_opt=undefined):
|
||||
if current_opt is undefined:
|
||||
current_opt = self
|
||||
values, values_params = self.get_callback()
|
||||
if values is not None:
|
||||
if option_bag is undefined:
|
||||
values = undefined
|
||||
else:
|
||||
values = carry_out_calculation(current_opt,
|
||||
callback=values,
|
||||
callback_params=values_params,
|
||||
index=None,
|
||||
config_bag=option_bag.config_bag,
|
||||
fromconsistency=[])
|
||||
if values is not undefined and not isinstance(values, list):
|
||||
raise ConfigError(_('calculated values for {0} is not a list'
|
||||
'').format(self.impl_getname()))
|
||||
option_bag):
|
||||
if isinstance(self._choice_values, Calculation):
|
||||
values = self._choice_values.execute(option_bag)
|
||||
if values is not undefined and not isinstance(values, list):
|
||||
raise ConfigError(_('calculated values for {0} is not a list'
|
||||
'').format(self.impl_getname()))
|
||||
else:
|
||||
values = self._choice_values
|
||||
return values
|
||||
|
||||
|
||||
def _validate(self,
|
||||
value,
|
||||
option_bag,
|
||||
current_opt=undefined):
|
||||
values = self.impl_get_values(option_bag,
|
||||
current_opt=current_opt)
|
||||
values = self.impl_get_values(option_bag)
|
||||
if values is not undefined and value not in values:
|
||||
if len(values) == 1:
|
||||
raise ValueError(_('only "{0}" is allowed'
|
||||
|
|
|
@ -42,12 +42,8 @@ class DomainnameOption(IPOption):
|
|||
doc,
|
||||
default=None,
|
||||
default_multi=None,
|
||||
requires=None,
|
||||
multi: bool=False,
|
||||
callback=None,
|
||||
callback_params=None,
|
||||
validator=None,
|
||||
validator_params=None,
|
||||
validators=None,
|
||||
properties=None,
|
||||
allow_ip: bool=False,
|
||||
cidr: bool=False,
|
||||
|
@ -94,12 +90,8 @@ class DomainnameOption(IPOption):
|
|||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
requires=requires,
|
||||
multi=multi,
|
||||
validator=validator,
|
||||
validator_params=validator_params,
|
||||
validators=validators,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
cidr=cidr,
|
||||
|
|
|
@ -41,13 +41,11 @@ class DynOptionDescription(OptionDescription):
|
|||
doc: str,
|
||||
children: List[BaseOption],
|
||||
suffixes: Calculation,
|
||||
requires=None,
|
||||
properties=None) -> None:
|
||||
|
||||
super().__init__(name,
|
||||
doc,
|
||||
children,
|
||||
requires,
|
||||
properties)
|
||||
# check children + set relation to this dynoptiondescription
|
||||
for child in children:
|
||||
|
|
|
@ -18,15 +18,14 @@
|
|||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||
# the whole pypy projet is under MIT licence
|
||||
# ____________________________________________________________
|
||||
from ipaddress import ip_address, ip_interface, ip_network
|
||||
from ipaddress import ip_address, ip_interface
|
||||
|
||||
from ..error import ConfigError
|
||||
from ..setting import undefined, Undefined, OptionBag
|
||||
from ..i18n import _
|
||||
from .option import Option
|
||||
from .stroption import StrOption
|
||||
from .netmaskoption import NetmaskOption
|
||||
from .networkoption import NetworkOption
|
||||
from ..function import valid_ip_netmask
|
||||
|
||||
|
||||
class IPOption(StrOption):
|
||||
|
@ -40,12 +39,8 @@ class IPOption(StrOption):
|
|||
doc,
|
||||
default=None,
|
||||
default_multi=None,
|
||||
requires=None,
|
||||
multi=False,
|
||||
callback=None,
|
||||
callback_params=None,
|
||||
validator=None,
|
||||
validator_params=None,
|
||||
validators=None,
|
||||
properties=None,
|
||||
private_only=False,
|
||||
allow_reserved=False,
|
||||
|
@ -63,12 +58,8 @@ class IPOption(StrOption):
|
|||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
requires=requires,
|
||||
multi=multi,
|
||||
validator=validator,
|
||||
validator_params=validator_params,
|
||||
validators=validators,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
extra=extra)
|
||||
|
@ -98,9 +89,11 @@ class IPOption(StrOption):
|
|||
if not cidr:
|
||||
ip_address(value)
|
||||
else:
|
||||
ip_interface(value)
|
||||
ip = ip_interface(value)
|
||||
except ValueError:
|
||||
raise ValueError()
|
||||
if cidr:
|
||||
valid_ip_netmask(str(ip.ip), str(ip.netmask))
|
||||
|
||||
def _second_level_validation(self,
|
||||
value,
|
||||
|
@ -118,68 +111,3 @@ class IPOption(StrOption):
|
|||
else:
|
||||
msg = _("must be private IP")
|
||||
raise ValueError(msg)
|
||||
if '/' in value:
|
||||
net = NetmaskOption(self.impl_getname(),
|
||||
self.impl_get_display_name(),
|
||||
str(ip.netmask))
|
||||
net._cons_ip_netmask(self,
|
||||
(net, self),
|
||||
(str(ip.netmask), str(ip.ip)),
|
||||
warnings_only,
|
||||
None,
|
||||
True)
|
||||
|
||||
def _cons_in_network(self,
|
||||
current_opt,
|
||||
opts,
|
||||
vals,
|
||||
warnings_only,
|
||||
context):
|
||||
if len(opts) == 2 and isinstance(opts[0], IPOption) and \
|
||||
opts[0].impl_get_extra('_cidr') == False and \
|
||||
isinstance(opts[1], NetworkOption) and \
|
||||
opts[1].impl_get_extra('_cidr') == True:
|
||||
if None in vals:
|
||||
return
|
||||
ip, network = vals
|
||||
network_obj = ip_network(network)
|
||||
if ip_interface(ip) not in network_obj:
|
||||
msg = _('IP not in network "{0}" ("{1}")')
|
||||
raise ValueError(msg.format(network,
|
||||
opts[1].impl_get_display_name()))
|
||||
# test if ip is not network/broadcast IP
|
||||
netmask = NetmaskOption(self.impl_getname(),
|
||||
self.impl_get_display_name(),
|
||||
str(network_obj.netmask))
|
||||
netmask._cons_ip_netmask(self,
|
||||
(netmask, self),
|
||||
(str(network_obj.netmask), str(ip)),
|
||||
warnings_only,
|
||||
None,
|
||||
True)
|
||||
else:
|
||||
if len(vals) != 3 and context is undefined:
|
||||
raise ConfigError(_('ip_network needs an IP, a network and a netmask'))
|
||||
if len(vals) != 3 or None in vals:
|
||||
return
|
||||
ip, network, netmask = vals
|
||||
if ip_interface(ip) not in ip_network('{0}/{1}'.format(network,
|
||||
netmask)):
|
||||
if current_opt == opts[0]:
|
||||
msg = _('IP not in network "{2}"/"{4}" ("{3}"/"{5}")')
|
||||
elif current_opt == opts[1]:
|
||||
msg = _('the network doest not match with IP "{0}" ("{1}") and network "{4}" ("{5}")')
|
||||
else:
|
||||
msg = _('the netmask does not match with IP "{0}" ("{1}") and broadcast "{2}" ("{3}")')
|
||||
raise ValueError(msg.format(ip,
|
||||
opts[0].impl_get_display_name(),
|
||||
network,
|
||||
opts[1].impl_get_display_name(),
|
||||
netmask,
|
||||
opts[2].impl_get_display_name()))
|
||||
# test if ip is not network/broadcast IP
|
||||
opts[2]._cons_ip_netmask(current_opt,
|
||||
(opts[2], opts[0]),
|
||||
(netmask, ip),
|
||||
warnings_only,
|
||||
context)
|
||||
|
|
|
@ -25,13 +25,13 @@ from typing import List, Iterator, Optional, Any
|
|||
|
||||
|
||||
from ..i18n import _
|
||||
from ..setting import groups, undefined, OptionBag, Settings
|
||||
from ..setting import groups, undefined, OptionBag, Settings, ALLOWED_LEADER_PROPERTIES
|
||||
from ..value import Values
|
||||
from .optiondescription import OptionDescription
|
||||
from .syndynoptiondescription import SynDynLeadership
|
||||
from .baseoption import BaseOption
|
||||
from .option import Option
|
||||
from ..error import RequirementError
|
||||
from ..error import LeadershipError
|
||||
from ..autolib import Calculation, ParamOption
|
||||
|
||||
|
||||
|
@ -43,12 +43,10 @@ class Leadership(OptionDescription):
|
|||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
requires=None,
|
||||
properties=None) -> None:
|
||||
super().__init__(name,
|
||||
doc,
|
||||
children,
|
||||
requires=requires,
|
||||
properties=properties)
|
||||
self._group_type = groups.leadership
|
||||
followers = []
|
||||
|
@ -93,28 +91,9 @@ class Leadership(OptionDescription):
|
|||
raise ValueError(_("callback of leader's option shall "
|
||||
"not refered to a follower's ones"))
|
||||
|
||||
# leader should not have requires, only Leadership should have
|
||||
# so move requires to Leadership
|
||||
# if Leadership has requires too, cannot manage this move so raises
|
||||
leader_requires = getattr(leader, '_requires', None)
|
||||
if leader_requires:
|
||||
if __debug__ and self.impl_getrequires():
|
||||
raise RequirementError(_('leader {} have requirement, but Leadership {} too'
|
||||
'').format(leader.impl_getname(),
|
||||
self.impl_getname()))
|
||||
leader_calproperties = getattr(leader, '_requires', None)
|
||||
if leader_calproperties:
|
||||
setattr(self, '_requires', leader_requires)
|
||||
delattr(leader, '_requires')
|
||||
if __debug__:
|
||||
for requires_ in getattr(self, '_requires', ()):
|
||||
for require in requires_:
|
||||
for require_opt, values in require[0]:
|
||||
if not isinstance(require_opt, tuple) and require_opt.impl_is_multi() and require_opt.impl_get_leadership():
|
||||
raise ValueError(_('malformed requirements option "{0}" '
|
||||
'must not be in follower for "{1}"').format(
|
||||
require_opt.impl_getname(),
|
||||
self.impl_getname()))
|
||||
for prop in leader.impl_getproperties():
|
||||
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(prop, Calculation):
|
||||
raise LeadershipError(_('leader cannot have "{}" property').format(prop))
|
||||
|
||||
def is_leader(self,
|
||||
opt: Option) -> bool:
|
||||
|
|
|
@ -49,58 +49,3 @@ class NetmaskOption(StrOption):
|
|||
ip_network('0.0.0.0/{0}'.format(value))
|
||||
except ValueError:
|
||||
raise ValueError()
|
||||
|
||||
def _cons_network_netmask(self,
|
||||
current_opt: Option,
|
||||
opts: List[Option],
|
||||
vals: List[str],
|
||||
warnings_only: bool,
|
||||
context: 'Config'):
|
||||
if context is undefined and len(vals) != 2:
|
||||
raise ConfigError(_('network_netmask needs a network and a netmask'))
|
||||
if None in vals or len(vals) != 2:
|
||||
return
|
||||
val_netmask, val_network = vals
|
||||
opt_netmask, opt_network = opts
|
||||
try:
|
||||
ip_network('{0}/{1}'.format(val_network, val_netmask))
|
||||
except ValueError:
|
||||
if current_opt == opt_network:
|
||||
raise ValueError(_('the netmask "{0}" ("{1}") does not match').format(val_netmask,
|
||||
opt_netmask.impl_get_display_name()))
|
||||
else:
|
||||
raise ValueError(_('the network "{0}" ("{1}") does not match').format(val_network,
|
||||
opt_network.impl_get_display_name()))
|
||||
|
||||
def _cons_ip_netmask(self,
|
||||
current_opt: Option,
|
||||
opts: List[Option],
|
||||
vals: List[str],
|
||||
warnings_only: bool,
|
||||
context: 'config',
|
||||
_cidr: bool=False):
|
||||
if context is undefined and len(vals) != 2:
|
||||
raise ConfigError(_('ip_netmask needs an IP and a netmask'))
|
||||
if None in vals or len(vals) != 2:
|
||||
return
|
||||
val_netmask, val_ip = vals
|
||||
opt_netmask, opt_ip = opts
|
||||
ip = ip_interface('{0}/{1}'.format(val_ip, val_netmask))
|
||||
if not _cidr and current_opt == opt_ip:
|
||||
if ip.ip == ip.network.network_address:
|
||||
raise ValueError( _('this is a network with netmask "{0}" ("{1}")'
|
||||
'').format(val_netmask,
|
||||
opt_netmask.impl_get_display_name()))
|
||||
elif ip.ip == ip.network.broadcast_address:
|
||||
raise ValueError(_('this is a broadcast with netmask "{0}" ("{1}")'
|
||||
'').format(val_netmask,
|
||||
opt_netmask.impl_get_display_name()))
|
||||
else:
|
||||
if ip.ip == ip.network.network_address:
|
||||
raise ValueError(_('IP "{0}" ("{1}") is the network'
|
||||
'').format(val_ip,
|
||||
opt_ip.impl_get_display_name()))
|
||||
elif ip.ip == ip.network.broadcast_address:
|
||||
raise ValueError(_('IP "{0}" ("{1}") is the broadcast'
|
||||
'').format(val_ip,
|
||||
opt_ip.impl_get_display_name()))
|
||||
|
|
|
@ -36,12 +36,8 @@ class NetworkOption(Option):
|
|||
doc,
|
||||
default=None,
|
||||
default_multi=None,
|
||||
requires=None,
|
||||
multi=False,
|
||||
callback=None,
|
||||
callback_params=None,
|
||||
validator=None,
|
||||
validator_params=None,
|
||||
validators=None,
|
||||
properties=None,
|
||||
warnings_only=False,
|
||||
cidr=False):
|
||||
|
@ -50,12 +46,8 @@ class NetworkOption(Option):
|
|||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
requires=requires,
|
||||
multi=multi,
|
||||
validator=validator,
|
||||
validator_params=validator_params,
|
||||
validators=validators,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
extra=extra)
|
||||
|
|
|
@ -27,11 +27,11 @@ from itertools import chain
|
|||
from .baseoption import BaseOption, submulti, STATIC_TUPLE
|
||||
from ..i18n import _
|
||||
from ..setting import undefined, OptionBag, Undefined
|
||||
from ..autolib import Calculation, carry_out_calculation, Params, ParamValue, ParamContext, ParamOption
|
||||
from ..autolib import Calculation, Params, ParamValue, ParamContext, ParamOption
|
||||
from ..error import (ConfigError, ValueWarning, ValueErrorWarning, PropertiesOptionError,
|
||||
ValueOptionError, display_list)
|
||||
from .syndynoption import SynDynOption
|
||||
ALLOWED_CONST_LIST = ['_cons_not_equal']
|
||||
#ALLOWED_CONST_LIST = ['_cons_not_equal']
|
||||
|
||||
|
||||
class Option(BaseOption):
|
||||
|
@ -43,14 +43,14 @@ class Option(BaseOption):
|
|||
__slots__ = ('_extra',
|
||||
'_warnings_only',
|
||||
'_allow_empty_list',
|
||||
#multi
|
||||
# multi
|
||||
'_multi',
|
||||
'_unique',
|
||||
#value
|
||||
# value
|
||||
'_default',
|
||||
'_default_multi',
|
||||
#calcul
|
||||
'_val_call',
|
||||
#
|
||||
'_validators',
|
||||
#
|
||||
'_leadership',
|
||||
'_choice_values',
|
||||
|
@ -62,13 +62,9 @@ class Option(BaseOption):
|
|||
doc: str,
|
||||
default: Any=undefined,
|
||||
default_multi: Any=None,
|
||||
requires: List[Dict]=None,
|
||||
multi: bool=False,
|
||||
unique: bool=undefined,
|
||||
callback: Optional[Callable]=None,
|
||||
callback_params: Optional[Params]=None,
|
||||
validator: Optional[Callable]=None,
|
||||
validator_params: Optional[Params]=None,
|
||||
validators: Optional[List[Calculation]]=None,
|
||||
properties: Optional[List[str]]=None,
|
||||
warnings_only: bool=False,
|
||||
extra: Optional[Dict]=None,
|
||||
|
@ -99,19 +95,23 @@ class Option(BaseOption):
|
|||
default = []
|
||||
super().__init__(name,
|
||||
doc,
|
||||
requires=requires,
|
||||
properties=properties,
|
||||
is_multi=is_multi)
|
||||
if validator is not None:
|
||||
validator_params = self._build_calculator_params(validator,
|
||||
validator_params,
|
||||
'validator',
|
||||
add_value=True)
|
||||
if not validator_params:
|
||||
val_call = (validator,)
|
||||
else:
|
||||
val_call = (validator, validator_params)
|
||||
self._val_call = (val_call, None)
|
||||
if __debug__:
|
||||
if validators is not None:
|
||||
if not isinstance(validators, list):
|
||||
raise ValueError(_('validators must be a list of Calculation for "{}"').format(name))
|
||||
for validator in validators:
|
||||
if not isinstance(validator, Calculation):
|
||||
raise ValueError(_('validators must be a Calculation for "{}"').format(name))
|
||||
for param in chain(validator.params.args, validator.params.kwargs.values()):
|
||||
if isinstance(param, ParamContext):
|
||||
self._has_calc_context = True
|
||||
elif isinstance(param, ParamOption):
|
||||
param.option._add_dependency(self)
|
||||
self._has_dependency = True
|
||||
|
||||
self._validators = tuple(validators)
|
||||
if extra is not None and extra != {}:
|
||||
_setattr(self, '_extra', extra)
|
||||
if unique != undefined and not isinstance(unique, bool):
|
||||
|
@ -126,9 +126,14 @@ class Option(BaseOption):
|
|||
def test_multi_value(value):
|
||||
if isinstance(value, Calculation):
|
||||
return
|
||||
option_bag = OptionBag()
|
||||
option_bag.set_option(self,
|
||||
undefined,
|
||||
None,
|
||||
undefined)
|
||||
try:
|
||||
self._validate(value,
|
||||
undefined)
|
||||
option_bag)
|
||||
except ValueError as err:
|
||||
str_err = str(err)
|
||||
if not str_err:
|
||||
|
@ -168,9 +173,6 @@ class Option(BaseOption):
|
|||
default = tuple(default)
|
||||
_setattr(self, '_default', default)
|
||||
|
||||
self._impl_set_callback(callback,
|
||||
callback_params)
|
||||
|
||||
def value_dependencies(self,
|
||||
value: Any) -> Any:
|
||||
if isinstance(value, list):
|
||||
|
@ -250,16 +252,6 @@ class Option(BaseOption):
|
|||
#__________________________________________________________________________
|
||||
# validator
|
||||
|
||||
def impl_get_validator(self) -> Tuple[Callable, Params]:
|
||||
val = getattr(self, '_val_call', (None,))[0]
|
||||
if val is None:
|
||||
ret_val = (None, None)
|
||||
elif len(val) == 1:
|
||||
ret_val = (val[0], None)
|
||||
else:
|
||||
ret_val = val
|
||||
return ret_val
|
||||
|
||||
def impl_validate(self,
|
||||
value: Any,
|
||||
option_bag: OptionBag,
|
||||
|
@ -272,13 +264,9 @@ class Option(BaseOption):
|
|||
|
||||
if check_error and config_bag is not undefined and \
|
||||
not 'validator' in config_bag.properties:
|
||||
# just to check propertieserror
|
||||
self.valid_consistency(option_bag,
|
||||
value,
|
||||
check_error,
|
||||
is_warnings_only)
|
||||
return
|
||||
|
||||
|
||||
def _is_not_unique(value):
|
||||
# if set(value) has not same length than value
|
||||
if check_error and self.impl_is_unique() and \
|
||||
|
@ -291,26 +279,33 @@ class Option(BaseOption):
|
|||
|
||||
def calculation_validator(val,
|
||||
_index):
|
||||
validator, validator_params = self.impl_get_validator()
|
||||
if validator is not None:
|
||||
#inject value in calculation
|
||||
if validator_params is None:
|
||||
args = []
|
||||
kwargs = None
|
||||
else:
|
||||
args = list(validator_params.args)
|
||||
kwargs = validator_params.kwargs
|
||||
args.insert(0, ParamValue(val))
|
||||
validator_params_ = Params(tuple(args), kwargs)
|
||||
# Raise ValueError if not valid
|
||||
carry_out_calculation(option_bag.ori_option,
|
||||
callback=validator,
|
||||
callback_params=validator_params_,
|
||||
index=_index,
|
||||
config_bag=option_bag.config_bag,
|
||||
fromconsistency=option_bag.fromconsistency,
|
||||
orig_value=value,
|
||||
is_validator=True)
|
||||
for validator in getattr(self, '_validators', []):
|
||||
calc_is_warnings_only = hasattr(validator, 'warnings_only') and validator.warnings_only
|
||||
if ((check_error and not calc_is_warnings_only) or
|
||||
(not check_error and calc_is_warnings_only)):
|
||||
try:
|
||||
kwargs = {'allow_raises': True}
|
||||
if _index is not None and option_bag.index == _index:
|
||||
soption_bag = option_bag
|
||||
else:
|
||||
soption_bag = option_bag.copy()
|
||||
soption_bag.index = _index
|
||||
kwargs['orig_value'] = value
|
||||
|
||||
validator.execute(soption_bag,
|
||||
leadership_must_have_index=True,
|
||||
**kwargs)
|
||||
except ValueError as err:
|
||||
if calc_is_warnings_only:
|
||||
warnings.warn_explicit(ValueWarning(val,
|
||||
self._display_name,
|
||||
self,
|
||||
'{0}'.format(err),
|
||||
_index),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
else:
|
||||
raise err
|
||||
|
||||
def do_validation(_value,
|
||||
_index):
|
||||
|
@ -328,8 +323,6 @@ class Option(BaseOption):
|
|||
if ((check_error and not is_warnings_only) or
|
||||
(not check_error and is_warnings_only)):
|
||||
try:
|
||||
calculation_validator(_value,
|
||||
_index)
|
||||
self._second_level_validation(_value,
|
||||
is_warnings_only)
|
||||
except ValueError as err:
|
||||
|
@ -343,6 +336,8 @@ class Option(BaseOption):
|
|||
self.__class__.__name__, 0)
|
||||
else:
|
||||
raise err
|
||||
calculation_validator(_value,
|
||||
_index)
|
||||
try:
|
||||
val = value
|
||||
err_index = force_index
|
||||
|
@ -379,12 +374,6 @@ class Option(BaseOption):
|
|||
for err_index, val in enumerate(value):
|
||||
do_validation(val,
|
||||
err_index)
|
||||
|
||||
if (not is_warnings_only or not check_error) and not isinstance(value, Calculation):
|
||||
self.valid_consistency(option_bag,
|
||||
value,
|
||||
check_error,
|
||||
is_warnings_only)
|
||||
except ValueError as err:
|
||||
if config_bag is undefined or \
|
||||
'demoting_error_warning' not in config_bag.properties:
|
||||
|
@ -419,11 +408,6 @@ class Option(BaseOption):
|
|||
warnings_only: bool) -> None:
|
||||
pass
|
||||
|
||||
#__________________________________________________________________________
|
||||
# leadership
|
||||
# def impl_is_leadership(self):
|
||||
# return self.impl_get_leadership() is not None
|
||||
|
||||
def impl_is_leader(self):
|
||||
leadership = self.impl_get_leadership()
|
||||
if leadership is None:
|
||||
|
@ -442,327 +426,6 @@ class Option(BaseOption):
|
|||
return leadership
|
||||
return leadership()
|
||||
|
||||
#____________________________________________________________
|
||||
# consistencies
|
||||
|
||||
def impl_add_consistency(self,
|
||||
func: str,
|
||||
*other_opts,
|
||||
**params) -> None:
|
||||
"""Add consistency means that value will be validate with other_opts
|
||||
option's values.
|
||||
|
||||
:param func: function's name
|
||||
:type func: `str`
|
||||
:param other_opts: options used to validate value
|
||||
:type other_opts: `list` of `tiramisu.option.Option`
|
||||
:param params: extra params (warnings_only and transitive are allowed)
|
||||
"""
|
||||
if self.impl_is_readonly():
|
||||
raise AttributeError(_("'{0}' ({1}) cannot add consistency, option is"
|
||||
" read-only").format(
|
||||
self.__class__.__name__,
|
||||
self.impl_getname()))
|
||||
self._valid_consistencies(other_opts,
|
||||
func=func)
|
||||
func = '_cons_{0}'.format(func)
|
||||
if func not in dir(self):
|
||||
raise ConfigError(_('consistency {0} not available for this option').format(func))
|
||||
options = [weakref.ref(self)]
|
||||
for option in other_opts:
|
||||
options.append(weakref.ref(option))
|
||||
all_cons_opts = tuple(options)
|
||||
unknown_params = set(params.keys()) - set(['warnings_only', 'transitive'])
|
||||
if unknown_params != set():
|
||||
raise ValueError(_('unknown parameter {0} in consistency').format(unknown_params))
|
||||
self._add_consistency(func,
|
||||
all_cons_opts,
|
||||
params)
|
||||
#validate default value when add consistency
|
||||
option_bag = OptionBag()
|
||||
option_bag.set_option(self,
|
||||
undefined,
|
||||
None,
|
||||
undefined)
|
||||
default = self.impl_getdefault()
|
||||
if isinstance(default, tuple):
|
||||
default = list(default)
|
||||
self.impl_validate(default,
|
||||
option_bag)
|
||||
self.impl_validate(default,
|
||||
option_bag,
|
||||
check_error=False)
|
||||
if func != '_cons_not_equal':
|
||||
#consistency could generate warnings or errors
|
||||
self._has_dependency = True
|
||||
for wopt in all_cons_opts:
|
||||
opt = wopt()
|
||||
if func in ALLOWED_CONST_LIST:
|
||||
if getattr(opt, '_unique', undefined) == undefined:
|
||||
opt._unique = True
|
||||
if opt != self:
|
||||
self._add_dependency(opt)
|
||||
opt._add_dependency(self)
|
||||
|
||||
def _add_consistency(self,
|
||||
func: str,
|
||||
all_cons_opts: List[BaseOption],
|
||||
params: Dict) -> None:
|
||||
cons = (-1, func, all_cons_opts, params)
|
||||
consistencies = getattr(self, '_consistencies', None)
|
||||
if consistencies is None:
|
||||
self._consistencies = [cons]
|
||||
else:
|
||||
consistencies.append(cons)
|
||||
|
||||
def get_consistencies(self):
|
||||
return getattr(self, '_consistencies', STATIC_TUPLE)
|
||||
|
||||
def has_consistencies(self, context) -> bool:
|
||||
descr = context.cfgimpl_get_description()
|
||||
if getattr(descr, '_cache_consistencies', None) is None:
|
||||
return False
|
||||
return self in descr._cache_consistencies
|
||||
|
||||
def valid_consistency(self,
|
||||
option_bag: OptionBag,
|
||||
value: Any,
|
||||
check_error: bool,
|
||||
option_warnings_only: bool) -> None:
|
||||
if option_bag.config_bag is not undefined:
|
||||
descr = option_bag.config_bag.context.cfgimpl_get_description()
|
||||
# no consistency found at all
|
||||
if getattr(descr, '_cache_consistencies', None) is None:
|
||||
return
|
||||
# get consistencies for this option
|
||||
consistencies = descr._cache_consistencies.get(option_bag.option)
|
||||
else:
|
||||
# is no context, get consistencies in option
|
||||
consistencies = option_bag.option.get_consistencies()
|
||||
if consistencies:
|
||||
if option_bag.config_bag is undefined:
|
||||
coption_bag = option_bag.copy()
|
||||
else:
|
||||
cconfig_bag = option_bag.config_bag.copy()
|
||||
cconfig_bag.remove_warnings()
|
||||
cconfig_bag.set_permissive()
|
||||
coption_bag = option_bag.copy()
|
||||
coption_bag.config_bag = cconfig_bag
|
||||
if not option_bag.fromconsistency:
|
||||
fromconsistency_is_empty = True
|
||||
option_bag.fromconsistency = [cons_id for cons_id, f, a, p in consistencies]
|
||||
else:
|
||||
fromconsistency_is_empty = False
|
||||
for cons_id, func, all_cons_opts, params in consistencies:
|
||||
if not fromconsistency_is_empty and cons_id in option_bag.fromconsistency:
|
||||
continue
|
||||
warnings_only = option_warnings_only or params.get('warnings_only', False)
|
||||
if (warnings_only and not check_error) or (not warnings_only and check_error):
|
||||
transitive = params.get('transitive', True)
|
||||
#all_cons_opts[0] is the option where func is set
|
||||
if option_bag.ori_option.impl_is_dynsymlinkoption():
|
||||
opts = []
|
||||
for opt in all_cons_opts:
|
||||
opts.append(opt().to_dynoption(option_bag.ori_option.rootpath,
|
||||
option_bag.ori_option.suffix))
|
||||
wopt = opts[0]
|
||||
else:
|
||||
opts = all_cons_opts
|
||||
wopt = opts[0]()
|
||||
wopt.launch_consistency(self,
|
||||
func,
|
||||
cons_id,
|
||||
coption_bag,
|
||||
value,
|
||||
opts,
|
||||
warnings_only,
|
||||
transitive)
|
||||
if fromconsistency_is_empty:
|
||||
option_bag.fromconsistency = []
|
||||
|
||||
def _valid_consistencies(self,
|
||||
other_opts: List[BaseOption],
|
||||
init: bool=True,
|
||||
func: Optional[str]=None) -> None:
|
||||
if self.issubdyn():
|
||||
dynod = self.getsubdyn()
|
||||
else:
|
||||
dynod = None
|
||||
if self.impl_is_submulti():
|
||||
raise ConfigError(_('cannot add consistency with submulti option'))
|
||||
is_multi = self.impl_is_multi()
|
||||
for opt in other_opts:
|
||||
if isinstance(opt, weakref.ReferenceType):
|
||||
opt = opt()
|
||||
assert not opt.impl_is_submulti(), _('cannot add consistency with submulti option')
|
||||
assert isinstance(opt, Option), _('consistency must be set with an option, not {}').format(opt)
|
||||
if opt.issubdyn():
|
||||
if dynod is None:
|
||||
raise ConfigError(_('almost one option in consistency is '
|
||||
'in a dynoptiondescription but not all'))
|
||||
subod = opt.getsubdyn()
|
||||
if dynod != subod:
|
||||
raise ConfigError(_('option in consistency must be in same'
|
||||
' dynoptiondescription'))
|
||||
dynod = subod
|
||||
elif dynod is not None:
|
||||
raise ConfigError(_('almost one option in consistency is in a '
|
||||
'dynoptiondescription but not all'))
|
||||
if self is opt:
|
||||
raise ConfigError(_('cannot add consistency with itself'))
|
||||
if is_multi != opt.impl_is_multi():
|
||||
raise ConfigError(_('every options in consistency must be '
|
||||
'multi or none'))
|
||||
# FIXME
|
||||
if init and func != 'not_equal':
|
||||
opt._has_dependency = True
|
||||
|
||||
def launch_consistency(self,
|
||||
current_opt: BaseOption,
|
||||
func: Callable,
|
||||
cons_id: int,
|
||||
option_bag: OptionBag,
|
||||
value: Any,
|
||||
opts: List[BaseOption],
|
||||
warnings_only: bool,
|
||||
transitive: bool) -> None:
|
||||
"""Launch consistency now
|
||||
"""
|
||||
all_cons_vals = []
|
||||
all_cons_opts = []
|
||||
length = None
|
||||
for opt in opts:
|
||||
if isinstance(opt, weakref.ReferenceType):
|
||||
opt = opt()
|
||||
try:
|
||||
opt_value = self.get_consistency_value(option_bag,
|
||||
opt,
|
||||
cons_id,
|
||||
value,
|
||||
func)
|
||||
except PropertiesOptionError as err:
|
||||
if transitive:
|
||||
err.set_orig_opt(option_bag.option)
|
||||
raise err
|
||||
else:
|
||||
if opt.impl_is_multi() and option_bag.index is None and \
|
||||
func not in ALLOWED_CONST_LIST:
|
||||
len_value = len(opt_value)
|
||||
if length is not None and length != len_value:
|
||||
if option_bag.config_bag is undefined:
|
||||
return
|
||||
raise ValueError(_('unexpected length of "{}" in constency "{}", '
|
||||
'should be "{}"').format(len(opt_value),
|
||||
opt.impl_get_display_name(),
|
||||
length)) # pragma: no cover
|
||||
length = len_value
|
||||
if isinstance(opt_value, list) and func in ALLOWED_CONST_LIST:
|
||||
for value_ in opt_value:
|
||||
all_cons_vals.append(value_)
|
||||
all_cons_opts.append(opt)
|
||||
else:
|
||||
all_cons_vals.append(opt_value)
|
||||
all_cons_opts.append(opt)
|
||||
if option_bag.config_bag is not undefined and \
|
||||
not 'validator' in option_bag.config_bag.properties:
|
||||
return
|
||||
all_values = []
|
||||
if length is None:
|
||||
all_values = [all_cons_vals]
|
||||
elif length:
|
||||
all_values = zip(*all_cons_vals)
|
||||
try:
|
||||
context = option_bag.config_bag if option_bag.config_bag is undefined else option_bag.config_bag.context
|
||||
for values in all_values:
|
||||
getattr(self, func)(current_opt,
|
||||
all_cons_opts,
|
||||
values,
|
||||
warnings_only,
|
||||
context)
|
||||
except ValueError as err:
|
||||
if warnings_only:
|
||||
warnings.warn_explicit(ValueWarning(value,
|
||||
self._display_name,
|
||||
current_opt,
|
||||
"{}".format(err),
|
||||
option_bag.index),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
else:
|
||||
raise err
|
||||
|
||||
def get_consistency_value(self,
|
||||
option_bag: OptionBag,
|
||||
current_option: BaseOption,
|
||||
cons_id: int,
|
||||
value: Any,
|
||||
func: str) -> Any:
|
||||
if option_bag.ori_option == current_option:
|
||||
# orig_option is current option
|
||||
# we have already value, so use it
|
||||
return value
|
||||
if option_bag.config_bag is undefined:
|
||||
#if no context get default value
|
||||
return current_option.impl_getdefault()
|
||||
if func in ALLOWED_CONST_LIST:
|
||||
index = None
|
||||
index_ = None
|
||||
elif current_option.impl_is_leader():
|
||||
index = option_bag.index
|
||||
index_ = None
|
||||
else:
|
||||
index = option_bag.index
|
||||
index_ = index
|
||||
#otherwise calculate value
|
||||
path = current_option.impl_getpath()
|
||||
coption_bag = OptionBag()
|
||||
coption_bag.set_option(current_option,
|
||||
path,
|
||||
index_,
|
||||
option_bag.config_bag)
|
||||
fromconsistency = option_bag.fromconsistency.copy()
|
||||
fromconsistency.append(cons_id)
|
||||
coption_bag.fromconsistency = fromconsistency
|
||||
current_value = option_bag.config_bag.context.getattr(path,
|
||||
coption_bag)
|
||||
if index_ is None and index is not None:
|
||||
#if self is a follower and current_option is a leader and func not in ALLOWED_CONST_LIST
|
||||
#return only the value of the leader for isolate follower
|
||||
current_value = current_value[index]
|
||||
return current_value
|
||||
|
||||
def _cons_not_equal(self,
|
||||
current_opt: BaseOption,
|
||||
opts: List[BaseOption],
|
||||
vals: List[Any],
|
||||
warnings_only: bool,
|
||||
context) -> None:
|
||||
equal = []
|
||||
is_current = False
|
||||
for idx_inf, val_inf in enumerate(vals):
|
||||
for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]):
|
||||
if val_inf == val_sup is not None:
|
||||
for opt_ in [opts[idx_inf], opts[idx_inf + idx_sup + 1]]:
|
||||
if opt_ == current_opt:
|
||||
is_current = True
|
||||
elif opt_ not in equal:
|
||||
equal.append(opt_)
|
||||
if equal:
|
||||
if is_current:
|
||||
if warnings_only:
|
||||
msg = _('should be different from the value of {}')
|
||||
else:
|
||||
msg = _('must be different from the value of {}')
|
||||
else:
|
||||
if warnings_only:
|
||||
msg = _('value for {} should be different')
|
||||
else:
|
||||
msg = _('value for {} must be different')
|
||||
equal_name = []
|
||||
for opt in equal:
|
||||
equal_name.append(opt.impl_get_display_name())
|
||||
raise ValueError(msg.format(display_list(list(equal_name), add_quote=True)))
|
||||
|
||||
def to_dynoption(self,
|
||||
rootpath: str,
|
||||
suffix: str) -> SynDynOption:
|
||||
|
|
|
@ -25,14 +25,12 @@ from typing import Optional, Iterator, Union, List
|
|||
from ..i18n import _
|
||||
from ..setting import ConfigBag, OptionBag, groups, undefined, owners, Undefined
|
||||
from .baseoption import BaseOption
|
||||
from .option import ALLOWED_CONST_LIST
|
||||
from .syndynoptiondescription import SynDynOptionDescription, SynDynLeadership
|
||||
from ..error import ConfigError, ConflictError
|
||||
|
||||
|
||||
class CacheOptionDescription(BaseOption):
|
||||
__slots__ = ('_cache_consistencies',
|
||||
'_cache_force_store_values')
|
||||
__slots__ = ('_cache_force_store_values',)
|
||||
|
||||
def impl_already_build_caches(self) -> bool:
|
||||
return self.impl_is_readonly()
|
||||
|
@ -101,60 +99,10 @@ class CacheOptionDescription(BaseOption):
|
|||
'"force_metaconfig_on_freeze" '
|
||||
'property without "frozen"'
|
||||
'').format(option.impl_get_display_name()))
|
||||
for cons_id, func, all_cons_opts, params in option.get_consistencies():
|
||||
option._valid_consistencies(all_cons_opts[1:], init=False)
|
||||
if func not in ALLOWED_CONST_LIST and is_multi:
|
||||
if __debug__ and not option.impl_get_leadership():
|
||||
raise ConfigError(_('malformed consistency option "{0}" '
|
||||
'must be in same leadership').format(
|
||||
option.impl_getname()))
|
||||
leadership = option.impl_get_leadership()
|
||||
for weak_opt in all_cons_opts:
|
||||
opt = weak_opt()
|
||||
if __debug__ and func not in ALLOWED_CONST_LIST and is_multi:
|
||||
if not opt.impl_get_leadership():
|
||||
raise ConfigError(_('malformed consistency option "{0}" '
|
||||
'must not be a multi for "{1}"').format(
|
||||
option.impl_getname(), opt.impl_getname()))
|
||||
elif leadership != opt.impl_get_leadership():
|
||||
raise ConfigError(_('malformed consistency option "{0}" '
|
||||
'must be in same leadership as "{1}"').format(
|
||||
option.impl_getname(), opt.impl_getname()))
|
||||
_consistencies.setdefault(weak_opt,
|
||||
[]).append((_consistencies_id,
|
||||
func,
|
||||
all_cons_opts,
|
||||
params))
|
||||
_consistencies_id += 1
|
||||
# if context is set to callback, must be reset each time a value change
|
||||
if hasattr(option, '_has_calc_context'):
|
||||
self._add_dependency(option)
|
||||
|
||||
if __debug__:
|
||||
is_follower = None
|
||||
if is_multi:
|
||||
all_requires = option.impl_getrequires()
|
||||
for requires in all_requires:
|
||||
for require in requires:
|
||||
#if option in require is a multi:
|
||||
# * option in require must be a leader or a follower
|
||||
# * current option must be a follower (and only a follower)
|
||||
# * option in require and current option must be in same leadership
|
||||
for require_opt, values in require[0]:
|
||||
if not isinstance(require_opt, tuple) and require_opt.impl_is_multi():
|
||||
if is_follower is None:
|
||||
is_follower = option.impl_is_follower()
|
||||
if is_follower:
|
||||
leadership = option.impl_get_leadership()
|
||||
if is_follower and require_opt.impl_get_leadership():
|
||||
if leadership != require_opt.impl_get_leadership():
|
||||
raise ValueError(_('malformed requirements option "{0}" '
|
||||
'must be in same leadership for "{1}"').format(
|
||||
require_opt.impl_getname(), option.impl_getname()))
|
||||
else:
|
||||
raise ValueError(_('malformed requirements option "{0}" '
|
||||
'must not be a multi for "{1}"').format(
|
||||
require_opt.impl_getname(), option.impl_getname()))
|
||||
if option.impl_is_readonly():
|
||||
raise ConflictError(_('duplicate option: {0}').format(option))
|
||||
if not self.impl_is_readonly() and display_name:
|
||||
|
@ -162,15 +110,6 @@ class CacheOptionDescription(BaseOption):
|
|||
option._path = subpath
|
||||
option._set_readonly()
|
||||
if init:
|
||||
if _consistencies != {}:
|
||||
self._cache_consistencies = {}
|
||||
for weak_opt, cons in _consistencies.items():
|
||||
opt = weak_opt()
|
||||
if __debug__ and opt not in cache_option:
|
||||
raise ConfigError(_('consistency with option {0} '
|
||||
'which is not in Config').format(
|
||||
opt.impl_getname()))
|
||||
self._cache_consistencies[opt] = tuple(cons)
|
||||
self._cache_force_store_values = force_store_values
|
||||
self._path = self._name
|
||||
self._set_readonly()
|
||||
|
@ -275,7 +214,6 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
name: str,
|
||||
doc: str,
|
||||
children: List[BaseOption],
|
||||
requires=None,
|
||||
properties=None) -> None:
|
||||
"""
|
||||
:param children: a list of options (including optiondescriptions)
|
||||
|
@ -285,7 +223,6 @@ class OptionDescription(OptionDescriptionWalk):
|
|||
'must be a list').format(name)
|
||||
super().__init__(name,
|
||||
doc=doc,
|
||||
requires=requires,
|
||||
properties=properties)
|
||||
child_names = []
|
||||
if __debug__:
|
||||
|
|
|
@ -48,12 +48,8 @@ class PortOption(StrOption):
|
|||
doc,
|
||||
default=None,
|
||||
default_multi=None,
|
||||
requires=None,
|
||||
multi=False,
|
||||
callback=None,
|
||||
callback_params=None,
|
||||
validator=None,
|
||||
validator_params=None,
|
||||
validators=None,
|
||||
properties=None,
|
||||
allow_range=False,
|
||||
allow_zero=False,
|
||||
|
@ -89,12 +85,8 @@ class PortOption(StrOption):
|
|||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
requires=requires,
|
||||
multi=multi,
|
||||
validator=validator,
|
||||
validator_params=validator_params,
|
||||
validators=validators,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
extra=extra)
|
||||
|
|
|
@ -58,6 +58,3 @@ class SymLinkOption(BaseOption):
|
|||
|
||||
def impl_getopt(self) -> BaseOption:
|
||||
return self._opt
|
||||
|
||||
def get_consistencies(self) -> tuple:
|
||||
return ()
|
||||
|
|
|
@ -64,24 +64,11 @@ class SynDynOption:
|
|||
def impl_getpath(self) -> str:
|
||||
return self.rootpath + '.' + self.impl_getname()
|
||||
|
||||
def impl_validate(self,
|
||||
value: Any,
|
||||
option_bag: OptionBag,
|
||||
check_error: bool=True) -> None:
|
||||
soption_bag = OptionBag()
|
||||
soption_bag.set_option(self.opt,
|
||||
self.impl_getpath(),
|
||||
option_bag.index,
|
||||
option_bag.config_bag)
|
||||
soption_bag.ori_option = option_bag.option
|
||||
soption_bag.fromconsistency = option_bag.fromconsistency.copy()
|
||||
self.opt.impl_validate(value,
|
||||
soption_bag,
|
||||
check_error=check_error)
|
||||
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
return True
|
||||
|
||||
def impl_get_leadership(self):
|
||||
return self.opt.impl_get_leadership().to_dynoption(self.rootpath,
|
||||
self.suffix)
|
||||
leadership = self.opt.impl_get_leadership()
|
||||
if leadership:
|
||||
return leadership.to_dynoption(self.rootpath,
|
||||
self.suffix)
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ____________________________________________________________
|
||||
from .error import (RequirementError, PropertiesOptionError,
|
||||
ConstError, ConfigError, display_list)
|
||||
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list
|
||||
from .i18n import _
|
||||
|
||||
|
||||
|
@ -109,7 +108,12 @@ FORBIDDEN_SET_PROPERTIES = frozenset(['force_store_value'])
|
|||
FORBIDDEN_SET_PERMISSIVES = frozenset(['force_default_on_freeze',
|
||||
'force_metaconfig_on_freeze',
|
||||
'force_store_value'])
|
||||
|
||||
ALLOWED_LEADER_PROPERTIES = frozenset(['empty',
|
||||
'force_store_value',
|
||||
'mandatory',
|
||||
'force_default_on_freeze',
|
||||
'force_metaconfig_on_freeze',
|
||||
'frozen'])
|
||||
|
||||
static_set = frozenset()
|
||||
|
||||
|
@ -123,12 +127,10 @@ class OptionBag:
|
|||
'properties', # properties of current option
|
||||
'properties_setted',
|
||||
'apply_requires', # apply requires or not for this option
|
||||
'fromconsistency' # history for consistency
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.option = None
|
||||
self.fromconsistency = []
|
||||
|
||||
def set_option(self,
|
||||
option,
|
||||
|
@ -235,9 +237,6 @@ class ConfigBag:
|
|||
return
|
||||
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
|
||||
|
||||
# def __setattr__(self, key, value):
|
||||
# super().__setattr__(key, value)
|
||||
|
||||
def copy(self):
|
||||
kwargs = {}
|
||||
for key in self.__slots__:
|
||||
|
@ -447,24 +446,19 @@ class Settings(object):
|
|||
if isinstance(prop, str):
|
||||
props.add(prop)
|
||||
elif apply_requires:
|
||||
new_props = prop.execute(option_bag,
|
||||
leadership_must_have_index=True)
|
||||
if not new_props:
|
||||
new_prop = prop.execute(option_bag,
|
||||
leadership_must_have_index=True)
|
||||
if not new_prop:
|
||||
continue
|
||||
elif not isinstance(new_props, str):
|
||||
raise ValueError(_('invalid property type {} for {} with {} function').format(type(new_props),
|
||||
elif not isinstance(new_prop, str):
|
||||
raise ValueError(_('invalid property type {} for {} with {} function').format(type(new_prop),
|
||||
option_bag.option.impl_getname(),
|
||||
prop.function.__name__))
|
||||
props.add(new_props)
|
||||
# else:
|
||||
# props.update(new_props)
|
||||
if apply_requires:
|
||||
props |= self.apply_requires(option_bag,
|
||||
False,
|
||||
search_properties=search_properties)
|
||||
if not option.impl_is_optiondescription() and option.impl_is_leader() and new_prop not in ALLOWED_LEADER_PROPERTIES:
|
||||
raise LeadershipError(_('leader cannot have "{}" property').format(new_prop))
|
||||
props.add(new_prop)
|
||||
props -= self.getpermissives(option,
|
||||
path)
|
||||
#if apply_requires and config_bag.properties == config_bag.true_properties:
|
||||
if apply_requires and not config_bag.is_unrestraint:
|
||||
cache.setcache(path,
|
||||
index,
|
||||
|
@ -508,195 +502,6 @@ class Settings(object):
|
|||
path = opt.impl_getpath()
|
||||
return self._pp_.getpermissives(path)
|
||||
|
||||
def apply_requires(self,
|
||||
option_bag,
|
||||
readable,
|
||||
search_properties=None):
|
||||
"""carries out the jit (just in time) requirements between options
|
||||
|
||||
a requirement is a tuple of this form that comes from the option's
|
||||
requirements validation::
|
||||
|
||||
(option, expected, action, inverse, transitive, same_action)
|
||||
|
||||
let's have a look at all the tuple's items:
|
||||
|
||||
- **option** is the target option's
|
||||
|
||||
- **expected** is the target option's value that is going to trigger
|
||||
an action
|
||||
|
||||
- **action** is the (property) action to be accomplished if the target
|
||||
option happens to have the expected value
|
||||
|
||||
- if **inverse** is `True` and if the target option's value does not
|
||||
apply, then the property action must be removed from the option's
|
||||
properties list (wich means that the property is inverted)
|
||||
|
||||
- **transitive**: but what happens if the target option cannot be
|
||||
accessed ? We don't kown the target option's value. Actually if some
|
||||
property in the target option is not present in the permissive, the
|
||||
target option's value cannot be accessed. In this case, the
|
||||
**action** have to be applied to the option. (the **action** property
|
||||
is then added to the option).
|
||||
|
||||
- **same_action**: actually, if **same_action** is `True`, the
|
||||
transitivity is not accomplished. The transitivity is accomplished
|
||||
only if the target option **has the same property** that the demanded
|
||||
action. If the target option's value is not accessible because of
|
||||
another reason, because of a property of another type, then an
|
||||
exception :exc:`~error.RequirementError` is raised.
|
||||
|
||||
And at last, if no target option matches the expected values, the
|
||||
action will not add to the option's properties list.
|
||||
|
||||
:param opt: the option on wich the requirement occurs
|
||||
:type opt: `option.Option()`
|
||||
:param path: the option's path in the config
|
||||
:type path: str
|
||||
"""
|
||||
current_requires = option_bag.option.impl_getrequires()
|
||||
|
||||
# filters the callbacks
|
||||
if readable:
|
||||
calc_properties = {}
|
||||
else:
|
||||
calc_properties = set()
|
||||
|
||||
if not current_requires:
|
||||
return calc_properties
|
||||
|
||||
context = option_bag.config_bag.context
|
||||
all_properties = None
|
||||
for requires in current_requires:
|
||||
for require in requires:
|
||||
exps, action, inverse, transitive, same_action, operator = require
|
||||
#if search_properties and action not in search_properties:
|
||||
# continue
|
||||
breaked = False
|
||||
for option, expected in exps:
|
||||
if not isinstance(option, tuple):
|
||||
if option.issubdyn():
|
||||
option = option.to_dynoption(option_bag.option.rootpath,
|
||||
option_bag.option.impl_getsuffix())
|
||||
reqpath = option.impl_getpath()
|
||||
if __debug__ and reqpath.startswith(option_bag.path + '.'):
|
||||
# FIXME too later!
|
||||
raise RequirementError(_("malformed requirements "
|
||||
"imbrication detected for option:"
|
||||
" '{0}' with requirement on: "
|
||||
"'{1}'").format(option_bag.path, reqpath))
|
||||
idx = None
|
||||
is_indexed = False
|
||||
if option.impl_is_follower():
|
||||
idx = option_bag.index
|
||||
if idx is None:
|
||||
continue
|
||||
elif option.impl_is_leader() and option_bag.index is None:
|
||||
continue
|
||||
elif option.impl_is_multi() and option_bag.index is not None:
|
||||
is_indexed = True
|
||||
config_bag = option_bag.config_bag.copy()
|
||||
soption_bag = OptionBag()
|
||||
soption_bag.set_option(option,
|
||||
reqpath,
|
||||
idx,
|
||||
config_bag)
|
||||
if option_bag.option == option:
|
||||
soption_bag.config_bag.unrestraint()
|
||||
soption_bag.config_bag.remove_validation()
|
||||
soption_bag.apply_requires = False
|
||||
else:
|
||||
soption_bag.config_bag.properties = soption_bag.config_bag.true_properties
|
||||
soption_bag.config_bag.set_permissive()
|
||||
else:
|
||||
if not option_bag.option.impl_is_optiondescription() and option_bag.option.impl_is_follower():
|
||||
idx = option_bag.index
|
||||
if idx is None:
|
||||
continue
|
||||
is_indexed = False
|
||||
try:
|
||||
if not isinstance(option, tuple):
|
||||
value = context.getattr(reqpath,
|
||||
soption_bag)
|
||||
else:
|
||||
value = context.cfgimpl_get_values().carry_out_calculation(option_bag,
|
||||
option[0],
|
||||
option[1])
|
||||
except (PropertiesOptionError, ConfigError) as err:
|
||||
if isinstance(err, ConfigError):
|
||||
if not isinstance(err.ori_err, PropertiesOptionError):
|
||||
raise err
|
||||
err = err.ori_err
|
||||
properties = err.proptype
|
||||
# if not transitive, properties must be verify in current requires
|
||||
# otherwise if same_action, property must be in properties
|
||||
# otherwise add property in returned properties (if operator is 'and')
|
||||
if not transitive:
|
||||
if all_properties is None:
|
||||
all_properties = []
|
||||
for requires_ in current_requires:
|
||||
for require_ in requires_:
|
||||
all_properties.append(require_[1])
|
||||
if not set(properties) - set(all_properties):
|
||||
continue
|
||||
if same_action and action not in properties:
|
||||
if len(properties) == 1:
|
||||
prop_msg = _('property')
|
||||
else:
|
||||
prop_msg = _('properties')
|
||||
err = RequirementError(_('cannot access to option "{0}" because '
|
||||
'required option "{1}" has {2} {3}'
|
||||
'').format(option_bag.option.impl_get_display_name(),
|
||||
option.impl_get_display_name(),
|
||||
prop_msg,
|
||||
display_list(list(properties), add_quote=True)))
|
||||
err.proptype = properties
|
||||
raise err
|
||||
# transitive action, add action
|
||||
if operator != 'and':
|
||||
if readable:
|
||||
for msg in self.apply_requires(err._option_bag,
|
||||
True).values():
|
||||
calc_properties.setdefault(action, []).extend(msg)
|
||||
else:
|
||||
calc_properties.add(action)
|
||||
breaked = True
|
||||
break
|
||||
else:
|
||||
if is_indexed:
|
||||
value = value[option_bag.index]
|
||||
if (not inverse and value in expected or
|
||||
inverse and value not in expected):
|
||||
if operator != 'and':
|
||||
if readable:
|
||||
display_value = display_list(expected, 'or', add_quote=True)
|
||||
if isinstance(option, tuple):
|
||||
if not inverse:
|
||||
msg = _('the calculated value is {0}').format(display_value)
|
||||
else:
|
||||
msg = _('the calculated value is not {0}').format(display_value)
|
||||
else:
|
||||
name = option.impl_get_display_name()
|
||||
if not inverse:
|
||||
msg = _('the value of "{0}" is {1}').format(name, display_value)
|
||||
else:
|
||||
msg = _('the value of "{0}" is not {1}').format(name, display_value)
|
||||
calc_properties.setdefault(action, []).append(msg)
|
||||
else:
|
||||
calc_properties.add(action)
|
||||
breaked = True
|
||||
break
|
||||
elif operator == 'and':
|
||||
break
|
||||
else:
|
||||
if operator == 'and':
|
||||
calc_properties.add(action)
|
||||
continue
|
||||
if breaked:
|
||||
break
|
||||
return calc_properties
|
||||
|
||||
#____________________________________________________________
|
||||
# set methods
|
||||
def set_context_properties(self,
|
||||
|
@ -715,23 +520,21 @@ class Settings(object):
|
|||
(never save properties if same has option properties)
|
||||
"""
|
||||
opt = option_bag.option
|
||||
if opt.impl_getrequires() is not None:
|
||||
not_allowed_props = properties & \
|
||||
getattr(opt, '_calc_properties', static_set)
|
||||
if not_allowed_props:
|
||||
raise ValueError(_('cannot set property {} for option "{}" this property is '
|
||||
'calculated').format(display_list(list(not_allowed_props),
|
||||
add_quote=True),
|
||||
opt.impl_get_display_name()))
|
||||
if opt.impl_is_symlinkoption():
|
||||
raise TypeError(_("can't assign property to the symlinkoption \"{}\""
|
||||
"").format(opt.impl_get_display_name()))
|
||||
if ('force_default_on_freeze' in properties or 'force_metaconfig_on_freeze' in properties) and \
|
||||
'frozen' not in properties and \
|
||||
opt.impl_is_leader():
|
||||
raise ConfigError(_('a leader ({0}) cannot have '
|
||||
'"force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
|
||||
'').format(opt.impl_get_display_name()))
|
||||
if not opt.impl_is_optiondescription() and opt.impl_is_leader():
|
||||
not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES
|
||||
if not_allowed_properties:
|
||||
if len(not_allowed_properties) == 1:
|
||||
raise LeadershipError(_('leader cannot have "{}" property').format(list(not_allowed_properties)[0]))
|
||||
else:
|
||||
raise LeadershipError(_('leader cannot have {} properties').format(display_list(list(not_allowed_properties), add_quote=True)))
|
||||
if ('force_default_on_freeze' in properties or 'force_metaconfig_on_freeze' in properties) and \
|
||||
'frozen' not in properties:
|
||||
raise LeadershipError(_('a leader ({0}) cannot have '
|
||||
'"force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
|
||||
'').format(opt.impl_get_display_name()))
|
||||
self._p_.setproperties(path,
|
||||
properties)
|
||||
# values too because of follower values could have a PropertiesOptionError has value
|
||||
|
|
|
@ -67,7 +67,7 @@ class Callbacks(object):
|
|||
raise ValueError(_('context is not supported from now for {}').format(path))
|
||||
if isinstance(callback_param, ParamOption):
|
||||
has_option = True
|
||||
if callback.__name__ != 'tiramisu_copy' or 'expire' in childapi.option.properties():
|
||||
if 'expire' in childapi.option.properties():
|
||||
self.tiramisu_web.set_remotable(callback_param.option.impl_getpath(), form)
|
||||
if not has_option and form.get(path, {}).get('remote', False) == False:
|
||||
if 'expire' in childapi.option.properties():
|
||||
|
@ -79,14 +79,15 @@ class Callbacks(object):
|
|||
form.setdefault(path, {})['clearable'] = True
|
||||
|
||||
def manage_callbacks(self, form):
|
||||
for callback, callback_params, path, childapi, schema, force_store_value in self.callbacks:
|
||||
if callback_params is not None:
|
||||
for callback_param in chain(callback_params.args, callback_params.kwargs.values()):
|
||||
if isinstance(callback_param, ParamOption) and callback.__name__ == 'tiramisu_copy':
|
||||
opt_path = callback_param.option.impl_getpath()
|
||||
if form.get(opt_path, {}).get('remote') is not True:
|
||||
form.setdefault(opt_path, {})
|
||||
form[opt_path].setdefault('copy', []).append(path)
|
||||
pass
|
||||
#for callback, callback_params, path, childapi, schema, force_store_value in self.callbacks:
|
||||
# if callback_params is not None:
|
||||
# for callback_param in chain(callback_params.args, callback_params.kwargs.values()):
|
||||
# if isinstance(callback_param, ParamOption) and callback.__name__ == 'tiramisu_copy':
|
||||
# opt_path = callback_param.option.impl_getpath()
|
||||
# if form.get(opt_path, {}).get('remote') is not True:
|
||||
# form.setdefault(opt_path, {})
|
||||
# form[opt_path].setdefault('copy', []).append(path)
|
||||
|
||||
def process(self,
|
||||
form):
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# ____________________________________________________________
|
||||
import weakref
|
||||
from typing import Optional, Any, Callable
|
||||
from .error import ConfigError, PropertiesOptionError, RequirementError
|
||||
from .error import ConfigError, PropertiesOptionError
|
||||
from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag
|
||||
from .autolib import Calculation, carry_out_calculation, Params
|
||||
from .i18n import _
|
||||
|
@ -78,7 +78,7 @@ class Values(object):
|
|||
# store value in cache
|
||||
properties = option_bag.config_bag.properties
|
||||
validator = 'validator' in properties and 'demoting_error_warning' not in properties
|
||||
if not option_bag.fromconsistency and (not is_cached or validator):
|
||||
if not is_cached or validator:
|
||||
cache.setcache(option_bag.path,
|
||||
option_bag.index,
|
||||
value,
|
||||
|
@ -258,8 +258,7 @@ class Values(object):
|
|||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
index=option_bag.index,
|
||||
config_bag=option_bag.config_bag,
|
||||
fromconsistency=option_bag.fromconsistency)
|
||||
config_bag=option_bag.config_bag)
|
||||
def isempty(self,
|
||||
opt,
|
||||
value,
|
||||
|
@ -289,24 +288,8 @@ class Values(object):
|
|||
context = option_bag.config_bag.context
|
||||
owner = self.get_context_owner()
|
||||
if 'validator' in option_bag.config_bag.properties:
|
||||
if option_bag.index is not None or option_bag.option.has_consistencies(context):
|
||||
# set value to a fake config when option has dependency
|
||||
# validation will be complet in this case (consistency, ...)
|
||||
tested_context = context._gen_fake_values()
|
||||
config_bag = option_bag.config_bag.copy()
|
||||
config_bag.unrestraint()
|
||||
config_bag.context = tested_context
|
||||
soption_bag = option_bag.copy()
|
||||
soption_bag.config_bag = config_bag
|
||||
tested_context.cfgimpl_get_values().setvalue(value,
|
||||
soption_bag,
|
||||
True)
|
||||
soption_bag.config_bag.properties = option_bag.config_bag.properties
|
||||
tested_context.getattr(soption_bag.path,
|
||||
soption_bag)
|
||||
else:
|
||||
self.setvalue_validation(value,
|
||||
option_bag)
|
||||
self.setvalue_validation(value,
|
||||
option_bag)
|
||||
|
||||
self._setvalue(option_bag,
|
||||
value,
|
||||
|
@ -622,7 +605,7 @@ class Values(object):
|
|||
except PropertiesOptionError as err:
|
||||
if err.proptype == ['mandatory']:
|
||||
yield path
|
||||
except (RequirementError, ConfigError):
|
||||
except ConfigError:
|
||||
pass
|
||||
|
||||
def mandatory_warnings(self,
|
||||
|
|
Loading…
Reference in a new issue