This commit is contained in:
egarette@silique.fr 2024-06-20 12:56:27 +02:00
parent 8e743131cd
commit 897d4dd216
36 changed files with 4299 additions and 5314 deletions

File diff suppressed because it is too large Load diff

View file

@ -81,10 +81,10 @@ def test_cache_importation_property():
def test_cache_importation_permissive(): def test_cache_importation_permissive():
od1 = make_description() od1 = make_description()
cfg = Config(od1) cfg = Config(od1)
cfg.option('u2').permissive.set(frozenset(['prop'])) cfg.option('u2').permissive.add('prop')
export = cfg.permissive.exportation() export = cfg.permissive.exportation()
assert cfg.option('u2').permissive.get() == {'prop'} assert cfg.option('u2').permissive.get() == {'prop'}
cfg.option('u2').permissive.set(frozenset(['prop', 'prop2'])) cfg.option('u2').permissive.add('prop2')
assert cfg.option('u2').permissive.get() == {'prop', 'prop2'} assert cfg.option('u2').permissive.get() == {'prop', 'prop2'}
cfg.permissive.importation(export) cfg.permissive.importation(export)
assert cfg.option('u2').permissive.get() == {'prop'} assert cfg.option('u2').permissive.get() == {'prop'}
@ -266,7 +266,7 @@ def test_cache_leadership():
#assert cache['ip_admin_eth0.netmask_admin_eth0'][None][0] == [None] #assert cache['ip_admin_eth0.netmask_admin_eth0'][None][0] == [None]
#assert cache['ip_admin_eth0.netmask_admin_eth0'][0][0] is None #assert cache['ip_admin_eth0.netmask_admin_eth0'][0][0] is None
cache = settings.get_cached() cache = settings.get_cached()
assert set(cache.keys()) == set([None, 'ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0']) assert set(cache.keys()) == set(['ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
assert set(cache['ip_admin_eth0'].keys()) == set([None]) assert set(cache['ip_admin_eth0'].keys()) == set([None])
assert set(cache['ip_admin_eth0.ip_admin_eth0'].keys()) == set([None]) assert set(cache['ip_admin_eth0.ip_admin_eth0'].keys()) == set([None])
assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == {0} assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == {0}
@ -284,7 +284,7 @@ def test_cache_leadership():
#assert cache['ip_admin_eth0.netmask_admin_eth0'][0][0] is None #assert cache['ip_admin_eth0.netmask_admin_eth0'][0][0] is None
#assert cache['ip_admin_eth0.netmask_admin_eth0'][1][0] is None #assert cache['ip_admin_eth0.netmask_admin_eth0'][1][0] is None
cache = settings.get_cached() cache = settings.get_cached()
assert set(cache.keys()) == set([None, 'ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0']) assert set(cache.keys()) == set(['ip_admin_eth0', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
assert set(cache['ip_admin_eth0'].keys()) == set([None]) assert set(cache['ip_admin_eth0'].keys()) == set([None])
assert set(cache['ip_admin_eth0.ip_admin_eth0'].keys()) == set([None]) assert set(cache['ip_admin_eth0.ip_admin_eth0'].keys()) == set([None])
assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == set([0, 1]) assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == set([0, 1])
@ -376,26 +376,22 @@ def test_cache_leader_and_followers():
idx_val2 = None idx_val2 = None
values = cfg._config_bag.context._impl_values_cache values = cfg._config_bag.context._impl_values_cache
settings = cfg._config_bag.context.properties_cache settings = cfg._config_bag.context.properties_cache
compare(settings.get_cached(), {None: {None: (global_props, None)}, compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
'val1': {None: (val1_props, None)}, 'val1.val1': {None: (val1_val1_props, None)},
'val1.val1': {None: (val1_val1_props, None)}, })
})
# len is 0 so don't get any value # len is 0 so don't get any value
compare(values.get_cached(), {'val1.val1': {None: ([], None)}}) compare(values.get_cached(), {'val1.val1': {None: ([], None)}})
# #
cfg.option('val1.val1').value.set([None]) cfg.option('val1.val1').value.set([None])
val_val2_props = {idx_val2: (val1_val2_props, None), None: (set(), None)} val_val2_props = {idx_val2: (val1_val2_props, None), None: (set(), None)}
compare(settings.get_cached(), {None: {None: (set(global_props), None)}, compare(settings.get_cached(), {'val1.val1': {None: ({'empty', 'unique'}, None, True)}})
# 'val1.val1': {None: (val1_val1_props, None)},
})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}}) compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.get() cfg.value.get()
#has value #has value
idx_val2 = 0 idx_val2 = 0
val_val2 = None val_val2 = None
val_val2_props = {idx_val2: (val1_val2_props, None)} val_val2_props = {idx_val2: (val1_val2_props, None)}
compare(settings.get_cached(), {None: {None: (global_props, None)}, compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
'val1': {None: (val1_props, None)},
'val1.val1': {None: (val1_val1_props, None)}, 'val1.val1': {None: (val1_val1_props, None)},
'val1.val2': val_val2_props}) 'val1.val2': val_val2_props})
compare(values.get_cached(), {'val1.val1': {None: ([None], None)}, compare(values.get_cached(), {'val1.val1': {None: ([None], None)},
@ -404,7 +400,7 @@ def test_cache_leader_and_followers():
cfg.option('val1.val1').value.set([None, None]) cfg.option('val1.val1').value.set([None, None])
cfg.value.get() cfg.value.get()
cfg.option('val1.val2', 1).value.set('oui') cfg.option('val1.val2', 1).value.set('oui')
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}}) compare(settings.get_cached(), {})
compare(values.get_cached(), {'val1.val2': {1: ('oui', None, True)}}) compare(values.get_cached(), {'val1.val2': {1: ('oui', None, True)}})
val1_val2_props = {0: (frozenset([]), None), 1: (frozenset([]), None)} val1_val2_props = {0: (frozenset([]), None), 1: (frozenset([]), None)}
# assert not list_sessions() # assert not list_sessions()
@ -428,15 +424,12 @@ def test_cache_leader_callback():
val1_val2_props = frozenset(val1_val2_props) val1_val2_props = frozenset(val1_val2_props)
values = cfg._config_bag.context._impl_values_cache values = cfg._config_bag.context._impl_values_cache
settings = cfg._config_bag.context.properties_cache settings = cfg._config_bag.context.properties_cache
compare(settings.get_cached(), {None: {None: (global_props, None)}, compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
'val1': {None: (val1_props, None)},
'val1.val1': {None: (val1_val1_props, None)}, 'val1.val1': {None: (val1_val1_props, None)},
}) })
compare(values.get_cached(), {'val1.val1': {None: ([], None)}}) compare(values.get_cached(), {'val1.val1': {None: ([], None)}})
cfg.option('val1.val1').value.set([None]) cfg.option('val1.val1').value.set([None])
compare(settings.get_cached(), {None: {None: (set(global_props), None)}, compare(settings.get_cached(), {'val1.val1': {None: ({'unique', 'empty'}, None, True)}})
# 'val1.val1': {None: (val1_val1_props, None)},
})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}}) compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.get() cfg.value.get()
@ -458,39 +451,34 @@ def test_cache_requires():
settings = cfg._config_bag.context.properties_cache settings = cfg._config_bag.context.properties_cache
assert values.get_cached() == {} assert values.get_cached() == {}
assert cfg.option('ip_address_service').value.get() == None assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'activate_service': {None: (set([]), None)}, 'ip_address_service': {None: (set([]), None)}})
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)}, compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}}) 'activate_service': {None: (True, None)}})
cfg.value.get() cfg.value.get()
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'activate_service': {None: (set([]), None)}, 'ip_address_service': {None: (set([]), None)}})
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)}, compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}}) 'activate_service': {None: (True, None)}})
cfg.option('ip_address_service').value.set('1.1.1.1') cfg.option('ip_address_service').value.set('1.1.1.1')
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)}})
'activate_service': {None: (set([]), None)}})
compare(values.get_cached(), {'activate_service': {None: (True, None)}, 'ip_address_service': {None: ('1.1.1.1', None, True)}}) compare(values.get_cached(), {'activate_service': {None: (True, None)}, 'ip_address_service': {None: ('1.1.1.1', None, True)}})
cfg.value.get() cfg.value.get()
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'activate_service': {None: (set([]), None)}, 'ip_address_service': {None: (set([]), None)}})
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: ('1.1.1.1', None)}, compare(values.get_cached(), {'ip_address_service': {None: ('1.1.1.1', None)},
'activate_service': {None: (True, None)}}) 'activate_service': {None: (True, None)}})
cfg.option('activate_service').value.set(False) cfg.option('activate_service').value.set(False)
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}}) compare(settings.get_cached(), {})
compare(values.get_cached(), {'activate_service': {None: (False, None)}}) compare(values.get_cached(), {'activate_service': {None: (False, None)}})
cfg.value.get() cfg.value.get()
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'activate_service': {None: (set([]), None)}, 'ip_address_service': {None: (set(['disabled']), None)}})
'ip_address_service': {None: (set(['disabled']), None)}})
compare(values.get_cached(), {'activate_service': {None: (False, None)}}) compare(values.get_cached(), {'activate_service': {None: (False, None)}})
# assert not list_sessions() # assert not list_sessions()
@ -511,22 +499,19 @@ def test_cache_global_properties():
settings = cfg._config_bag.context.properties_cache settings = cfg._config_bag.context.properties_cache
assert values.get_cached() == {} assert values.get_cached() == {}
assert cfg.option('ip_address_service').value.get() == None assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'activate_service': {None: (set([]), None)}, 'ip_address_service': {None: (set([]), None)}})
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)}, compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}}) 'activate_service': {None: (True, None)}})
cfg.property.remove('disabled') cfg.property.remove('disabled')
assert cfg.option('ip_address_service').value.get() == None assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {None: {None: (set(['cache', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'activate_service': {None: (set([]), None)}, 'ip_address_service': {None: (set([]), None)}})
'ip_address_service': {None: (set([]), None)}})
cfg.property.add('test') cfg.property.add('test')
assert cfg.option('ip_address_service').value.get() == None assert cfg.option('ip_address_service').value.get() == None
compare(settings.get_cached(), {None: {None: (set(['cache', 'frozen', 'hidden', 'validator', 'warnings', 'test', 'force_store_value']), None)}, compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'activate_service': {None: (set([]), None)}, 'ip_address_service': {None: (set([]), None)}})
'ip_address_service': {None: (set([]), None)}})
# assert not list_sessions() # assert not list_sessions()

View file

@ -1,10 +1,9 @@
# coding: utf-8 # coding: utf-8
from py.test import raises
from .autopath import do_autopath from .autopath import do_autopath
do_autopath() do_autopath()
from .config import config_type, get_config, value_list, global_owner from .config import config_type, get_config, value_list, global_owner, parse_od_get
from pytest import raises
from tiramisu import ChoiceOption, StrOption, OptionDescription, Config, owners, Calculation, \ from tiramisu import ChoiceOption, StrOption, OptionDescription, Config, owners, Calculation, \
undefined, Params, ParamValue, ParamOption undefined, Params, ParamValue, ParamOption
from tiramisu.error import ConfigError from tiramisu.error import ConfigError
@ -76,6 +75,29 @@ def test_choiceoption_function(config_type):
# assert not list_sessions() # assert not list_sessions()
def test_choiceoption_subfunction(config_type):
choice = ChoiceOption('choice', '', values=(Calculation(return_val, Params(ParamValue('val1'))), Calculation(return_val, Params(ParamValue('val2')))))
od1 = OptionDescription('od', '', [choice])
cfg = Config(od1)
cfg.property.read_write()
cfg = get_config(cfg, config_type)
owner = global_owner(cfg, config_type)
assert cfg.option('choice').owner.isdefault()
#
cfg.option('choice').value.set('val1')
assert cfg.option('choice').owner.get() == owner
#
cfg.option('choice').value.reset()
assert cfg.option('choice').owner.isdefault()
#
with raises(ValueError):
cfg.option('choice').value.set('no')
assert cfg.option('choice').owner.isdefault()
#
assert value_list(cfg.option('choice').value.list()) == ('val1', 'val2')
# assert not list_sessions()
def test_choiceoption_function_error(): def test_choiceoption_function_error():
choice = ChoiceOption('choice', '', values=Calculation(return_error)) choice = ChoiceOption('choice', '', values=Calculation(return_error))
od1 = OptionDescription('od', '', [choice]) od1 = OptionDescription('od', '', [choice])
@ -262,3 +284,13 @@ def test_choiceoption_calc_not_list():
with raises(ConfigError): with raises(ConfigError):
cfg.option('choice').value.set(['val1']) cfg.option('choice').value.set(['val1'])
# assert not list_sessions() # assert not list_sessions()
def test_choiceoption_calc_default_value():
var1 = StrOption("var1", '', default="val1")
var2 = StrOption("var2", '', default="val2")
choice = ChoiceOption("choice", '', values=(Calculation(return_val, Params((ParamOption(var1)))), Calculation(return_val, Params((ParamOption(var2))))), default="val1")
od2 = OptionDescription("rougail", '', children=[var1, var2, choice])
od1 = OptionDescription("baseoption", "", children=[od2])
cfg = Config(od1)
assert parse_od_get(cfg.value.get()) == {'rougail.var1': 'val1', 'rougail.var2': 'val2', 'rougail.choice': 'val1'}

View file

@ -26,8 +26,7 @@ def make_description():
floatoption = FloatOption('float', 'Test float option', default=2.3) floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc", properties=('mandatory', )) stroption = StrOption('str', 'Test string option', default="abc", properties=('mandatory', ))
boolop = BoolOption('boolop', 'Test boolean option op', default=True, properties=('hidden',)) boolop = BoolOption('boolop', 'Test boolean option op', default=True, properties=('hidden',))
wantref_option = BoolOption('wantref', 'Test requires', default=False) wantref_option = BoolOption('wantref', 'Test requires', default=False, informations={'info': 'default value'})
wantref_option.impl_set_information('info', 'default value')
wantframework_option = BoolOption('wantframework', 'Test requires', wantframework_option = BoolOption('wantframework', 'Test requires',
default=False) default=False)
@ -143,11 +142,11 @@ def test_information_config():
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.information.get('noinfo') cfg.information.get('noinfo')
assert cfg.information.get('noinfo', 'default') == 'default' assert cfg.information.get('noinfo', 'default') == 'default'
cfg.information.reset('info') cfg.information.remove('info')
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.information.get('info') cfg.information.remove('info')
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.information.reset('noinfo') cfg.information.remove('noinfo')
assert list(cfg.information.list()) == ['doc'] assert list(cfg.information.list()) == ['doc']
# assert not list_sessions() # assert not list_sessions()
@ -194,26 +193,23 @@ def test_information_option():
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.option('gc.name').information.get('noinfo') cfg.option('gc.name').information.get('noinfo')
assert cfg.option('gc.name').information.get('noinfo', 'default') == 'default' assert cfg.option('gc.name').information.get('noinfo', 'default') == 'default'
cfg.option('gc.name').information.reset('info') cfg.option('gc.name').information.remove('info')
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.option('gc.name').information.get('info') cfg.option('gc.name').information.get('info')
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.option('gc.name').information.reset('noinfo') cfg.option('gc.name').information.remove('noinfo')
assert list(cfg.option('gc.name').information.list()) == ['doc'] assert list(cfg.option('gc.name').information.list()) == ['doc']
# #
assert cfg.option('wantref').information.get('info') == 'default value' assert cfg.option('wantref').information.get('info') == 'default value'
cfg.option('wantref').information.set('info', 'default value') cfg.option('wantref').information.set('info', 'default value')
assert cfg.option('wantref').information.get('info') == 'default value' assert cfg.option('wantref').information.get('info') == 'default value'
cfg.option('wantref').information.reset('info') cfg.option('wantref').information.remove('info')
assert cfg.option('wantref').information.get('info') == 'default value' assert cfg.option('wantref').information.get('info') == 'default value'
# assert not list_sessions() # assert not list_sessions()
def test_information_option_2(): def test_information_option_2():
i1 = IntOption('test1', '') i1 = IntOption('test1', '', informations={'info': 'value'})
i1.impl_set_information('info', 'value')
# it's a dict
assert set(i1.impl_list_information()) == {'info', 'doc'}
od1 = OptionDescription('test', '', [i1]) od1 = OptionDescription('test', '', [i1])
cfg = Config(od1) cfg = Config(od1)
# it's tuples # it's tuples
@ -234,11 +230,11 @@ def test_information_optiondescription():
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.option('gc').information.get('noinfo') cfg.option('gc').information.get('noinfo')
assert cfg.option('gc').information.get('noinfo', 'default') == 'default' assert cfg.option('gc').information.get('noinfo', 'default') == 'default'
cfg.option('gc').information.reset('info') cfg.option('gc').information.remove('info')
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.option('gc').information.get('info') cfg.option('gc').information.get('info')
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.option('gc').information.reset('noinfo') cfg.option('gc').information.remove('noinfo')
assert list(cfg.option('gc').information.list()) == ['doc'] assert list(cfg.option('gc').information.list()) == ['doc']
# assert not list_sessions() # assert not list_sessions()

View file

@ -412,7 +412,6 @@ def test_help():
cfg = Config(od2) cfg = Config(od2)
cfg.help(_display=False) cfg.help(_display=False)
cfg.config.help(_display=False) cfg.config.help(_display=False)
cfg.option.help(_display=False)
cfg.option('o').help(_display=False) cfg.option('o').help(_display=False)
cfg.option('o.s').help(_display=False) cfg.option('o.s').help(_display=False)
# assert not list_sessions() # assert not list_sessions()
@ -430,7 +429,7 @@ def test_config_reset():
# #
cfg.option('gc.gc2.bool').value.set(True) cfg.option('gc.gc2.bool').value.set(True)
cfg.option('boolop').property.add('test') cfg.option('boolop').property.add('test')
cfg.option('float').permissive.set(frozenset(['test'])) cfg.option('float').permissive.add('test')
cfg.option('wantref').information.set('info', 'info') cfg.option('wantref').information.set('info', 'info')
assert cfg.option('gc.gc2.bool').value.get() assert cfg.option('gc.gc2.bool').value.get()
assert cfg.option('boolop').property.get() assert cfg.option('boolop').property.get()

View file

@ -59,27 +59,27 @@ def test_copy_information():
ncfg = cfg.config.copy() ncfg = cfg.config.copy()
assert ncfg.information.get('key') == 'value' assert ncfg.information.get('key') == 'value'
# assert not list_sessions() # assert not list_sessions()
#
#
#def test_copy_force_store_value(): def test_copy_force_store_value():
# od1 = make_description() od1 = make_description()
# conf = Config(od1) conf = Config(od1)
# conf2 = Config(od1) conf2 = Config(od1)
# assert conf.value.exportation() == {} assert conf.value.exportation() == {}
# assert conf2.value.exportation() == {} assert conf2.value.exportation() == {}
# # #
# conf.property.read_write() conf.property.read_write()
# assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}} assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
# assert conf2.value.exportation() == {} assert conf2.value.exportation() == {}
# # #
# conf2.property.read_only() conf2.property.read_only()
# assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}} assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
# assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}} assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
# # #
# conf.option('creole.general.wantref').value.set(True) conf.option('creole.general.wantref').value.set(True)
# assert conf.value.exportation() == {'creole.general.wantref': {None: [True, 'user']}} assert conf.value.exportation() == {'creole.general.wantref': {None: [True, 'user']}}
# assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}} assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
## assert not list_sessions() # assert not list_sessions()
# #
# #
#def test_copy_force_store_value_metaconfig(): #def test_copy_force_store_value_metaconfig():

File diff suppressed because it is too large Load diff

View file

@ -160,57 +160,57 @@ def test_freeze_multi():
# assert not list_sessions() # assert not list_sessions()
#def test_force_store_value(): def test_force_store_value():
# od1 = make_description_freeze() od1 = make_description_freeze()
# cfg = Config(od1) cfg = Config(od1)
# compare(cfg.value.exportation(), {}) compare(cfg.value.exportation(), {})
# cfg.property.read_write() cfg.property.read_write()
# compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}}) compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
# cfg.option('bool').value.set(False) cfg.option('bool').value.set(False)
# cfg.option('wantref').value.set(True) cfg.option('wantref').value.set(True)
# cfg.option('bool').value.reset() cfg.option('bool').value.reset()
# compare(cfg.value.exportation(), {'wantref': {None: [True, 'user']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}}) compare(cfg.value.exportation(), {'wantref': {None: [True, 'user']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
# cfg.option('bool').value.set(False) cfg.option('bool').value.set(False)
# cfg.option('wantref').value.reset() cfg.option('wantref').value.reset()
# cfg.option('bool').value.reset() cfg.option('bool').value.reset()
# compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}}) compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_force_store_value_leadership_sub(): def test_force_store_value_leadership_sub():
# b = IntOption('int', 'Test int option', multi=True, properties=('force_store_value',)) b = IntOption('int', 'Test int option', multi=True, properties=('force_store_value',))
# c = StrOption('str', 'Test string option', multi=True) c = StrOption('str', 'Test string option', multi=True)
# descr = Leadership("int", "", [b, c]) descr = Leadership("int", "", [b, c])
# od1 = OptionDescription('odr', '', [descr]) od1 = OptionDescription('odr', '', [descr])
# cfg = Config(od1) cfg = Config(od1)
# cfg.property.read_only() cfg.property.read_only()
# compare(cfg.value.exportation(), {'int.int': {None: [[], 'forced']}}) compare(cfg.value.exportation(), {'int.int': {None: [[], 'forced']}})
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_force_store_value_callback(): def test_force_store_value_callback():
# b = IntOption('int', 'Test int option', Calculation(return_val), properties=('force_store_value',)) b = IntOption('int', 'Test int option', Calculation(return_val), properties=('force_store_value',))
# od1 = OptionDescription("int", "", [b]) od1 = OptionDescription("int", "", [b])
# cfg = Config(od1) cfg = Config(od1)
# cfg.property.read_only() cfg.property.read_only()
# compare(cfg.value.exportation(), {'int': {None: [1, 'forced']}}) compare(cfg.value.exportation(), {'int': {None: [1, 'forced']}})
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_force_store_value_callback_params(): def test_force_store_value_callback_params():
# b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamValue(2)})), properties=('force_store_value',)) b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamValue(2)})), properties=('force_store_value',))
# od1 = OptionDescription("int", "", [b]) od1 = OptionDescription("int", "", [b])
# cfg = Config(od1) cfg = Config(od1)
# cfg.property.read_only() cfg.property.read_only()
# compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}}) compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_force_store_value_callback_params_with_opt(): def test_force_store_value_callback_params_with_opt():
# a = IntOption('val1', "", 2) a = IntOption('val1', "", 2)
# b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamOption(a)})), properties=('force_store_value',)) b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamOption(a)})), properties=('force_store_value',))
# od1 = OptionDescription("int", "", [a, b]) od1 = OptionDescription("int", "", [a, b])
# cfg = Config(od1) cfg = Config(od1)
# cfg.property.read_only() cfg.property.read_only()
# compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}}) compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
## assert not list_sessions() # assert not list_sessions()

View file

@ -159,7 +159,7 @@ def test_iter_on_empty_group():
od1 = OptionDescription("name", "descr", []) od1 = OptionDescription("name", "descr", [])
cfg = Config(od1) cfg = Config(od1)
cfg.property.read_write() cfg.property.read_write()
result = list(cfg.option.list()) result = list(cfg.list())
assert result == [] assert result == []
# assert not list_sessions() # assert not list_sessions()
@ -207,7 +207,7 @@ def test_leader_list(config_type):
od1 = OptionDescription('od', '', [interface1]) od1 = OptionDescription('od', '', [interface1])
cfg = Config(od1) cfg = Config(od1)
cfg = get_config(cfg, config_type) cfg = get_config(cfg, config_type)
ret = cfg.option.list() ret = cfg.list()
assert len(ret) == 1 assert len(ret) == 1
assert ret[0].name() == 'leadership' assert ret[0].name() == 'leadership'
# #
@ -983,65 +983,65 @@ def test_follower_not_multi():
# assert not list_sessions() # assert not list_sessions()
#def test_follower_force_store_value_none(): def test_follower_force_store_value_none():
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1']) 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, properties=('force_store_value',)) netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('force_store_value',))
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0]) interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
# od1 = OptionDescription('od', '', [interface0]) od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1]) od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2) cfg = Config(od2)
# cfg.property.read_write() cfg.property.read_write()
# assert cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault() assert cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_follower_force_store_value(): def test_follower_force_store_value():
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1']) 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", default_multi='255.255.255.0', multi=True, properties=('force_store_value',)) netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0]) interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
# od1 = OptionDescription('od', '', [interface0]) od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1]) od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2) cfg = Config(od2)
# cfg.property.read_write() cfg.property.read_write()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault() assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_follower_force_store_value_read_only(): def test_follower_force_store_value_read_only():
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1']) 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", default_multi='255.255.255.0', multi=True, properties=('force_store_value',)) netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0]) interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
# od1 = OptionDescription('od', '', [interface0]) od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1]) od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2) cfg = Config(od2)
# cfg.property.read_only() cfg.property.read_only()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault() assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_follower_force_store_value_reset(): def test_follower_force_store_value_reset():
# ip_admin_eth0 = IPOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['1.1.1.1']) 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", default_multi='255.255.255.0', multi=True, properties=('force_store_value',)) netmask_admin_eth0 = NetmaskOption('netmask_admin_eth0', "masque du sous-réseau", default_multi='255.255.255.0', multi=True, properties=('force_store_value',))
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0]) interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
# od1 = OptionDescription('od', '', [interface0]) od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1]) od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2) cfg = Config(od2)
# cfg.property.read_write() cfg.property.read_write()
# cfg.option('od.interface0.ip_admin_eth0').value.set(['1.1.1.1', '192.168.0.0']) cfg.option('od.interface0.ip_admin_eth0').value.set(['1.1.1.1', '192.168.0.0'])
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault() assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault() assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault()
# # #
# cfg.option('od.interface0.netmask_admin_eth0', 1).value.reset() cfg.option('od.interface0.netmask_admin_eth0', 1).value.reset()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault() assert not cfg.option('od.interface0.netmask_admin_eth0', 1).owner.isdefault()
# # #
# cfg.option('od.interface0.ip_admin_eth0').value.pop(0) cfg.option('od.interface0.ip_admin_eth0').value.pop(0)
# cfg.option('od.interface0.ip_admin_eth0').value.pop(0) cfg.option('od.interface0.ip_admin_eth0').value.pop(0)
# assert cfg.option('od.interface0.ip_admin_eth0').value.get() == [] assert cfg.option('od.interface0.ip_admin_eth0').value.get() == []
# cfg.option('od.interface0.ip_admin_eth0').value.reset() cfg.option('od.interface0.ip_admin_eth0').value.reset()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault() assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions() # assert not list_sessions()
#
#
#def test_follower_properties(): #def test_follower_properties():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) 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=('aproperty',)) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('aproperty',))

View file

@ -34,20 +34,6 @@ def test_option_valid_name():
i = SymLinkOption("test1", i) i = SymLinkOption("test1", i)
def test_option_get_information():
description = "it's ok"
string = 'some informations'
i = IntOption('test', description)
with pytest.raises(ValueError):
i.impl_get_information('noinfo')
i.impl_set_information('info', string)
assert i.impl_get_information('info') == string
with pytest.raises(ValueError):
i.impl_get_information('noinfo')
assert i.impl_get_information('noinfo', 'default') == 'default'
assert i.impl_get_information('doc') == description
def test_option_get_information_config(): def test_option_get_information_config():
description = "it's ok" description = "it's ok"
string = 'some informations' string = 'some informations'
@ -55,21 +41,16 @@ def test_option_get_information_config():
od = OptionDescription('od', '', [i]) od = OptionDescription('od', '', [i])
cfg = Config(od) cfg = Config(od)
with pytest.raises(ValueError): with pytest.raises(ValueError):
i.impl_get_information('noinfo') cfg.option('test').information.get('noinfo')
with pytest.raises(AttributeError): assert cfg.option('test').information.get('noinfo', 'default') == 'default'
i.impl_set_information('info', string) assert cfg.option('test').information.get('doc') == description
with pytest.raises(ValueError):
i.impl_get_information('noinfo')
assert i.impl_get_information('noinfo', 'default') == 'default'
assert i.impl_get_information('doc') == description
# assert not list_sessions() # assert not list_sessions()
def test_option_unknown(): def test_option_unknown():
description = "it's ok" description = "it's ok"
string = 'some informations' string = 'some informations'
i = IntOption('test', description) i = IntOption('test', description, informations={'noinfo': 'optdefault'})
i.impl_set_information('noinfo', 'optdefault')
od = OptionDescription('od', '', [i]) od = OptionDescription('od', '', [i])
cfg = Config(od) cfg = Config(od)
# #
@ -93,8 +74,7 @@ def test_option_description():
def test_option_get_information_default(): def test_option_get_information_default():
description = "it's ok" description = "it's ok"
string = 'some informations' string = 'some informations'
i = IntOption('test', description) i = IntOption('test', description, informations={'noinfo': 'optdefault'})
i.impl_set_information('noinfo', 'optdefault')
od = OptionDescription('od', '', [i]) od = OptionDescription('od', '', [i])
cfg = Config(od) cfg = Config(od)
# #
@ -108,32 +88,30 @@ def test_option_get_information_default():
def test_option_get_information_config2(): def test_option_get_information_config2():
description = "it's ok" description = "it's ok"
string = 'some informations' string = 'some informations'
i = IntOption('test', description) i = IntOption('test', description, informations={'info': string})
i.impl_set_information('info', string)
od = OptionDescription('od', '', [i]) od = OptionDescription('od', '', [i])
cfg = Config(od) cfg = Config(od)
with pytest.raises(ValueError): with pytest.raises(ValueError):
i.impl_get_information('noinfo') cfg.option('test').information.get('noinfo')
with pytest.raises(AttributeError): assert cfg.option('test').information.get('info') == string
i.impl_set_information('info', 'hello')
assert i.impl_get_information('info') == string
with pytest.raises(ValueError): with pytest.raises(ValueError):
i.impl_get_information('noinfo') cfg.option('test').information.get('noinfo')
assert i.impl_get_information('noinfo', 'default') == 'default' assert cfg.option('test').information.get('noinfo', 'default') == 'default'
assert i.impl_get_information('doc') == description assert cfg.option('test').information.get('doc') == description
# assert not list_sessions() # assert not list_sessions()
def test_optiondescription_get_information(): def test_optiondescription_get_information():
description = "it's ok" description = "it's ok"
string = 'some informations' string = 'some informations'
o = OptionDescription('test', description, []) o = OptionDescription('test', description, [], informations={'info': string})
o.impl_set_information('info', string) od = OptionDescription('od', '', [o])
assert o.impl_get_information('info') == string cfg = Config(od)
assert cfg.option('test').information.get('info') == string
with pytest.raises(ValueError): with pytest.raises(ValueError):
o.impl_get_information('noinfo') cfg.option('test').information.get('noinfo')
assert o.impl_get_information('noinfo', 'default') == 'default' assert cfg.option('test').information.get('noinfo', 'default') == 'default'
assert o.impl_get_information('doc') == description assert cfg.option('test').information.get('doc') == description
# assert not list_sessions() # assert not list_sessions()
@ -218,7 +196,7 @@ def test_optiondescription_group():
od3.impl_set_group_type(groups.notfamily) od3.impl_set_group_type(groups.notfamily)
od2 = OptionDescription('od', '', [od1, od3]) od2 = OptionDescription('od', '', [od1, od3])
cfg = Config(od2) cfg = Config(od2)
assert len(list(cfg.option.list())) == 2 assert len(list(cfg.list())) == 2
# assert not list_sessions() # assert not list_sessions()

View file

@ -415,8 +415,7 @@ def test_callback_information(config_type):
def test_callback_information2(config_type): def test_callback_information2(config_type):
val1 = StrOption('val1', "", Calculation(return_value, Params(ParamSelfInformation('information', 'no_value')))) val1 = StrOption('val1', "", Calculation(return_value, Params(ParamSelfInformation('information', 'no_value'))))
val2 = StrOption('val2', "", Calculation(return_value, Params(ParamSelfInformation('information')))) val2 = StrOption('val2', "", Calculation(return_value, Params(ParamSelfInformation('information'))), informations={'information': 'new_value'})
val2.impl_set_information('information', 'new_value')
val3 = StrOption('val3', "", Calculation(return_value, Params(ParamSelfInformation('information')))) val3 = StrOption('val3', "", Calculation(return_value, Params(ParamSelfInformation('information'))))
od1 = OptionDescription('rootconfig', '', [val1, val2, val3]) od1 = OptionDescription('rootconfig', '', [val1, val2, val3])
cfg = Config(od1) cfg = Config(od1)
@ -432,9 +431,8 @@ def test_callback_information2(config_type):
def test_callback_information3(config_type): def test_callback_information3(config_type):
val1 = StrOption('val1', "") val1 = StrOption('val1', "", informations={'information': 'new_value'})
val2 = StrOption('val2', "", Calculation(return_value, Params(ParamInformation('information', option=val1)))) val2 = StrOption('val2', "", Calculation(return_value, Params(ParamInformation('information', option=val1))))
val1.impl_set_information('information', 'new_value')
od1 = OptionDescription('rootconfig', '', [val1, val2]) od1 = OptionDescription('rootconfig', '', [val1, val2])
cfg = Config(od1) cfg = Config(od1)
cfg.property.read_write() cfg.property.read_write()
@ -1691,3 +1689,38 @@ def test_calc_dependencies(config_type):
def test_callback__kwargs_wrong(config_type): def test_callback__kwargs_wrong(config_type):
with pytest.raises(ValueError): with pytest.raises(ValueError):
Params(kwargs='string') Params(kwargs='string')
def test_callback_information_parent(config_type):
information = ParamInformation('information')
val1 = StrOption('val1', "", Calculation(return_value, Params(information)))
od2 = OptionDescription('od', '', [val1], informations={'information': 'new_value'})
information.set_option(od2)
od1 = OptionDescription('rootconfig', '', [od2])
cfg = Config(od1)
cfg.property.read_write()
cfg = get_config(cfg, config_type)
assert cfg.option('od.val1').value.get() == 'new_value'
cfg.option('od').information.set('information', 'new_value2')
assert cfg.option('od.val1').value.get() == 'new_value2'
def test_callback_information_redefined(config_type):
val1 = StrOption('val1', "")
information = ParamInformation('information', option=val1)
val2 = StrOption('val2', "", Calculation(return_value, Params(information)))
od2 = OptionDescription('od', '', [val1, val2], informations={'information': 'new_value'})
with pytest.raises(ConfigError):
information.set_option(od2)
def test_callback_information_redefined_after(config_type):
information = ParamInformation('information')
val1 = StrOption('val1', "", Calculation(return_value, Params(information)))
od2 = OptionDescription('od', '', [val1], informations={'information': 'new_value'})
od1 = OptionDescription('rootconfig', '', [od2])
cfg = Config(od1)
cfg.property.read_write()
cfg = get_config(cfg, config_type)
with pytest.raises(ConfigError):
information.set_option(od2)

View file

@ -166,28 +166,6 @@ def test_force_default_on_freeze_multi():
# assert not list_sessions() # assert not list_sessions()
def test_force_default_on_freeze_leader_frozen():
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_default_on_freeze', 'frozen'))
dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
descr = Leadership("dummy1", "", [dummy1, dummy2])
od1 = OptionDescription("root", "", [descr])
cfg = Config(od1)
with pytest.raises(LeadershipError):
cfg.option('dummy1.dummy1').property.remove('frozen')
# assert not list_sessions()
def test_force_metaconfig_on_freeze_leader_frozen():
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_metaconfig_on_freeze', 'frozen'))
dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
descr = Leadership("dummy1", "", [dummy1, dummy2])
od1 = OptionDescription("root", "", [descr])
cfg = Config(od1)
with pytest.raises(LeadershipError):
cfg.option('dummy1.dummy1').property.remove('frozen')
# assert not list_sessions()
def test_force_default_on_freeze_follower(config_type): def test_force_default_on_freeze_follower(config_type):
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('notunique',)) dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('notunique',))
dummy2 = BoolOption('dummy2', 'Test string option', multi=True, properties=('force_default_on_freeze',)) dummy2 = BoolOption('dummy2', 'Test string option', multi=True, properties=('force_default_on_freeze',))

View file

@ -82,7 +82,7 @@ def test_mod_read_only_write():
'empty', 'empty',
} }
# #
config.property.setdefault(frozenset(['cache'])) # config.property.setdefault(frozenset(['cache']))
config.property.setdefault(type='read_only', when='append', properties=frozenset(['disabled'])) config.property.setdefault(type='read_only', when='append', properties=frozenset(['disabled']))
config.property.setdefault(type='read_only', when='remove', properties=frozenset(['hidden'])) config.property.setdefault(type='read_only', when='remove', properties=frozenset(['hidden']))
config.property.setdefault(type='read_write', when='append', properties=frozenset(['disabled', 'hidden'])) config.property.setdefault(type='read_write', when='append', properties=frozenset(['disabled', 'hidden']))
@ -94,7 +94,7 @@ def test_mod_read_only_write():
with pytest.raises(TypeError): with pytest.raises(TypeError):
config.property.setdefault(type='read_only', when='append', properties=['disabled']) config.property.setdefault(type='read_only', when='append', properties=['disabled'])
assert config.property.default() == {'cache'} assert config.property.default() == {'warnings', 'validator', 'cache'}
assert config.property.default('read_only', 'append') == {'disabled'} assert config.property.default('read_only', 'append') == {'disabled'}
assert config.property.default('read_only', 'remove') == {'hidden'} assert config.property.default('read_only', 'remove') == {'hidden'}
assert config.property.default('read_write', 'append') == {'disabled', assert config.property.default('read_write', 'append') == {'disabled',
@ -102,11 +102,11 @@ def test_mod_read_only_write():
assert config.property.default('read_write', 'remove') == set([]) assert config.property.default('read_write', 'remove') == set([])
# #
config.property.read_only() config.property.read_only()
assert config.property.get() == {'cache', 'disabled'} assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled'}
config.property.read_write() config.property.read_write()
assert config.property.get() == {'cache', 'disabled', 'hidden'} assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled', 'hidden'}
config.property.read_only() config.property.read_only()
assert config.property.get() == {'cache', 'disabled'} assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled'}
# #
assert config2.property.default() == {'cache', 'validator', 'warnings'} assert config2.property.default() == {'cache', 'validator', 'warnings'}
assert config2.property.default('read_only', 'append') == {'frozen', assert config2.property.default('read_only', 'append') == {'frozen',
@ -138,6 +138,19 @@ def test_mod_read_only_write():
# assert not list_sessions() # assert not list_sessions()
def test_setting_tree(config_type):
s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True)
od4 = OptionDescription("option4", "", [s])
od3 = OptionDescription("option3", "", [od4])
od2 = OptionDescription("option2", "", [od3], properties=('hidden',))
od1 = OptionDescription("root", "", [od2])
cfg = Config(od1)
cfg = get_config(cfg, config_type)
cfg.property.read_write()
with pytest.raises(PropertiesOptionError):
cfg.option('option2.option3.option4.string').value.get()
def test_setitem(config_type): def test_setitem(config_type):
s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True) s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True)
od1 = OptionDescription("options", "", [s]) od1 = OptionDescription("options", "", [s])
@ -365,8 +378,7 @@ def test_apply_requires_from_config():
with pytest.raises(PropertiesOptionError): with pytest.raises(PropertiesOptionError):
cfg.option('opt.str').value.get() cfg.option('opt.str').value.get()
assert 'hidden' in cfg.forcepermissive.option('opt.str').property.get() assert 'hidden' in cfg.forcepermissive.option('opt.str').property.get()
assert 'hidden' not in cfg.forcepermissive.option('opt.str').properties() assert 'hidden' not in cfg.forcepermissive.option('opt.str').property.get(only_raises=True)
assert 'hidden' not in cfg.forcepermissive.option('opt.str').properties(only_raises=True)
# assert not list_sessions() # assert not list_sessions()
@ -386,8 +398,7 @@ def test_apply_requires_with_disabled():
cfg.option('int').value.set(1) cfg.option('int').value.set(1)
with pytest.raises(PropertiesOptionError): with pytest.raises(PropertiesOptionError):
cfg.option('opt.str').value.get() cfg.option('opt.str').value.get()
assert 'disabled' not in cfg.unrestraint.option('opt.str').properties() assert 'disabled' not in cfg.unrestraint.option('opt.str').property.get(only_raises=True, apply_requires=False)
assert 'disabled' not in cfg.unrestraint.option('opt.str').properties(only_raises=True)
assert 'disabled' in cfg.unrestraint.option('opt.str').property.get() assert 'disabled' in cfg.unrestraint.option('opt.str').property.get()
# assert not list_sessions() # assert not list_sessions()
@ -607,7 +618,7 @@ def test_properties_get_add_reset():
cfg.property.add('frozen') cfg.property.add('frozen')
assert cfg.property.get() == {'validator', 'warnings', 'cache', 'frozen'} assert cfg.property.get() == {'validator', 'warnings', 'cache', 'frozen'}
cfg.property.reset() cfg.property.reset()
assert cfg.property.get() == {'validator', 'warnings', 'cache'} assert cfg.property.get() == frozenset()
def test_reset_properties_force_store_value(): def test_reset_properties_force_store_value():
@ -615,28 +626,25 @@ def test_reset_properties_force_store_value():
gcgroup = OptionDescription('gc', '', [gcdummy]) gcgroup = OptionDescription('gc', '', [gcdummy])
od1 = OptionDescription('tiramisu', '', [gcgroup]) od1 = OptionDescription('tiramisu', '', [gcgroup])
cfg = Config(od1) cfg = Config(od1)
assert cfg.property.exportation() == {} assert cfg.property.exportation() == {None: {None: frozenset({'validator', 'warnings', 'cache'})}}
cfg.property.add('frozen') cfg.property.add('frozen')
assert cfg.property.exportation() == \ assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}} {None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}}
cfg.property.reset() cfg.property.reset()
assert cfg.property.exportation() == {None: {}} assert cfg.property.exportation() == {None: {}}
cfg.option('gc.dummy').property.add('test') cfg.option('gc.dummy').property.add('test')
assert cfg.property.exportation() == {None: {}, 'gc.dummy': {None: set(('test', 'force_store_value'))}} assert cfg.property.exportation() == {None: {}, 'gc.dummy': {None: frozenset({'test'})}}
cfg.property.reset() cfg.property.reset()
assert cfg.property.exportation() == {None: {}, 'gc.dummy': {None: set(('test', 'force_store_value'))}} assert cfg.property.exportation() == {None: {}, 'gc.dummy': {None: frozenset({'test'})}}
cfg.property.add('frozen') cfg.property.add('frozen')
assert cfg.property.exportation() == \ assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))}, {None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}}
'gc.dummy': {None: set(('test', 'force_store_value'))}}
cfg.property.add('frozen') cfg.property.add('frozen')
assert cfg.property.exportation() == \ assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))}, {None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}}
'gc.dummy': {None: set(('test', 'force_store_value'))}}
cfg.option('gc.dummy').property.add('test') cfg.option('gc.dummy').property.add('test')
assert cfg.property.exportation() == \ assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))}, {None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}}
'gc.dummy': {None: set(('test', 'force_store_value'))}}
# assert not list_sessions() # assert not list_sessions()
@ -666,7 +674,7 @@ def test_set_modified_value():
gcgroup = OptionDescription('gc', '', [gcdummy]) gcgroup = OptionDescription('gc', '', [gcdummy])
od1 = OptionDescription('tiramisu', '', [gcgroup]) od1 = OptionDescription('tiramisu', '', [gcgroup])
cfg = Config(od1) cfg = Config(od1)
assert cfg.property.exportation() == {} assert cfg.property.exportation() == {None: {None: frozenset({'warnings', 'validator', 'cache'})}}
cfg.property.importation({None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}}) cfg.property.importation({None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}})
assert cfg.property.exportation() == \ assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}} {None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}}

View file

@ -64,7 +64,10 @@ def test_is_hidden(config_type):
def test_group_is_hidden(config_type): def test_group_is_hidden(config_type):
od1 = make_description() gcdummy = BoolOption('dummy', 'dummy', default=False, properties=(('hidden'),))
floatoption = FloatOption('float', 'Test float option', default=2.3)
gcgroup = OptionDescription('gc', '', [gcdummy, floatoption])
od1 = OptionDescription('trs', '', [gcgroup])
cfg_ori = Config(od1) cfg_ori = Config(od1)
cfg_ori.property.read_write() cfg_ori.property.read_write()
cfg_ori.option('gc').property.add('hidden') cfg_ori.option('gc').property.add('hidden')
@ -73,14 +76,14 @@ def test_group_is_hidden(config_type):
cfg.option('gc.dummy').value.get() cfg.option('gc.dummy').value.get()
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
assert 'hidden' in cfg_ori.forcepermissive.option('gc').property.get() assert 'hidden' in cfg_ori.option('gc').property.get()
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
with pytest.raises(PropertiesOptionError): with pytest.raises(PropertiesOptionError):
cfg.option('gc.float').value.get() cfg.option('gc.float').value.get()
# manually set the subconfigs to "show" # manually set the subconfigs to "show"
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.forcepermissive.option('gc').property.remove('hidden') cfg_ori.option('gc').property.remove('hidden')
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
assert not 'hidden' in cfg.option('gc').property.get() assert not 'hidden' in cfg.option('gc').property.get()
assert cfg.option('gc.float').value.get() == 2.3 assert cfg.option('gc.float').value.get() == 2.3

View file

@ -1260,18 +1260,24 @@ def test_consistency_not_equal_has_dependency():
def test_validator_information(config_type): def test_validator_information(config_type):
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfInformation('key'), ParamValue('yes'))))], default='val') opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfInformation('key'), ParamValue('yes'))))], default='val')
opt2 = StrOption('opt2', '', validators=[Calculation(return_true, Params((ParamInformation('key'), ParamValue('yes'))))], default='val') opt2 = StrOption('opt2', '', validators=[Calculation(return_true, Params((ParamInformation('key'), ParamValue('yes'))))], default='val')
od1 = OptionDescription('root', '', [opt1, opt2]) opt3 = StrOption('opt3', '', validators=[Calculation(return_true, Params((ParamInformation('key', option=opt1), ParamValue('yes'))))], default='val')
od1 = OptionDescription('root', '', [opt1, opt2, opt3])
cfg = Config(od1) cfg = Config(od1)
with pytest.raises(ConfigError): with pytest.raises(ConfigError):
cfg.option('opt1').value.get() cfg.option('opt1').value.get()
with pytest.raises(ConfigError):
cfg.option('opt3').value.get()
cfg.option('opt1').information.set('key', 'val') cfg.option('opt1').information.set('key', 'val')
assert cfg.option('opt1').value.get() == 'val' assert cfg.option('opt1').value.get() == 'val'
assert cfg.option('opt3').value.get() == 'val'
cfg.option('opt1').information.set('key', 'val1') cfg.option('opt1').information.set('key', 'val1')
with pytest.raises(ValueError): with pytest.raises(ValueError):
cfg.option('opt1').value.get() cfg.option('opt1').value.get()
with pytest.raises(ValueError):
cfg.option('opt3').value.get()
# #
with pytest.raises(ConfigError): with pytest.raises(ConfigError):
assert cfg.option('opt2').value.get() cfg.option('opt2').value.get()
cfg.information.set('key', 'val') cfg.information.set('key', 'val')
assert cfg.option('opt2').value.get() == 'val' assert cfg.option('opt2').value.get() == 'val'
cfg.information.set('key', 'val1') cfg.information.set('key', 'val1')

View file

@ -22,7 +22,7 @@ def test_forcepermissive_and_unrestraint(config_type):
cfg_ori.property.read_write() cfg_ori.property.read_write()
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
with pytest.raises(ConfigError): with pytest.raises(ConfigError):
cfg_ori.unrestraint.forcepermissive.add('disabled') cfg_ori.forcepermissive.add('disabled')
def test_permissive(config_type): def test_permissive(config_type):
@ -39,9 +39,9 @@ def test_permissive(config_type):
assert set(props) == {'disabled'} assert set(props) == {'disabled'}
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.unrestraint.permissive.add('disabled') cfg_ori.permissive.add('disabled')
cfg_ori.unrestraint.permissive.remove('hidden') cfg_ori.permissive.remove('hidden')
assert cfg_ori.unrestraint.permissive.get() == frozenset(['disabled']) assert cfg_ori.permissive.get() == frozenset(['disabled'])
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
props = frozenset() props = frozenset()
try: try:
@ -81,8 +81,8 @@ def test_permissive_add(config_type):
assert set(props) == {'disabled'} assert set(props) == {'disabled'}
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.unrestraint.permissive.add('disabled') cfg_ori.permissive.add('disabled')
assert cfg_ori.unrestraint.permissive.get() == frozenset(['hidden', 'disabled']) assert cfg_ori.permissive.get() == frozenset(['hidden', 'disabled'])
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
props = frozenset() props = frozenset()
try: try:
@ -119,10 +119,10 @@ def test_permissive_pop():
except PropertiesOptionError as err: except PropertiesOptionError as err:
props = err.proptype props = err.proptype
assert set(props) == {'disabled'} assert set(props) == {'disabled'}
cfg.unrestraint.permissive.add('disabled') cfg.permissive.add('disabled')
assert cfg.unrestraint.permissive.get() == frozenset(['hidden', 'disabled']) assert cfg.permissive.get() == frozenset(['hidden', 'disabled'])
cfg.forcepermissive.option('u1').value.get() cfg.forcepermissive.option('u1').value.get()
cfg.unrestraint.permissive.remove('disabled') cfg.permissive.remove('disabled')
props = frozenset() props = frozenset()
try: try:
cfg.forcepermissive.option('u1').value.get() cfg.forcepermissive.option('u1').value.get()
@ -136,14 +136,14 @@ def test_permissive_reset():
od1 = make_description() od1 = make_description()
cfg = Config(od1) cfg = Config(od1)
cfg.property.read_write() cfg.property.read_write()
assert cfg.unrestraint.permissive.get() == frozenset(['hidden']) assert cfg.permissive.get() == frozenset(['hidden'])
# #
cfg.unrestraint.permissive.add('disabled') cfg.permissive.add('disabled')
cfg.unrestraint.permissive.remove('hidden') cfg.permissive.remove('hidden')
assert cfg.unrestraint.permissive.get() == frozenset(['disabled']) assert cfg.permissive.get() == frozenset(['disabled'])
# #
cfg.unrestraint.permissive.reset() cfg.permissive.reset()
assert cfg.unrestraint.permissive.get() == frozenset() assert cfg.permissive.get() == frozenset(['hidden'])
# assert not list_sessions() # assert not list_sessions()
@ -157,9 +157,9 @@ def test_permissive_mandatory():
except PropertiesOptionError as err: except PropertiesOptionError as err:
props = err.proptype props = err.proptype
assert frozenset(props) == frozenset(['disabled']) assert frozenset(props) == frozenset(['disabled'])
cfg.unrestraint.permissive.add('mandatory') cfg.permissive.add('mandatory')
cfg.unrestraint.permissive.add('disabled') cfg.permissive.add('disabled')
assert cfg.unrestraint.permissive.get() == frozenset(['mandatory', 'disabled']) assert cfg.permissive.get() == frozenset(['hidden', 'mandatory', 'disabled'])
cfg.property.add('permissive') cfg.property.add('permissive')
cfg.option('u1').value.get() cfg.option('u1').value.get()
cfg.property.remove('permissive') cfg.property.remove('permissive')
@ -175,10 +175,10 @@ def test_permissive_frozen():
od1 = make_description() od1 = make_description()
cfg = Config(od1) cfg = Config(od1)
cfg.property.read_write() cfg.property.read_write()
cfg.unrestraint.permissive.remove('hidden') cfg.permissive.remove('hidden')
cfg.unrestraint.permissive.add('frozen') cfg.permissive.add('frozen')
cfg.unrestraint.permissive.add('disabled') cfg.permissive.add('disabled')
assert cfg.unrestraint.permissive.get() == frozenset(['frozen', 'disabled']) assert cfg.permissive.get() == frozenset(['frozen', 'disabled'])
assert cfg.permissive.get() == frozenset(['frozen', 'disabled']) assert cfg.permissive.get() == frozenset(['frozen', 'disabled'])
try: try:
cfg.option('u1').value.set(1) cfg.option('u1').value.set(1)
@ -229,7 +229,7 @@ def test_permissive_option(config_type):
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.unrestraint.option('u1').permissive.set(frozenset(['disabled'])) cfg_ori.option('u1').permissive.add('disabled')
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
props = frozenset() props = frozenset()
try: try:
@ -293,7 +293,7 @@ def test_permissive_option_cache():
props = err.proptype props = err.proptype
assert set(props) == {'disabled'} assert set(props) == {'disabled'}
cfg.unrestraint.option('u1').permissive.set(frozenset(['disabled'])) cfg.option('u1').permissive.add('disabled')
props = frozenset() props = frozenset()
try: try:
cfg.option('u1').value.get() cfg.option('u1').value.get()
@ -342,8 +342,9 @@ def test_permissive_option_mandatory():
except PropertiesOptionError as err: except PropertiesOptionError as err:
props = err.proptype props = err.proptype
assert frozenset(props) == frozenset(['disabled']) assert frozenset(props) == frozenset(['disabled'])
cfg.unrestraint.option('u1').permissive.set(frozenset(['mandatory', 'disabled'])) cfg.option('u1').permissive.add('mandatory')
assert cfg.unrestraint.option('u1').permissive.get() == frozenset(['mandatory', 'disabled']) cfg.option('u1').permissive.add('disabled')
assert cfg.option('u1').permissive.get() == frozenset(['mandatory', 'disabled'])
cfg.property.add('permissive') cfg.property.add('permissive')
cfg.option('u1').value.get() cfg.option('u1').value.get()
cfg.property.remove('permissive') cfg.property.remove('permissive')
@ -359,7 +360,8 @@ def test_permissive_option_frozen():
od1 = make_description() od1 = make_description()
cfg = Config(od1) cfg = Config(od1)
cfg.property.read_write() cfg.property.read_write()
cfg.unrestraint.option('u1').permissive.set(frozenset(['frozen', 'disabled'])) cfg.option('u1').permissive.add('disabled')
cfg.option('u1').permissive.add('frozen')
cfg.option('u1').value.set(1) cfg.option('u1').value.set(1)
assert cfg.option('u1').value.get() == 1 assert cfg.option('u1').value.get() == 1
cfg.property.add('permissive') cfg.property.add('permissive')
@ -369,15 +371,6 @@ def test_permissive_option_frozen():
# assert not list_sessions() # assert not list_sessions()
def test_invalid_option_permissive():
od1 = make_description()
cfg = Config(od1)
cfg.property.read_write()
with pytest.raises(TypeError):
cfg.unrestraint.option('u1').permissive.set(['frozen', 'disabled'])
# assert not list_sessions()
def test_remove_option_permissive(config_type): def test_remove_option_permissive(config_type):
var1 = StrOption('var1', '', u'value', properties=('hidden',)) var1 = StrOption('var1', '', u'value', properties=('hidden',))
od1 = OptionDescription('od1', '', [var1]) od1 = OptionDescription('od1', '', [var1])
@ -389,13 +382,13 @@ def test_remove_option_permissive(config_type):
cfg.option('od1.var1').value.get() cfg.option('od1.var1').value.get()
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.forcepermissive.option('od1.var1').permissive.set(frozenset(['hidden'])) cfg_ori.forcepermissive.option('od1.var1').permissive.add('hidden')
assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset(['hidden']) assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset(['hidden'])
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
assert cfg.option('od1.var1').value.get() == 'value' assert cfg.option('od1.var1').value.get() == 'value'
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.forcepermissive.option('od1.var1').permissive.set(frozenset()) cfg_ori.forcepermissive.option('od1.var1').permissive.reset()
assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset() assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset()
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
with pytest.raises(PropertiesOptionError): with pytest.raises(PropertiesOptionError):
@ -414,7 +407,7 @@ def test_reset_option_permissive(config_type):
cfg.option('od1.var1').value.get() cfg.option('od1.var1').value.get()
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.forcepermissive.option('od1.var1').permissive.set(frozenset(['hidden'])) cfg_ori.forcepermissive.option('od1.var1').permissive.add('hidden')
assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset(['hidden']) assert cfg_ori.forcepermissive.option('od1.var1').permissive.get() == frozenset(['hidden'])
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
assert cfg.option('od1.var1').value.get() == 'value' assert cfg.option('od1.var1').value.get() == 'value'

View file

@ -31,12 +31,12 @@ def test_properties(config_type):
assert frozenset(props) == frozenset(['disabled']) assert frozenset(props) == frozenset(['disabled'])
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.unrestraint.option('ip_address_service').property.remove('disabled') cfg_ori.unrestraint.option('ip_address_service').permissive.add('disabled')
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
cfg.option('ip_address_service').value.get() cfg.option('ip_address_service').value.get()
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.unrestraint.option('ip_address_service').property.add('disabled') cfg_ori.unrestraint.option('ip_address_service').permissive.remove('disabled')
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)
props = [] props = []
try: try:
@ -47,8 +47,8 @@ def test_properties(config_type):
# pop twice # pop twice
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
cfg.send() cfg.send()
cfg_ori.unrestraint.option('ip_address_service').property.remove('disabled') cfg_ori.unrestraint.option('ip_address_service').permissive.add('disabled')
cfg_ori.unrestraint.option('ip_address_service').property.remove('disabled') cfg_ori.unrestraint.option('ip_address_service').permissive.remove('disabled')
# assert not list_sessions() # assert not list_sessions()
@ -613,6 +613,7 @@ def test_requires_transitive_hidden_disabled_multiple(config_type):
del req del req
# #
cfg_ori.permissive.reset() cfg_ori.permissive.reset()
cfg_ori.permissive.remove('hidden')
if config_type == 'tiramisu-api': if config_type == 'tiramisu-api':
try: try:
cfg = get_config(cfg_ori, config_type) cfg = get_config(cfg_ori, config_type)

View file

@ -141,7 +141,7 @@ def test_symlink_getpermissive():
od1 = OptionDescription('opt', '', [boolopt, linkopt]) od1 = OptionDescription('opt', '', [boolopt, linkopt])
cfg = Config(od1) cfg = Config(od1)
cfg.property.read_write() cfg.property.read_write()
cfg.option('b').permissive.set(frozenset(['perm'])) cfg.option('b').permissive.add('perm')
cfg.option('c').permissive.get() == frozenset(['perm']) cfg.option('c').permissive.get() == frozenset(['perm'])
# assert not list_sessions() # assert not list_sessions()
@ -266,14 +266,26 @@ def test_symlink_owner(config_type):
def test_symlink_get_information(): def test_symlink_get_information():
boolopt = BoolOption("b", "", default=False) boolopt = BoolOption("b", "", default=False, informations={'test': 'test'})
linkopt = SymLinkOption("c", boolopt) linkopt = SymLinkOption("c", boolopt)
boolopt.impl_set_information('test', 'test') od1 = OptionDescription('opt', '', [linkopt, boolopt])
assert boolopt.impl_get_information('test') == 'test' cfg = Config(od1)
assert linkopt.impl_get_information('test') == 'test' assert cfg.option('b').information.get('test') == 'test'
boolopt.impl_set_information('test', 'test2') assert cfg.option('c').information.get('test') == 'test'
assert boolopt.impl_get_information('test') == 'test2' cfg.option('b').information.set('test', 'test2')
assert linkopt.impl_get_information('test') == 'test2' assert cfg.option('b').information.get('test') == 'test2'
assert cfg.option('c').information.get('test') == 'test2'
def test_symlink_informations():
boolopt = BoolOption("b", "", default=False)
with pytest.raises(TypeError):
linkopt = SymLinkOption("c", boolopt, informations={'test': 'test'})
linkopt = SymLinkOption("c", boolopt)
od1 = OptionDescription('opt', '', [linkopt, boolopt])
cfg = Config(od1)
with pytest.raises(ConfigError):
cfg.option('c').information.set('test', 'test2')
def test_symlink_leader(): def test_symlink_leader():
@ -359,9 +371,9 @@ def test_symlink_dependency():
[linkopt, OptionDescription("s1", "", [boolopt])]) [linkopt, OptionDescription("s1", "", [boolopt])])
cfg = Config(od1) cfg = Config(od1)
assert cfg.option('s1.b').has_dependency() is False assert cfg.option('s1.b').has_dependency() is False
assert cfg.option('c').has_dependency() is True assert cfg.option('c').has_dependency() is False
assert cfg.option('s1.b').has_dependency(False) is True assert cfg.option('s1.b').has_dependency(False) is True
assert cfg.option('c').has_dependency(False) is False assert cfg.option('c').has_dependency(False) is True
# assert not list_sessions() # assert not list_sessions()
@ -385,7 +397,7 @@ def test_symlink_list(config_type):
[linkopt, OptionDescription("s1", "", [boolopt])]) [linkopt, OptionDescription("s1", "", [boolopt])])
cfg = Config(od1) cfg = Config(od1)
cfg = get_config(cfg, config_type) cfg = get_config(cfg, config_type)
assert [opt.path() for opt in cfg.option.list()] == ['c', 's1'] assert [opt.path() for opt in cfg.list()] == ['c', 's1']
# #
assert [opt.path() for opt in cfg.option('s1').list()] == ['s1.b'] assert [opt.path() for opt in cfg.option('s1').list()] == ['s1.b']
# assert not list_sessions() # assert not list_sessions()

File diff suppressed because it is too large Load diff

View file

@ -19,16 +19,47 @@
# ____________________________________________________________ # ____________________________________________________________
"enables us to carry out a calculation and return an option's value" "enables us to carry out a calculation and return an option's value"
from typing import Any, Optional, Union, Callable, Dict, List from typing import Any, Optional, Union, Callable, Dict, List
from os.path import commonprefix
from itertools import chain from itertools import chain
import weakref
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
from .i18n import _ from .i18n import _
from .setting import undefined, ConfigBag, Undefined from .setting import undefined, ConfigBag
from .function import FUNCTION_WAITING_FOR_DICT from .function import FUNCTION_WAITING_FOR_DICT
# ____________________________________________________________ # ____________________________________________________________
def get_calculated_value(subconfig: "SubConfig",
value: Any,
*,
reset_cache: bool=True,
validate_properties: bool=True,
) -> Any:
"""value could be a calculation, in this case do calculation
"""
has_calculation = False
if isinstance(value, Calculation):
if subconfig is None:
return undefined, False
value = value.execute(subconfig,
validate_properties=validate_properties,
)
has_calculation = True
elif isinstance(value, list):
# if value is a list, do subcalculation
for idx, val in enumerate(value):
value[idx], _has_calculation = get_calculated_value(subconfig,
val,
reset_cache=False,
validate_properties=validate_properties,
)
if value[idx] is undefined:
return undefined, False
if _has_calculation:
has_calculation = True
return value, has_calculation
class Params: class Params:
__slots__ = ('args', 'kwargs') __slots__ = ('args', 'kwargs')
def __init__(self, args=None, kwargs=None, **kwgs): def __init__(self, args=None, kwargs=None, **kwgs):
@ -85,13 +116,11 @@ class ParamOption(Param):
class ParamDynOption(ParamOption): class ParamDynOption(ParamOption):
__slots__ = ('suffixes', __slots__ = ('suffixes',
'dynoptiondescription',
'optional', 'optional',
) )
def __init__(self, def __init__(self,
option: 'Option', option: 'Option',
suffixes: list[str], suffixes: list[str],
dynoptiondescription: 'DynOptionDescription'=None,
notraisepropertyerror: bool=False, notraisepropertyerror: bool=False,
raisepropertyerror: bool=False, raisepropertyerror: bool=False,
optional: bool=False, optional: bool=False,
@ -101,7 +130,6 @@ class ParamDynOption(ParamOption):
raisepropertyerror, raisepropertyerror,
) )
self.suffixes = suffixes self.suffixes = suffixes
self.dynoptiondescription = dynoptiondescription
self.optional = optional self.optional = optional
@ -125,6 +153,7 @@ class ParamInformation(Param):
__slots__ = ('information_name', __slots__ = ('information_name',
'default_value', 'default_value',
'option', 'option',
'self_option',
) )
def __init__(self, def __init__(self,
information_name: str, information_name: str,
@ -133,7 +162,22 @@ class ParamInformation(Param):
) -> None: ) -> None:
self.information_name = information_name self.information_name = information_name
self.default_value = default_value self.default_value = default_value
self.self_option = None
self.option = None
if option: if option:
self.set_option(option)
def set_self_option(self, option):
self.self_option = option
def set_option(self,
option: 'Option'=None
) -> None:
if not hasattr(self, 'self_option'):
raise ConfigError('cannot add option in information after creating config')
if self.option:
raise ConfigError('cannot redefine option in information')
if not option.impl_is_optiondescription():
if option.impl_is_symlinkoption(): if option.impl_is_symlinkoption():
raise ValueError(_('option in ParamInformation cannot be a symlinkoption')) raise ValueError(_('option in ParamInformation cannot be a symlinkoption'))
if option.impl_is_follower(): if option.impl_is_follower():
@ -141,10 +185,27 @@ class ParamInformation(Param):
if option.impl_is_dynsymlinkoption(): if option.impl_is_dynsymlinkoption():
raise ValueError(_('option in ParamInformation cannot be a dynamic option')) raise ValueError(_('option in ParamInformation cannot be a dynamic option'))
self.option = option self.option = option
if self.self_option:
informations = self.self_option._dependencies_information
if set(informations) == {None, self.information_name}:
del self.self_option._dependencies_information
else:
informations.remove(None)
if not getattr(option, '_dependencies_information', {}):
option._dependencies_information = {None: []}
option._dependencies_information[None].append(self)
option._dependencies_information.setdefault(self.information_name, []).append(weakref.ref(self.self_option))
class ParamSelfInformation(ParamInformation): class ParamSelfInformation(ParamInformation):
__slots__ = tuple() __slots__ = tuple()
def __init__(self,
information_name: str,
default_value: Any=undefined,
) -> None:
return super().__init__(information_name,
default_value,
)
class ParamIndex(Param): class ParamIndex(Param):
@ -152,7 +213,11 @@ class ParamIndex(Param):
class ParamSuffix(Param): class ParamSuffix(Param):
__slots__ = tuple() __slots__ = ('suffix_index',)
def __init__(self,
suffix_index: int=-1,
) -> None:
self.suffix_index = suffix_index
class Calculation: class Calculation:
@ -190,6 +255,7 @@ class Calculation:
allow_value_error: bool=False, allow_value_error: bool=False,
force_value_warning: bool=False, force_value_warning: bool=False,
for_settings: bool=False, for_settings: bool=False,
validate_properties: bool=True,
) -> Any: ) -> Any:
return carry_out_calculation(subconfig, return carry_out_calculation(subconfig,
callback=self.function, callback=self.function,
@ -200,6 +266,7 @@ class Calculation:
allow_value_error=allow_value_error, allow_value_error=allow_value_error,
force_value_warning=force_value_warning, force_value_warning=force_value_warning,
for_settings=for_settings, for_settings=for_settings,
validate_properties=validate_properties,
) )
def help(self, def help(self,
@ -229,6 +296,7 @@ def manager_callback(callback: Callable,
orig_value, orig_value,
config_bag: ConfigBag, config_bag: ConfigBag,
for_settings: bool, for_settings: bool,
validate_properties: bool,
) -> Any: ) -> Any:
"""replace Param by true value""" """replace Param by true value"""
option = subconfig.option option = subconfig.option
@ -297,18 +365,18 @@ def manager_callback(callback: Callable,
return value return value
def _get_value(param: Params, def _get_value(param: Params,
subconfig: SubConfig, subconfig: 'SubConfig',
) -> Any: ) -> Any:
try: try:
# get value # get value
value = config_bag.context.get_value(subconfig) value = config_bag.context.get_value(subconfig)
except PropertiesOptionError as err: except PropertiesOptionError as err:
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation # raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
if param.notraisepropertyerror or param.raisepropertyerror: if isinstance(param, ParamSelfOption) or param.notraisepropertyerror or param.raisepropertyerror:
raise err from err raise err from err
raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err
except ValueError as err: except ValueError as err:
display_name = subconfig.option.impl_get_display_name() display_name = subconfig.option.impl_get_display_name(subconfig)
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(display_name, err)) from err raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(display_name, err)) from err
except AttributeError as err: except AttributeError as err:
if isinstance(param, ParamDynOption) and param.optional: if isinstance(param, ParamDynOption) and param.optional:
@ -317,7 +385,7 @@ def manager_callback(callback: Callable,
['configerror'], ['configerror'],
config_bag.context.get_settings(), config_bag.context.get_settings(),
) )
display_name = subconfig.option.impl_get_display_name() display_name = subconfig.option.impl_get_display_name(subconfig)
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
return value return value
@ -341,20 +409,20 @@ def manager_callback(callback: Callable,
config_bag.remove_validation() config_bag.remove_validation()
# root = config_bag.context.get_root(config_bag) # root = config_bag.context.get_root(config_bag)
try: try:
subconfig = config_bag.context.get_sub_config(config_bag, subsubconfig = config_bag.context.get_sub_config(config_bag,
opt.impl_getpath(), opt.impl_getpath(),
index_, index_,
validate_properties=not self_calc, validate_properties=not self_calc,
properties=properties, properties=properties,
) )
except PropertiesOptionError as err: except PropertiesOptionError as err:
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation # raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
if param.notraisepropertyerror or param.raisepropertyerror: if param.notraisepropertyerror or param.raisepropertyerror:
raise err from err raise err from err
display_name = option.impl_get_display_name() display_name = option.impl_get_display_name(subconfig)
raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err
except ValueError as err: except ValueError as err:
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(), err)) from err raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(subconfig), err)) from err
except AttributeError as err: except AttributeError as err:
if isinstance(param, ParamDynOption) and param.optional: if isinstance(param, ParamDynOption) and param.optional:
# cannot acces, simulate a propertyerror # cannot acces, simulate a propertyerror
@ -362,19 +430,9 @@ def manager_callback(callback: Callable,
['configerror'], ['configerror'],
config_bag.context.get_settings(), config_bag.context.get_settings(),
) )
display_name = option.impl_get_display_name() display_name = option.impl_get_display_name(subconfig)
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
return subconfig return subsubconfig
def get_common_path(path1, path2):
common_path = commonprefix([path1, path2])
if common_path in [path1, path2]:
return common_path
if common_path.endswith('.'):
return common_path[:-1]
if '.' in common_path:
return common_path.rsplit('.', 1)[0]
return None
if isinstance(param, ParamValue): if isinstance(param, ParamValue):
return param.value return param.value
@ -383,22 +441,30 @@ def manager_callback(callback: Callable,
if isinstance(param, ParamSelfInformation): if isinstance(param, ParamSelfInformation):
isubconfig = subconfig isubconfig = subconfig
elif param.option: elif param.option:
isubconfig = get_option_bag(config_bag, if param.option.issubdyn():
param.option, search_option = param.option
param, isubconfig = subconfig.get_common_child(search_option,
None, true_path=subconfig.path,
False, )
#properties=properties, if isinstance(isubconfig, list):
) raise ConfigError(f'cannot find information for "{option.impl_get_display_name(subconfig)}", "{search_option.impl_get_display_name(None)}" is a dynamic option')
else:
isubconfig = get_option_bag(config_bag,
param.option,
param,
None,
False,
#properties=properties,
)
else: else:
isubconfig = None isubconfig = config_bag.context.get_root(config_bag)
try: try:
return config_bag.context.get_values().get_information(isubconfig, return config_bag.context.get_values().get_information(isubconfig,
param.information_name, param.information_name,
param.default_value, param.default_value,
) )
except ValueError as err: except ValueError as err:
display_name = option.impl_get_display_name() display_name = option.impl_get_display_name(subconfig)
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
if isinstance(param, ParamIndex): if isinstance(param, ParamIndex):
@ -406,9 +472,9 @@ def manager_callback(callback: Callable,
if isinstance(param, ParamSuffix): if isinstance(param, ParamSuffix):
if not option.issubdyn(): if not option.issubdyn():
display_name = subconfig.option.impl_get_display_name() display_name = subconfig.option.impl_get_display_name(subconfig)
raise ConfigError(_('option "{display_name}" is not in a dynoptiondescription')) raise ConfigError(_('option "{display_name}" is not in a dynoptiondescription'))
return subconfig.suffixes[-1] return subconfig.suffixes[param.suffix_index]
if isinstance(param, ParamSelfOption): if isinstance(param, ParamSelfOption):
value = calc_self(param, value = calc_self(param,
@ -418,45 +484,13 @@ def manager_callback(callback: Callable,
) )
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT: if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
return value return value
return {'name': option.impl_get_display_name(), return {'name': option.impl_get_display_name(subconfig),
'value': value, 'value': value,
} }
if isinstance(param, ParamOption): if isinstance(param, ParamOption):
callbk_option = param.option callbk_option = param.option
callbk_options = None config_bag = subconfig.config_bag
subconfigs = None
if callbk_option.issubdyn():
found = False
if isinstance(param, ParamDynOption):
# SUBDYN INSIDE CURRENT != SUBDYN OUTSIDE ?
callbk_option = callbk_option.to_sub_dyoption(param.suffixes)
found = True
else:
search_option = param.option
current_option_path = option.impl_getpath()
search_option_path = search_option.impl_getpath()
common_path = get_common_path(current_option_path, search_option_path)
if common_path:
parent_number = current_option_path[len(common_path) + 2:].count('.')
if parent_number:
raise Exception('pfff')
subconfig = subconfig.parent.get_child(search_option,
None,
True,
)
else:
raise Exception('pfff')
subconfigs = [subconfig]
found = True
if not found:
callbk_options = []
for doption_bag in callbk_option.getsubdyn().get_sub_children(callbk_option,
config_bag,
index=None,
):
callbk_options.append(doption_bag.option)
if index is not None and callbk_option.impl_get_leadership() and \ if index is not None and callbk_option.impl_get_leadership() and \
callbk_option.impl_get_leadership().in_same_leadership(option): callbk_option.impl_get_leadership().in_same_leadership(option):
if not callbk_option.impl_is_follower(): if not callbk_option.impl_is_follower():
@ -470,7 +504,69 @@ def manager_callback(callback: Callable,
else: else:
index_ = None index_ = None
with_index = False with_index = False
if subconfigs is None: if callbk_option.issubdyn():
if isinstance(param, ParamDynOption):
#callbk_option = callbk_option.to_sub_dyoption(param.suffixes)
suffixes = param.suffixes.copy()
paths = callbk_option.impl_getpath().split('.')
parents = [config_bag.context.get_root(config_bag)]
subconfigs_is_a_list = False
for name in paths:
new_parents = []
for parent in parents:
doption = parent.option.get_child(name,
config_bag,
parent,
allow_dynoption=True,
)
if doption.impl_is_dynoptiondescription():
if suffixes:
suffix = suffixes.pop(0)
name = doption.impl_getname(suffix)
try:
doption = parent.option.get_child(name,
config_bag,
parent,
)
except AttributeError as err:
raise ConfigError(err) from err
new_parents.append(parent.get_child(doption,
None,
True,
name=name,
suffix=suffix,
))
else:
subconfigs_is_a_list = True
new_parents.extend(parent.dyn_to_subconfig(doption,
True,
)
)
else:
new_parents.append(parent.get_child(doption,
None,
True,
name=name,
))
parents = new_parents
if subconfigs_is_a_list:
subconfigs = parents
else:
subconfigs = parents[0]
else:
search_option = param.option
subconfigs = subconfig.get_common_child(search_option,
true_path=subconfig.path,
validate_properties=validate_properties,
)
if isinstance(subconfigs, list):
values = []
else:
values = None
subconfigs = [subconfigs]
else:
subconfigs = [get_option_bag(config_bag, subconfigs = [get_option_bag(config_bag,
callbk_option, callbk_option,
param, param,
@ -479,13 +575,7 @@ def manager_callback(callback: Callable,
#properties=properties, #properties=properties,
) )
] ]
# callbk_options = [callbk_option]
values = None values = None
else:
values = []
#FIXME
values = None
# for callbk_option in callbk_options:
for subconfig in subconfigs: for subconfig in subconfigs:
callbk_option = subconfig.option callbk_option = subconfig.option
value = get_value(config_bag, value = get_value(config_bag,
@ -501,7 +591,7 @@ def manager_callback(callback: Callable,
value = values value = values
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT: if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
return value return value
return {'name': callbk_option.impl_get_display_name(), return {'name': callbk_option.impl_get_display_name(subconfig),
'value': value} 'value': value}
@ -514,6 +604,8 @@ def carry_out_calculation(subconfig: 'SubConfig',
allow_value_error: bool=False, allow_value_error: bool=False,
force_value_warning: bool=False, force_value_warning: bool=False,
for_settings: bool=False, for_settings: bool=False,
*,
validate_properties: bool=True,
): ):
"""a function that carries out a calculation for an option's value """a function that carries out a calculation for an option's value
@ -533,7 +625,7 @@ def carry_out_calculation(subconfig: 'SubConfig',
Values could have multiple values only when key is ''.""" Values could have multiple values only when key is ''."""
option = subconfig.option option = subconfig.option
if not option.impl_is_optiondescription() and option.impl_is_follower() and index is None: if not option.impl_is_optiondescription() and option.impl_is_follower() and index is None:
raise Exception('follower must have index in carry_out_calculation!') raise ConfigError(f'the follower "{option.impl_get_display_name(subconfig)}" must have index in carry_out_calculation!')
def fake_items(iterator): def fake_items(iterator):
return ((None, i) for i in iterator) return ((None, i) for i in iterator)
args = [] args = []
@ -548,20 +640,21 @@ def carry_out_calculation(subconfig: 'SubConfig',
orig_value, orig_value,
config_bag, config_bag,
for_settings, for_settings,
validate_properties,
) )
if key is None: if key is None:
args.append(value) args.append(value)
else: else:
kwargs[key] = value kwargs[key] = value
except PropertiesOptionError as err: except PropertiesOptionError as err:
if param.raisepropertyerror: if isinstance(param, ParamSelfOption) or param.raisepropertyerror:
raise err raise err
if callback.__name__ in FUNCTION_WAITING_FOR_DICT: if callback.__name__ in FUNCTION_WAITING_FOR_DICT:
if key is None: if key is None:
args.append({'propertyerror': str(err), 'name': option.impl_get_display_name()}) args.append({'propertyerror': str(err), 'name': option.impl_get_display_name(subconfig)})
else: else:
kwargs[key] = {'propertyerror': str(err), 'name': option.impl_get_display_name()} kwargs[key] = {'propertyerror': str(err), 'name': option.impl_get_display_name(subconfig)}
ret = calculate(option, ret = calculate(subconfig,
callback, callback,
allow_value_error, allow_value_error,
force_value_warning, force_value_warning,
@ -579,17 +672,17 @@ def carry_out_calculation(subconfig: 'SubConfig',
args, args,
kwargs, kwargs,
ret, ret,
option.impl_get_display_name())) option.impl_get_display_name(subconfig)))
else: else:
raise LeadershipError(_('the "{}" function must not return a list ("{}") ' raise LeadershipError(_('the "{}" function must not return a list ("{}") '
'for the follower option "{}"' 'for the follower option "{}"'
'').format(callback.__name__, '').format(callback.__name__,
ret, ret,
option.impl_get_display_name())) option.impl_get_display_name(subconfig)))
return ret return ret
def calculate(option, def calculate(subconfig,
callback: Callable, callback: Callable,
allow_value_error: bool, allow_value_error: bool,
force_value_warning: bool, force_value_warning: bool,
@ -617,12 +710,12 @@ def calculate(option,
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" ' msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
'for option "{2}"').format(str(error), 'for option "{2}"').format(str(error),
callback.__name__, callback.__name__,
option.impl_get_display_name(), subconfig.option.impl_get_display_name(subconfig),
args, args,
kwargs) kwargs)
else: else:
msg = _('unexpected error "{0}" in function "{1}" for option "{2}"' msg = _('unexpected error "{0}" in function "{1}" for option "{2}"'
'').format(str(error), '').format(str(error),
callback.__name__, callback.__name__,
option.impl_get_display_name()) subconfig.option.impl_get_display_name(subconfig))
raise ConfigError(msg) from error raise ConfigError(msg) from error

View file

@ -47,17 +47,12 @@ class Cache:
if path not in self._cache or index not in self._cache[path]: if path not in self._cache or index not in self._cache[path]:
return no_cache return no_cache
value, timestamp, validated = self._cache[path][index] value, timestamp, validated = self._cache[path][index]
if type_ == 'context_props': props = subconfig.config_bag.properties
# cached value is settings properties so value is props if type_ == 'self_props':
props = value # cached value is self_props
self_props = {} self_props = value
else: else:
props = subconfig.config_bag.properties self_props = subconfig.properties
if type_ == 'self_props':
# cached value is self_props
self_props = value
else:
self_props = subconfig.properties
if 'cache' in props or \ if 'cache' in props or \
'cache' in self_props: 'cache' in self_props:
if expiration and timestamp and \ if expiration and timestamp and \

View file

@ -23,6 +23,7 @@
import weakref import weakref
from copy import copy, deepcopy from copy import copy, deepcopy
from typing import Optional, List, Any, Union from typing import Optional, List, Any, Union
from os.path import commonprefix
from .error import PropertiesOptionError, ConfigError, ConflictError, \ from .error import PropertiesOptionError, ConfigError, ConflictError, \
LeadershipError LeadershipError
@ -35,6 +36,17 @@ from .autolib import Calculation
from . import autolib from . import autolib
def get_common_path(path1, path2):
common_path = commonprefix([path1, path2])
if common_path in [path1, path2]:
return common_path
if common_path.endswith('.'):
return common_path[:-1]
if '.' in common_path:
return common_path.rsplit('.', 1)[0]
return None
class CCache: class CCache:
__slots__ = tuple() __slots__ = tuple()
# ============================================================================= # =============================================================================
@ -171,6 +183,7 @@ class SubConfig:
'path', 'path',
'true_path', 'true_path',
'properties', 'properties',
'raises_properties',
'is_dynamic', 'is_dynamic',
'suffixes', 'suffixes',
'_length', '_length',
@ -187,8 +200,6 @@ class SubConfig:
properties: Union[list[str], undefined]=undefined, properties: Union[list[str], undefined]=undefined,
validate_properties: bool=True, validate_properties: bool=True,
) -> None: ) -> None:
if path and '.' in path and not parent:
raise Exception('pff connard')
self.index = index self.index = index
self.suffixes = suffixes self.suffixes = suffixes
self.option = option self.option = option
@ -198,12 +209,14 @@ class SubConfig:
self.path = path self.path = path
if true_path is None: if true_path is None:
true_path = path true_path = path
is_follower = not option.impl_is_optiondescription() and option.impl_is_follower()
apply_requires = not is_follower or index is not None
self.true_path = true_path self.true_path = true_path
settings = config_bag.context.get_settings()
if properties is undefined: if properties is undefined:
if path is None: if path is None:
self.properties = frozenset() self.properties = frozenset()
else: else:
settings = config_bag.context.get_settings()
self.properties = frozenset() self.properties = frozenset()
if validate_properties: if validate_properties:
self.properties = settings.getproperties(self, self.properties = settings.getproperties(self,
@ -211,7 +224,7 @@ class SubConfig:
) )
self.config_bag.context.get_settings().validate_properties(self) self.config_bag.context.get_settings().validate_properties(self)
self.properties = settings.getproperties(self, self.properties = settings.getproperties(self,
apply_requires=True, apply_requires=apply_requires,
) )
else: else:
self.properties = properties self.properties = properties
@ -221,6 +234,15 @@ class SubConfig:
self.is_dynamic = False self.is_dynamic = False
if validate_properties: if validate_properties:
self.config_bag.context.get_settings().validate_properties(self) self.config_bag.context.get_settings().validate_properties(self)
if self.option.impl_is_optiondescription():
if self.properties is not None:
self.raises_properties = settings.calc_raises_properties(self,
apply_requires=apply_requires,
not_unrestraint=True,
)
else:
self.raises_properties = frozenset()
def __repr__(self): def __repr__(self):
return f'<SubConfig path={self.path}, index={self.index}>' return f'<SubConfig path={self.path}, index={self.index}>'
@ -228,7 +250,8 @@ class SubConfig:
def dyn_to_subconfig(self, def dyn_to_subconfig(self,
child: Option, child: Option,
validate_properties: bool, validate_properties: bool,
follower_not_apply_requires: bool=False, *,
true_path: Optional[str]=None,
) -> List['SubConfig']: ) -> List['SubConfig']:
config_bag = self.config_bag config_bag = self.config_bag
for suffix in child.get_suffixes(self): for suffix in child.get_suffixes(self):
@ -241,10 +264,10 @@ class SubConfig:
yield self.get_child(child, yield self.get_child(child,
None, None,
validate_properties, validate_properties,
follower_not_apply_requires=follower_not_apply_requires,
suffix=suffix, suffix=suffix,
name=name, name=name,
properties=properties, properties=properties,
true_path=true_path,
) )
except PropertiesOptionError as err: except PropertiesOptionError as err:
if err.proptype in (['mandatory'], ['empty']): if err.proptype in (['mandatory'], ['empty']):
@ -298,7 +321,6 @@ class SubConfig:
validate_properties: bool, validate_properties: bool,
*, *,
properties=undefined, properties=undefined,
follower_not_apply_requires: bool=False,
allow_dynoption: bool=False, allow_dynoption: bool=False,
suffix: Optional[str]=None, suffix: Optional[str]=None,
name: Optional[str]=None, name: Optional[str]=None,
@ -312,24 +334,6 @@ class SubConfig:
if not self.option.impl_is_optiondescription(): if not self.option.impl_is_optiondescription():
raise TypeError(f'"{self.path}" is not an optiondescription') raise TypeError(f'"{self.path}" is not an optiondescription')
if check_index and index is not None:
if option.impl_is_optiondescription() or \
option.impl_is_symlinkoption() or \
not option.impl_is_follower():
raise ConfigError('index must be set only with a follower option')
length = self.get_length_leadership()
if index >= length:
raise LeadershipError(_(f'index "{index}" is greater than the leadership '
f'length "{length}" for option '
f'"{option.impl_get_display_name()}"'))
if properties is undefined and not validate_properties:
# not transitive property error
apply_requires = False
else:
apply_requires = not follower_not_apply_requires or \
option.impl_is_optiondescription() or \
not option.impl_is_follower()
path = self.get_path(name, path = self.get_path(name,
option, option,
) )
@ -340,16 +344,27 @@ class SubConfig:
suffixes = self.suffixes + [suffix] suffixes = self.suffixes + [suffix]
else: else:
suffixes = [suffix] suffixes = [suffix]
return SubConfig(option, subsubconfig = SubConfig(option,
index, index,
path, path,
self.config_bag, self.config_bag,
self, self,
suffixes, suffixes,
properties=properties, properties=properties,
validate_properties=validate_properties, validate_properties=validate_properties,
true_path=true_path, true_path=true_path,
) )
if check_index and index is not None:
if option.impl_is_optiondescription() or \
option.impl_is_symlinkoption() or \
not option.impl_is_follower():
raise ConfigError('index must be set only with a follower option')
length = self.get_length_leadership()
if index >= length:
raise LeadershipError(_(f'index "{index}" is greater than the leadership '
f'length "{length}" for option '
f'"{option.impl_get_display_name(subsubconfig)}"'))
return subsubconfig
def get_path(self, def get_path(self,
name: str, name: str,
@ -379,10 +394,77 @@ class SubConfig:
cconfig_bag, cconfig_bag,
self, self,
self.suffixes, self.suffixes,
validate_properties=False,
) )
self._length = len(cconfig_bag.context.get_value(subconfig)) self._length = len(cconfig_bag.context.get_value(subconfig))
return self._length return self._length
autolib.SubConfig = SubConfig
def get_common_child(self,
search_option: 'BaseOption',
true_path: Optional[str]=None,
validate_properties: bool=True,
):
current_option_path = self.option.impl_getpath()
search_option_path = search_option.impl_getpath()
common_path = get_common_path(current_option_path, search_option_path)
config_bag = self.config_bag
index = None
if not self.option.impl_is_optiondescription() and \
self.option.impl_is_follower() and search_option.impl_is_follower() and \
self.parent.option == search_option.impl_get_leadership():
index = self.index
search_child_number = 0
parents = [self.parent]
else:
if common_path:
parent = self.parent
common_parent_number = common_path.count('.') + 1
for idx in range(current_option_path.count('.') - common_parent_number):
parent = parent.parent
parents = [parent]
else:
common_parent_number = 0
parents = [config_bag.context.get_root(config_bag)]
search_child_number = search_option_path.count('.') - common_parent_number
subconfigs_is_a_list = False
if search_child_number:
if common_parent_number:
parent_paths = search_option_path.rsplit('.', search_child_number + 1)[1:-1]
else:
parent_paths = search_option_path.split('.')[:-1]
for parent_path in parent_paths:
new_parents = []
for parent in parents:
sub_option = parent.option.get_child(parent_path,
config_bag,
parent,
allow_dynoption=True,
)
if sub_option.impl_is_dynoptiondescription():
new_parents.extend(parent.dyn_to_subconfig(sub_option,
True,
true_path=true_path,
)
)
subconfigs_is_a_list = True
else:
new_parents.append(parent.get_child(sub_option,
None,
validate_properties,
true_path=true_path,
)
)
parents = new_parents
subconfigs = []
for parent in parents:
subconfigs.append(parent.get_child(search_option,
index,
validate_properties,
)
)
if subconfigs_is_a_list:
return subconfigs
return subconfigs[0]
class _Config(CCache): class _Config(CCache):
@ -486,7 +568,6 @@ class _Config(CCache):
path, path,
None, None,
validate_properties=True, validate_properties=True,
follower_not_apply_requires=False,
) )
except PropertiesOptionError: except PropertiesOptionError:
continue continue
@ -541,7 +622,6 @@ class _Config(CCache):
index, index,
*, *,
validate_properties: bool=True, validate_properties: bool=True,
follower_not_apply_requires: bool=False,
properties=undefined, properties=undefined,
true_path: Optional[str]=None, true_path: Optional[str]=None,
): ):
@ -577,7 +657,6 @@ class _Config(CCache):
subconfig = subconfig.get_child(option, subconfig = subconfig.get_child(option,
index_, index_,
validate_properties, validate_properties,
follower_not_apply_requires=follower_not_apply_requires,
properties=properties, properties=properties,
name=name, name=name,
suffix=suffix, suffix=suffix,
@ -647,17 +726,6 @@ class _Config(CCache):
# ============================================================================= # =============================================================================
# Manage value # Manage value
def set_value(self,
subconfig: SubConfig,
value: Any,
) -> Any:
"""set value
"""
self.get_settings().validate_properties(subconfig)
return self.get_values().set_value(subconfig,
value
)
def get_value(self, def get_value(self,
subconfig, subconfig,
need_help=True, need_help=True,
@ -672,8 +740,9 @@ class _Config(CCache):
if isinstance(subconfig, list): if isinstance(subconfig, list):
value = [] value = []
follower_subconfig = None follower_subconfig = None
is_follower = not subconfig or subconfig[0].option.impl_is_follower()
for sconfig in subconfig: for sconfig in subconfig:
if follower_subconfig is None: if not is_follower or follower_subconfig is None:
follower_subconfig = self.get_sub_config(sconfig.config_bag, follower_subconfig = self.get_sub_config(sconfig.config_bag,
sconfig.path, sconfig.path,
sconfig.index, sconfig.index,
@ -692,7 +761,7 @@ class _Config(CCache):
length = subconfig.parent.get_length_leadership() length = subconfig.parent.get_length_leadership()
follower_len = self.get_values().get_max_length(subconfig.path) follower_len = self.get_values().get_max_length(subconfig.path)
if follower_len > length: if follower_len > length:
option_name = subconfig.option.impl_get_display_name() option_name = subconfig.option.impl_get_display_name(subconfig)
raise LeadershipError(_(f'the follower option "{option_name}" ' raise LeadershipError(_(f'the follower option "{option_name}" '
f'has greater length ({follower_len}) than the leader ' f'has greater length ({follower_len}) than the leader '
f'length ({length})')) f'length ({length})'))
@ -704,6 +773,7 @@ class _Config(CCache):
def _get(self, def _get(self,
subconfig: "SubConfig", subconfig: "SubConfig",
need_help: bool, need_help: bool,
validate_properties: bool=True,
) -> "OptionBag": ) -> "OptionBag":
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
option = subconfig.option option = subconfig.option
@ -712,17 +782,15 @@ class _Config(CCache):
suboption = option.impl_getopt() suboption = option.impl_getopt()
if suboption.issubdyn(): if suboption.issubdyn():
dynopt = suboption.getsubdyn() dynopt = suboption.getsubdyn()
return list(dynopt.get_sub_children(suboption, return subconfig.get_common_child(suboption,
suboption.config_bag, true_path=subconfig.path,
index=suboption.index, validate_properties=validate_properties,
true_path=subconfig.path, )
))
if suboption.impl_is_follower(): if suboption.impl_is_follower():
subconfig = self.get_sub_config(subconfig.config_bag, # pylint: disable=no-member subconfig = self.get_sub_config(subconfig.config_bag, # pylint: disable=no-member
suboption.impl_getpath(), suboption.impl_getpath(),
None, None,
validate_properties=True, validate_properties=validate_properties,
follower_not_apply_requires=False,
true_path=subconfig.path, true_path=subconfig.path,
) )
leadership_length = subconfig.parent.get_length_leadership() leadership_length = subconfig.parent.get_length_leadership()
@ -739,8 +807,7 @@ class _Config(CCache):
s_subconfig = self.get_sub_config(subconfig.config_bag, # pylint: disable=no-member s_subconfig = self.get_sub_config(subconfig.config_bag, # pylint: disable=no-member
suboption.impl_getpath(), suboption.impl_getpath(),
None, None,
validate_properties=True, validate_properties=validate_properties,
follower_not_apply_requires=False,
true_path=subconfig.path, true_path=subconfig.path,
) )
return self._get(s_subconfig, return self._get(s_subconfig,
@ -818,6 +885,7 @@ class _CommonConfig(_Config):
self.reset_cache(option_bag) self.reset_cache(option_bag)
def impl_get_information(self, def impl_get_information(self,
subconfig,
key, key,
default, default,
): ):
@ -893,7 +961,7 @@ class _CommonConfig(_Config):
duplicated_settings.rw_append = self.get_settings().rw_append duplicated_settings.rw_append = self.get_settings().rw_append
duplicated_settings.ro_remove = self.get_settings().ro_remove duplicated_settings.ro_remove = self.get_settings().ro_remove
duplicated_settings.rw_remove = self.get_settings().rw_remove duplicated_settings.rw_remove = self.get_settings().rw_remove
duplicated_settings.default_properties = self.get_settings().default_properties # duplicated_settings.default_properties = self.get_settings().default_properties
duplicated_config.reset_cache(None, None) duplicated_config.reset_cache(None, None)
if child is not None: if child is not None:
duplicated_config._impl_children.append(child) # pylint: disable=protected-access duplicated_config._impl_children.append(child) # pylint: disable=protected-access
@ -1412,7 +1480,7 @@ class KernelMixConfig(KernelGroupConfig):
) )
# Copy context properties/permissives # Copy context properties/permissives
settings = config.get_settings() settings = config.get_settings()
properties = settings.get_context_properties(config.properties_cache) properties = settings.get_context_properties()
settings.set_context_properties(properties, settings.set_context_properties(properties,
config, config,
) )
@ -1421,7 +1489,7 @@ class KernelMixConfig(KernelGroupConfig):
settings.rw_append = settings.rw_append settings.rw_append = settings.rw_append
settings.ro_remove = settings.ro_remove settings.ro_remove = settings.ro_remove
settings.rw_remove = settings.rw_remove settings.rw_remove = settings.rw_remove
settings.default_properties = settings.default_properties # settings.default_properties = settings.default_properties
config.parents.append(weakref.ref(self)) config.parents.append(weakref.ref(self))
self._impl_children.append(config) self._impl_children.append(config)

View file

@ -70,8 +70,9 @@ class PropertiesOptionError(AttributeError):
self._opt_type = 'optiondescription' self._opt_type = 'optiondescription'
else: else:
self._opt_type = 'option' self._opt_type = 'option'
self._name = subconfig.option.impl_get_display_name() self._name = subconfig.option.impl_get_display_name(subconfig)
self._orig_opt = None self._orig_opt = None
self._subconfig = subconfig
self.proptype = proptype self.proptype = proptype
self.help_properties = help_properties self.help_properties = help_properties
self._settings = settings self._settings = settings
@ -108,8 +109,9 @@ class PropertiesOptionError(AttributeError):
else: else:
msg = 'cannot access to {0} "{1}" because has {2} {3}' msg = 'cannot access to {0} "{1}" because has {2} {3}'
if self._orig_opt: if self._orig_opt:
# FIXME _orig_opt ?
self.msg = _(msg).format(self._opt_type, self.msg = _(msg).format(self._opt_type,
self._orig_opt.impl_get_display_name(), self._orig_opt.impl_get_display_name(subconfig),
self._name, self._name,
prop_msg, prop_msg,
properties_msg) properties_msg)
@ -156,6 +158,7 @@ class ConstError(TypeError):
class _CommonError: class _CommonError:
def __init__(self, def __init__(self,
subconfig,
val, val,
display_type, display_type,
opt, opt,
@ -164,7 +167,7 @@ class _CommonError:
self.val = val self.val = val
self.display_type = display_type self.display_type = display_type
self.opt = weakref.ref(opt) self.opt = weakref.ref(opt)
self.name = opt.impl_get_display_name() self.name = opt.impl_get_display_name(subconfig)
self.err_msg = err_msg self.err_msg = err_msg
self.index = index self.index = index
super().__init__(self.err_msg) super().__init__(self.err_msg)

View file

@ -944,7 +944,7 @@ msgstr "option \"{0}\" inconnue dans l'optiondescription \"{1}\""
#: tiramisu/option/optiondescription.py:279 #: tiramisu/option/optiondescription.py:279
msgid "children in optiondescription \"{}\" must be a list" msgid "children in optiondescription \"{}\" must be a list"
msgstr "les enfants d'une optiondescription \"{}\" doit être une liste" msgstr "les enfants d'une optiondescription \"{}\" doivent être une liste"
#: tiramisu/option/optiondescription.py:303 #: tiramisu/option/optiondescription.py:303
msgid "duplicate option name: \"{0}\"" msgid "duplicate option name: \"{0}\""

View file

@ -20,14 +20,14 @@
# ____________________________________________________________ # ____________________________________________________________
"""base option """base option
""" """
from typing import FrozenSet, Set, Any, List from typing import FrozenSet, Set, Any, List, Optional, Dict
import weakref import weakref
from itertools import chain from itertools import chain
from ..i18n import _ from ..i18n import _
from ..setting import undefined from ..setting import undefined
from ..autolib import Calculation, ParamOption from ..autolib import Calculation, ParamOption, ParamInformation, ParamSelfInformation
STATIC_TUPLE = frozenset() STATIC_TUPLE = frozenset()
@ -57,6 +57,7 @@ class Base:
'_properties', '_properties',
'_has_dependency', '_has_dependency',
'_dependencies', '_dependencies',
'_dependencies_information',
'_suffixes_dependencies', '_suffixes_dependencies',
'__weakref__' '__weakref__'
) )
@ -64,8 +65,11 @@ class Base:
def __init__(self, def __init__(self,
name: str, name: str,
doc: str, doc: str,
informations: Optional[Dict],
*,
properties=None, properties=None,
is_multi: bool=False) -> None: is_multi: bool=False,
) -> None:
if not valid_name(name): if not valid_name(name):
raise ValueError(_('"{0}" is an invalid name for an option').format(name)) raise ValueError(_('"{0}" is an invalid name for an option').format(name))
if properties is None: if properties is None:
@ -83,6 +87,9 @@ class Base:
assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},' assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
' must be a frozenset').format(type(properties), ' must be a frozenset').format(type(properties),
name) name)
_setattr = object.__setattr__
_setattr(self, '_name', name)
_setattr(self, '_informations', {'doc': doc})
for prop in properties: for prop in properties:
if not isinstance(prop, str): if not isinstance(prop, str):
if not isinstance(prop, Calculation): if not isinstance(prop, Calculation):
@ -91,11 +98,19 @@ class Base:
for param in chain(prop.params.args, prop.params.kwargs.values()): for param in chain(prop.params.args, prop.params.kwargs.values()):
if isinstance(param, ParamOption): if isinstance(param, ParamOption):
param.option._add_dependency(self) param.option._add_dependency(self)
_setattr = object.__setattr__
_setattr(self, '_name', name)
_setattr(self, '_informations', {'doc': doc})
if properties: if properties:
_setattr(self, '_properties', properties) _setattr(self, '_properties', properties)
self.set_informations(informations)
def set_informations(self,
informations: Optional[Dict],
) -> None:
if not informations:
return
for key, value in informations.items():
self._set_information(key,
value,
)
def impl_has_dependency(self, def impl_has_dependency(self,
self_is_dep: bool=True, self_is_dep: bool=True,
@ -196,10 +211,11 @@ class Base:
# ____________________________________________________________ # ____________________________________________________________
# information # information
def impl_get_information(self, def _get_information(self,
key: str, subconfig: "SubConfig",
default: Any=undefined, key: str,
) -> Any: default: Any=undefined,
) -> Any:
"""retrieves one information's item """retrieves one information's item
:param key: the item string (ex: "help") :param key: the item string (ex: "help")
@ -217,13 +233,13 @@ class Base:
if default is not undefined: if default is not undefined:
return default return default
# pylint: disable=no-member # pylint: disable=no-member
raise ValueError(_(f'information\'s item for "{self.impl_get_display_name()}" ' raise ValueError(_(f'information\'s item for "{self.impl_get_display_name(subconfig)}" '
f'not found: "{key}"')) f'not found: "{key}"'))
def impl_set_information(self, def _set_information(self,
key: str, key: str,
value: Any, value: Any,
) -> None: ) -> None:
"""updates the information's attribute """updates the information's attribute
(which is a dictionary) (which is a dictionary)
@ -237,13 +253,13 @@ class Base:
key)) key))
self._informations[key] = value # pylint: disable=no-member self._informations[key] = value # pylint: disable=no-member
def impl_list_information(self) -> Any: def _list_information(self) -> Any:
"""get the list of information keys """get the list of information keys
""" """
dico = self._informations # pylint: disable=no-member dico = self._informations # pylint: disable=no-member
if isinstance(dico, tuple): if isinstance(dico, tuple):
return list(dico[0]) return list(dico[0])
if isinstance(dico, str): if not isinstance(dico, dict):
return ['doc'] return ['doc']
# it's a dict # it's a dict
return list(dico.keys()) return list(dico.keys())
@ -272,7 +288,7 @@ class BaseOption(Base):
if self.impl_is_readonly(): if self.impl_is_readonly():
raise AttributeError(_('"{}" ({}) object attribute "{}" is' raise AttributeError(_('"{}" ({}) object attribute "{}" is'
' read-only').format(self.__class__.__name__, ' read-only').format(self.__class__.__name__,
self.impl_get_display_name(), self.impl_get_display_name(None),
name)) name))
super().__setattr__(name, value) super().__setattr__(name, value)
@ -282,21 +298,22 @@ class BaseOption(Base):
try: try:
return self._path return self._path
except AttributeError as err: except AttributeError as err:
raise AttributeError(_(f'"{self.impl_get_display_name()}" not part of any Config')) \ raise AttributeError(_(f'"{self.impl_get_display_name(None)}" not part of any Config')) \
from err from err
def impl_get_display_name(self, def impl_get_display_name(self,
dynopt=None, subconfig: "SubConfig",
) -> str: ) -> str:
"""get display name """get display name
""" """
if dynopt is None:
dynopt = self
if hasattr(self, '_display_name_function'): if hasattr(self, '_display_name_function'):
return self._display_name_function(dynopt) return self._display_name_function(self, subconfig)
name = self.impl_get_information('doc', None) name = self._get_information(subconfig, 'doc', None)
if name is None or name == '': if name is None or name == '':
name = dynopt.impl_getname() if subconfig and subconfig.path:
name = subconfig.path.rsplit('.', 1)[-1]
else:
name = self._name
return name return name
def reset_cache(self, def reset_cache(self,
@ -322,33 +339,43 @@ class BaseOption(Base):
""" """
return getattr(self, '_dependencies_information', {}) return getattr(self, '_dependencies_information', {})
def to_sub_dyoption(self, def value_dependencies(self,
suffixes: list[str], value: Any,
): is_suffix: bool=False,
sub_dyn = self ) -> Any:
# retrieve all subdyn options """parse dependancies to add dependencies
sub_dyns = [] """
while True: if isinstance(value, list):
sub_dyn = sub_dyn.getsubdyn() for val in value:
sub_dyns.append(sub_dyn) if isinstance(value, list):
if not sub_dyn.issubdyn(): self.value_dependencies(val, is_suffix)
break elif isinstance(value, Calculation):
paths = [] self.value_dependency(val, is_suffix)
parent_path = self.impl_getpath().rsplit('.', 1)[0] elif isinstance(value, Calculation):
suffix_idx = len(sub_dyns) - 1 self.value_dependency(value, is_suffix)
for sub_dyn in sub_dyns:
dyn_path = sub_dyn.impl_getpath() def value_dependency(self,
if dyn_path.count('.') == parent_path.count('.'): value: Any,
*root_paths, dyn_path_ = parent_path.split('.', dyn_path.count('.') + 1) is_suffix: bool=False,
else: ) -> Any:
*root_paths, dyn_path_, child_path = parent_path.split('.', dyn_path.count('.') + 1) """parse dependancy to add dependencies
paths.insert(0, child_path) """
paths.insert(0, sub_dyn.impl_getname(suffixes[suffix_idx])) for param in chain(value.params.args, value.params.kwargs.values()):
suffix_idx -= 1 if isinstance(param, ParamOption):
parent_path = '.'.join(root_paths) # pylint: disable=protected-access
if parent_path: param.option._add_dependency(self, is_suffix=is_suffix)
paths.insert(0, parent_path) self._has_dependency = True
full_parent_path = '.'.join(paths) elif isinstance(param, ParamInformation):
return self.to_dynoption(full_parent_path, dest = self
suffixes, if isinstance(param, ParamSelfInformation):
) opt = weakref.ref(self)
elif param.option:
dest = param.option
opt = weakref.ref(self)
else:
param.set_self_option(self)
opt = None
if not getattr(dest, '_dependencies_information', {}):
dest._dependencies_information = {None: []}
dest._dependencies_information[None].append(param)
dest._dependencies_information.setdefault(param.information_name, []).append(opt)

View file

@ -25,7 +25,7 @@ from typing import Any
from ..setting import undefined from ..setting import undefined
from ..i18n import _ from ..i18n import _
from .option import Option from .option import Option
from ..autolib import Calculation from ..autolib import Calculation, get_calculated_value
from ..error import ConfigError, display_list from ..error import ConfigError, display_list
@ -61,13 +61,16 @@ class ChoiceOption(Option):
): ):
"""get values allowed by option """get values allowed by option
""" """
if isinstance(self._choice_values, Calculation): choices = self._choice_values
values = self._choice_values.execute(subconfig) if isinstance(choices, tuple):
if values is not undefined and not isinstance(values, list): choices = list(choices)
raise ConfigError(_('the calculated values "{0}" for "{1}" is not a list' values = get_calculated_value(subconfig,
'').format(values, self.impl_getname())) choices,
else: )[0]
values = self._choice_values
if values != undefined and not isinstance(values, (list, tuple)):
raise ConfigError(_('the calculated values "{0}" for "{1}" is not a list'
'').format(values, self.impl_getname()))
return values return values
def validate(self, def validate(self,

View file

@ -20,22 +20,23 @@
# ____________________________________________________________ # ____________________________________________________________
"""DynOptionDescription """DynOptionDescription
""" """
import re
import weakref import weakref
from typing import List, Any, Optional from typing import List, Any, Optional, Dict
from itertools import chain from itertools import chain
from ..autolib import ParamOption from ..autolib import ParamOption
from ..i18n import _ from ..i18n import _
from .optiondescription import OptionDescription from .optiondescription import OptionDescription
from .syndynoption import CommonDyn #, SynDynLeadership
from .baseoption import BaseOption from .baseoption import BaseOption
from ..setting import ConfigBag, undefined from ..setting import ConfigBag, undefined
from ..error import ConfigError from ..error import ConfigError
from ..autolib import Calculation from ..autolib import Calculation, get_calculated_value
class DynOptionDescription(OptionDescription, CommonDyn): NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
class DynOptionDescription(OptionDescription):
"""dyn option description """dyn option description
""" """
__slots__ = ('_suffixes', __slots__ = ('_suffixes',
@ -48,25 +49,28 @@ class DynOptionDescription(OptionDescription, CommonDyn):
children: List[BaseOption], children: List[BaseOption],
suffixes: Calculation, suffixes: Calculation,
properties=None, properties=None,
informations: Optional[Dict]=None,
) -> None: ) -> None:
# pylint: disable=too-many-arguments # pylint: disable=too-many-arguments
super().__init__(name, super().__init__(name,
doc, doc,
children, children,
properties, properties,
informations=informations,
) )
# check children + set relation to this dynoptiondescription # check children + set relation to this dynoptiondescription
wself = weakref.ref(self) wself = weakref.ref(self)
for child in children: for child in children:
child._setsubdyn(wself) child._setsubdyn(wself)
# add suffixes # add suffixes
if __debug__ and not isinstance(suffixes, Calculation): self.value_dependencies(suffixes, is_suffix=True)
raise ConfigError(_('suffixes in dynoptiondescription has to be a calculation')) # if __debug__ and not isinstance(suffixes, Calculation):
for param in chain(suffixes.params.args, suffixes.params.kwargs.values()): # raise ConfigError(_('suffixes in dynoptiondescription has to be a calculation'))
if isinstance(param, ParamOption): # for param in chain(suffixes.params.args, suffixes.params.kwargs.values()):
param.option._add_dependency(self, # if isinstance(param, ParamOption):
is_suffix=True, # param.option._add_dependency(self,
) # is_suffix=True,
# )
self._suffixes = suffixes self._suffixes = suffixes
def convert_suffix_to_path(self, def convert_suffix_to_path(self,
@ -98,3 +102,42 @@ class DynOptionDescription(OptionDescription, CommonDyn):
return name return name
path_suffix = self.convert_suffix_to_path(suffix) path_suffix = self.convert_suffix_to_path(suffix)
return name + path_suffix return name + path_suffix
def get_suffixes(self,
parent: 'SubConfig',
) -> List[str]:
"""get dynamic suffixes
"""
subconfig = parent.get_child(self,
None,
False,
properties=None,
)
suffixes = self._suffixes
if isinstance(suffixes, list):
suffixes = suffixes.copy()
values = get_calculated_value(subconfig,
suffixes,
validate_properties=False,
)[0]
if values is None:
values = []
values_ = []
if __debug__:
if not isinstance(values, list):
raise ValueError(_('DynOptionDescription suffixes for '
f'option "{self.impl_get_display_name(subconfig)}", is not '
f'a list ({values})'))
for val in values:
cval = self.convert_suffix_to_path(val)
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
if __debug__ and cval is not None:
raise ValueError(_('invalid suffix "{}" for option "{}"'
'').format(cval,
self.impl_get_display_name(subconfig)))
else:
values_.append(val)
if __debug__ and len(values_) > len(set(values_)):
raise ValueError(_(f'DynOptionDescription "{self._name}" suffixes return a list with '
f'same values "{values_}"'''))
return values_

View file

@ -75,15 +75,15 @@ class Leadership(OptionDescription):
def _check_child_is_valid(self, child: BaseOption): def _check_child_is_valid(self, child: BaseOption):
if child.impl_is_symlinkoption(): if child.impl_is_symlinkoption():
raise ValueError(_('leadership "{0}" shall not have ' raise ValueError(_('leadership "{0}" shall not have '
"a symlinkoption").format(self.impl_get_display_name())) "a symlinkoption").format(self.impl_get_display_name(None)))
if not isinstance(child, Option): if not isinstance(child, Option):
raise ValueError(_('leadership "{0}" shall not have ' raise ValueError(_('leadership "{0}" shall not have '
'a subgroup').format(self.impl_get_display_name())) 'a subgroup').format(self.impl_get_display_name(None)))
if not child.impl_is_multi(): if not child.impl_is_multi():
raise ValueError(_('only multi option allowed in leadership "{0}" but option ' raise ValueError(_('only multi option allowed in leadership "{0}" but option '
'"{1}" is not a multi' '"{1}" is not a multi'
'').format(self.impl_get_display_name(), '').format(self.impl_get_display_name(None),
child.impl_get_display_name())) child.impl_get_display_name(None)))
def _check_default_value(self, child: BaseOption): def _check_default_value(self, child: BaseOption):
default = child.impl_getdefault() default = child.impl_getdefault()
@ -100,8 +100,8 @@ class Leadership(OptionDescription):
calculation = isinstance(default, Calculation) calculation = isinstance(default, Calculation)
if not calculation: if not calculation:
raise ValueError(_('not allowed default value for follower option ' raise ValueError(_('not allowed default value for follower option '
f'"{child.impl_get_display_name()}" in leadership ' f'"{child.impl_get_display_name(None)}" in leadership '
f'"{self.impl_get_display_name()}"')) f'"{self.impl_get_display_name(None)}"'))
def _setsubdyn(self, def _setsubdyn(self,
subdyn, subdyn,
@ -143,58 +143,54 @@ class Leadership(OptionDescription):
def reset(self, parent: "SubConfig") -> None: def reset(self, parent: "SubConfig") -> None:
"""reset follower value """reset follower value
""" """
#config_bag = parent.option_bag.config_bag
values = parent.config_bag.context.get_values() values = parent.config_bag.context.get_values()
#config_bag = config_bag.copy()
#config_bag.remove_validation()
for follower in self.get_followers(): for follower in self.get_followers():
subconfig_follower = parent.get_child(follower, subconfig_follower = parent.get_child(follower,
None, None,
False, False,
) )
# OptionBag(follower, values.reset(subconfig_follower,
# None, validate=False,
# config_bag, )
# )
values.reset(subconfig_follower) def follower_force_store_value(self,
# value,
# def follower_force_store_value(self, subconfig: 'SubConfig',
# value, owner,
# config_bag: 'ConfigBag', ) -> None:
# owner, """apply force_store_value to follower
# dyn=None, """
# ) -> None: if not value:
# """apply force_store_value to follower return
# """ config_bag = subconfig.config_bag
# if value: values = config_bag.context.get_values()
# if dyn is None: for idx, follower in enumerate(self.get_children()):
# dyn = self sub_subconfig = subconfig.get_child(follower,
# values = config_bag.context.get_values() None,
# for idx, follower in enumerate(dyn.get_children(config_bag)): False,
# if not idx: config_bag=config_bag,
# # it's a master )
# apply_requires = True if 'force_store_value' not in sub_subconfig.properties:
# indexes = [None] continue
# else: self_path = sub_subconfig.path
# apply_requires = False if not idx:
# indexes = range(len(value)) # it's a master
# foption_bag = OptionBag(follower, apply_requires = True
# None, indexes = [None]
# config_bag, else:
# apply_requires=apply_requires, apply_requires = False
# ) indexes = range(len(value))
# if 'force_store_value' not in foption_bag.properties: for index in indexes:
# continue i_sub_subconfig = subconfig.get_child(follower,
# for index in indexes: index,
# foption_bag_index = OptionBag(follower, False,
# index, config_bag=config_bag,
# config_bag, )
# ) values.set_storage_value(self_path,
# values.set_storage_value(foption_bag_index.path, index,
# index, values.get_value(i_sub_subconfig)[0],
# values.get_value(foption_bag_index)[0], owner,
# owner, )
# )
def pop(self, def pop(self,
subconfig: 'SubConfig', subconfig: 'SubConfig',

View file

@ -26,9 +26,8 @@ from itertools import chain
from .baseoption import BaseOption, submulti from .baseoption import BaseOption, submulti
from ..i18n import _ from ..i18n import _
from ..setting import undefined from ..setting import undefined
from ..autolib import Calculation, ParamOption, ParamInformation, ParamSelfInformation from ..autolib import Calculation
from ..error import ValueWarning, ValueErrorWarning, ValueOptionError from ..error import ValueWarning, ValueErrorWarning, ValueOptionError
from .syndynoption import SynDynOption
class Option(BaseOption): class Option(BaseOption):
@ -48,7 +47,6 @@ class Option(BaseOption):
# #
'_validators', '_validators',
# #
'_dependencies_information',
'_leadership', '_leadership',
'_choice_values', '_choice_values',
'_choice_values_params', '_choice_values_params',
@ -63,7 +61,9 @@ class Option(BaseOption):
validators: Optional[List[Calculation]]=None, validators: Optional[List[Calculation]]=None,
properties: Optional[List[str]]=None, properties: Optional[List[str]]=None,
warnings_only: bool=False, warnings_only: bool=False,
extra: Optional[Dict]=None): extra: Optional[Dict]=None,
informations: Optional[Dict]=None,
):
_setattr = object.__setattr__ _setattr = object.__setattr__
if not multi and default_multi is not None: if not multi and default_multi is not None:
raise ValueError(_("default_multi is set whereas multi is False" raise ValueError(_("default_multi is set whereas multi is False"
@ -92,8 +92,10 @@ class Option(BaseOption):
default = [] default = []
super().__init__(name, super().__init__(name,
doc, doc,
informations,
properties=properties, properties=properties,
is_multi=is_multi) is_multi=is_multi,
)
if validators is not None: if validators is not None:
if __debug__ and not isinstance(validators, list): if __debug__ and not isinstance(validators, list):
raise ValueError(_(f'validators must be a list of Calculation for "{name}"')) raise ValueError(_(f'validators must be a list of Calculation for "{name}"'))
@ -126,10 +128,10 @@ class Option(BaseOption):
if not str_err: if not str_err:
raise ValueError(_('invalid default_multi value "{0}" ' raise ValueError(_('invalid default_multi value "{0}" '
'for option "{1}"').format(str(value), 'for option "{1}"').format(str(value),
self.impl_get_display_name()) self.impl_get_display_name(None))
) from err ) from err
raise ValueError(_(f'invalid default_multi value "{value}" for option ' raise ValueError(_(f'invalid default_multi value "{value}" for option '
f'"{self.impl_get_display_name()}", {str_err}') f'"{self.impl_get_display_name(None)}", {str_err}')
) from err ) from err
if _multi is submulti: if _multi is submulti:
if not isinstance(default_multi, Calculation): if not isinstance(default_multi, Calculation):
@ -137,7 +139,7 @@ class Option(BaseOption):
raise ValueError(_('invalid default_multi value "{0}" ' raise ValueError(_('invalid default_multi value "{0}" '
'for option "{1}", must be a list for a submulti' 'for option "{1}", must be a list for a submulti'
'').format(str(default_multi), '').format(str(default_multi),
self.impl_get_display_name())) self.impl_get_display_name(None)))
for value in default_multi: for value in default_multi:
test_multi_value(value) test_multi_value(value)
else: else:
@ -164,43 +166,6 @@ class Option(BaseOption):
default = tuple(default) default = tuple(default)
_setattr(self, '_default', default) _setattr(self, '_default', default)
def value_dependencies(self,
value: Any,
) -> Any:
"""parse dependancies to add dependencies
"""
if isinstance(value, list):
for val in value:
if isinstance(value, list):
self.value_dependencies(val)
elif isinstance(value, Calculation):
self.value_dependency(val)
elif isinstance(value, Calculation):
self.value_dependency(value)
def value_dependency(self,
value: Any,
) -> Any:
"""parse dependancy to add dependencies
"""
for param in chain(value.params.args, value.params.kwargs.values()):
if isinstance(param, ParamOption):
# pylint: disable=protected-access
param.option._add_dependency(self)
self._has_dependency = True
elif isinstance(param, ParamInformation):
dest = self
if isinstance(param, ParamSelfInformation):
opt = self
elif param.option:
dest = param.option
opt = self
else:
opt = None
if not getattr(dest, '_dependencies_information', {}):
dest._dependencies_information = {}
dest._dependencies_information.setdefault(param.information_name, []).append(opt)
#__________________________________________________________________________ #__________________________________________________________________________
# option's information # option's information
@ -326,7 +291,8 @@ class Option(BaseOption):
**kwargs, **kwargs,
) )
except ValueWarning as warn: except ValueWarning as warn:
warnings.warn_explicit(ValueWarning(val, warnings.warn_explicit(ValueWarning(subconfig,
val,
self.get_type(), self.get_type(),
self, self,
str(warn), str(warn),
@ -343,7 +309,7 @@ class Option(BaseOption):
return return
if isinstance(_value, list): if isinstance(_value, list):
raise ValueError(_('which must not be a list').format(_value, raise ValueError(_('which must not be a list').format(_value,
self.impl_get_display_name()), self.impl_get_display_name(subconfig)),
) )
if isinstance(_value, Calculation) and not subconfig: if isinstance(_value, Calculation) and not subconfig:
return return
@ -361,7 +327,8 @@ class Option(BaseOption):
is_warnings_only) is_warnings_only)
except ValueError as err: except ValueError as err:
if is_warnings_only: if is_warnings_only:
warnings.warn_explicit(ValueWarning(_value, warnings.warn_explicit(ValueWarning(subconfig,
_value,
self.get_type(), self.get_type(),
self, self,
str(err), str(err),
@ -420,12 +387,14 @@ class Option(BaseOption):
except ValueError as err: except ValueError as err:
if not subconfig or \ if not subconfig or \
'demoting_error_warning' not in subconfig.config_bag.properties: 'demoting_error_warning' not in subconfig.config_bag.properties:
raise ValueOptionError(val, raise ValueOptionError(subconfig,
val,
self.get_type(), self.get_type(),
self, self,
str(err), str(err),
err_index) from err err_index) from err
warnings.warn_explicit(ValueErrorWarning(val, warnings.warn_explicit(ValueErrorWarning(subconfig,
val,
self.get_type(), self.get_type(),
self, self,
str(err), str(err),
@ -476,16 +445,6 @@ class Option(BaseOption):
#pylint: disable=not-callable #pylint: disable=not-callable
return leadership() return leadership()
def to_dynoption(self,
rootpath: str,
suffixes: list[str],
) -> SynDynOption:
"""tranforme a dynoption to a syndynoption
"""
return SynDynOption(self,
rootpath,
suffixes,
)
def validate(self, value: Any): def validate(self, value: Any):
"""option needs a validate function """option needs a validate function
""" """

View file

@ -21,7 +21,7 @@
"""OptionDescription """OptionDescription
""" """
import weakref import weakref
from typing import Optional, Iterator, Union, List from typing import Optional, Iterator, Union, List, Dict
from ..i18n import _ from ..i18n import _
@ -87,6 +87,10 @@ class CacheOptionDescription(BaseOption):
dependencies_information, dependencies_information,
) )
else: else:
informations = option.get_dependencies_information()
if informations:
for param in informations.pop(None):
del param.self_option
for information, options in option.get_dependencies_information().items(): for information, options in option.get_dependencies_information().items():
if None in options: if None in options:
dependencies_information.setdefault(information, []).append(option) dependencies_information.setdefault(information, []).append(option)
@ -105,71 +109,86 @@ class CacheOptionDescription(BaseOption):
self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init
self._path = None # pylint: disable=attribute-defined-outside-init,no-member self._path = None # pylint: disable=attribute-defined-outside-init,no-member
self._set_readonly() self._set_readonly()
#
# def impl_build_force_store_values(self, def impl_build_force_store_values(self,
# config_bag: ConfigBag, config_bag: ConfigBag,
# ) -> None: ) -> None:
# """set value to force_store_values option """set value to force_store_values option
# """ """
# # pylint: disable=too-many-branches # pylint: disable=too-many-branches
# def do_option_bags(option): context = config_bag.context
# if option.issubdyn(): if 'force_store_value' not in config_bag.properties:
# dynopt = option.getsubdyn() return
# yield from dynopt.get_sub_children(option,
# config_bag, values = config_bag.context.get_values()
# index=None, for option in self._cache_force_store_values:
# ) if option.issubdyn():
# else: paths = option.impl_getpath().split('.')
# yield OptionBag(option, parents = [config_bag.context.get_root(config_bag)]
# None, for name in paths:
# config_bag, new_parents = []
# properties=None, for parent in parents:
# ) doption = parent.option.get_child(name,
# if 'force_store_value' not in config_bag.properties: config_bag,
# return parent,
# values = config_bag.context.get_values() allow_dynoption=True,
# for option in self._cache_force_store_values: )
# if option.impl_is_follower(): if doption.impl_is_dynoptiondescription():
# leader = option.impl_get_leadership().get_leader() new_parents.extend(parent.dyn_to_subconfig(doption,
# for leader_option_bag in do_option_bags(leader): True,
# leader_option_bag.properties = frozenset() )
# follower_len = len(values.get_value(leader_option_bag)[0]) )
# if option.issubdyn(): else:
# doption = option.to_dynoption(leader_option_bag.option.rootpath, new_parents.append(parent.get_child(doption,
# leader_option_bag.option.get_current_suffixes(), None,
# ) True,
# else: name=name,
# doption = option ))
# subpath = doption.impl_getpath() parents = new_parents
# for index in range(follower_len): subconfigs = new_parents
# option_bag = OptionBag(doption, else:
# index, subconfigs = [context.get_sub_config(config_bag,
# config_bag, option.impl_getpath(),
# properties=frozenset(), None,
# ) properties=None,
# if values.hasvalue(subpath, index=index): validate_properties=False,
# continue )]
# value = values.get_value(option_bag)[0]
# if value is None: if option.impl_is_follower():
# continue for follower_subconfig in subconfigs:
# values.set_storage_value(subpath, parent = follower_subconfig.parent
# index, follower_len = parent.get_length_leadership()
# value, for index in range(follower_len):
# owners.forced, if values.hasvalue(follower_subconfig.path,
# ) index=index,
# else: ):
# for option_bag in do_option_bags(option): continue
# option_bag.properties = frozenset() idx_follower_subconfig = parent.get_child(follower_subconfig.option,
# value = values.get_value(option_bag)[0] index,
# if value is None: validate_properties=False,
# continue )
# if values.hasvalue(option_bag.path):
# continue value = values.get_value(idx_follower_subconfig)[0]
# values.set_storage_value(option_bag.path, if value is None:
# None, continue
# value, values.set_storage_value(follower_subconfig.path,
# owners.forced, index,
# ) value,
owners.forced,
)
else:
for subconfig in subconfigs:
subconfig.properties = frozenset()
value = values.get_value(subconfig)[0]
if value is None:
continue
if values.hasvalue(subconfig.path):
continue
values.set_storage_value(subconfig.path,
None,
value,
owners.forced,
)
class OptionDescriptionWalk(CacheOptionDescription): class OptionDescriptionWalk(CacheOptionDescription):
@ -228,7 +247,7 @@ class OptionDescriptionWalk(CacheOptionDescription):
'in root optiondescription' 'in root optiondescription'
)) ))
raise AttributeError(_(f'unknown option "{name}" ' raise AttributeError(_(f'unknown option "{name}" '
f'in optiondescription "{self.impl_get_display_name()}"' f'in optiondescription "{self.impl_get_display_name(parent)}"'
)) ))
def get_children(self) -> List[BaseOption]: def get_children(self) -> List[BaseOption]:
@ -278,7 +297,9 @@ class OptionDescription(OptionDescriptionWalk):
name: str, name: str,
doc: str, doc: str,
children: List[BaseOption], children: List[BaseOption],
properties=None) -> None: properties=None,
informations: Optional[Dict]=None,
) -> None:
""" """
:param children: a list of options (including optiondescriptions) :param children: a list of options (including optiondescriptions)
@ -286,8 +307,10 @@ class OptionDescription(OptionDescriptionWalk):
assert isinstance(children, list), _('children in optiondescription "{}" ' assert isinstance(children, list), _('children in optiondescription "{}" '
'must be a list').format(name) 'must be a list').format(name)
super().__init__(name, super().__init__(name,
doc=doc, doc,
properties=properties) informations,
properties=properties,
)
child_names = [] child_names = []
if __debug__: if __debug__:
dynopt_names = [] dynopt_names = []

View file

@ -20,7 +20,7 @@
# ____________________________________________________________ # ____________________________________________________________
"""SymLinkOption link to an other option """SymLinkOption link to an other option
""" """
from typing import Any from typing import Any, Optional, Dict
from .baseoption import BaseOption, valid_name from .baseoption import BaseOption, valid_name
from ..error import ConfigError from ..error import ConfigError
from ..i18n import _ from ..i18n import _
@ -41,55 +41,46 @@ class SymLinkOption(BaseOption):
if not isinstance(opt, BaseOption) or \ if not isinstance(opt, BaseOption) or \
opt.impl_is_optiondescription() or \ opt.impl_is_optiondescription() or \
opt.impl_is_symlinkoption(): opt.impl_is_symlinkoption():
raise ValueError(_('malformed symlinkoption must be an option for symlink {0}' raise ValueError(_(f'malformed symlink second parameters must be an option for "{name}", not {opt}'))
'').format(name)) self._name = name
_setattr = object.__setattr__ self._opt = opt
_setattr(self, '_name', name)
_setattr(self, '_opt', opt)
opt._add_dependency(self) opt._add_dependency(self)
def __getattr__(self, def __getattr__(self,
name: str, name: str,
) -> Any: ) -> Any:
if name == '_subdyns':
return None
if name == '_path': if name == '_path':
raise AttributeError() raise AttributeError()
return getattr(self._opt, name) return getattr(self._opt, name)
def _setsubdyn(self,
subdyn,
) -> None:
raise ConfigError(_('cannot set symlinkoption in a '
'dynoptiondescription'))
def impl_has_dependency(self,
self_is_dep: bool=True,
) -> bool:
"""If self_is_dep is True, it has dependency (self._opt), so return True
if self_is_dep is False, cannot has validation or callback, so return False
"""
return self_is_dep
def impl_is_symlinkoption(self) -> bool: def impl_is_symlinkoption(self) -> bool:
"""it's a symlinkoption """it's a symlinkoption
""" """
return True return True
def impl_is_leader(self) -> bool:
return False
def impl_is_follower(self) -> bool:
return False
def impl_getopt(self) -> BaseOption: def impl_getopt(self) -> BaseOption:
"""get to linked option """get to linked option
""" """
return self._opt return self._opt
def issubdyn(self) -> bool:
"""it's not a sub dyn option
"""
return False
def impl_is_multi(self) -> bool: def impl_is_multi(self) -> bool:
"""is it a multi? """is it a multi?
""" """
if self._opt.issubdyn(): if self._opt.impl_is_multi():
return True return True
return self._opt.impl_is_multi() if self._opt.issubdyn() or self.issubdyn():
if self.issubdyn() != self._opt.issubdyn():
return self._opt.issubdyn()
return self._opt.issubdyn() in self.get_sub_dyns()
return False
def impl_is_submulti(self) -> bool: def impl_is_submulti(self) -> bool:
"""is it a submulti? """is it a submulti?

View file

@ -1,351 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017-2024 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# 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/>.
#
# The original `Config` design model is unproudly borrowed from
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
"""SynDynOption internal option, it's an instanciate synoption
"""
import re
from typing import Optional, Iterator, Any, List, Tuple
from .baseoption import BaseOption
from ..i18n import _
from ..setting import ConfigBag, undefined
NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
class CommonDyn:
def get_path(self,
config_bag,
):
if config_bag is undefined or \
config_bag.context.get_description() == self:
return ''
return self.impl_getpath()
def get_suffixes(self,
parent: 'SubConfig',
) -> List[str]:
"""get dynamic suffixes
"""
subconfig = parent.get_child(self,
None,
False,
properties=None,
)
values = self._suffixes.execute(subconfig)
if values is None:
values = []
values_ = []
if __debug__:
if not isinstance(values, list):
raise ValueError(_('DynOptionDescription suffixes for '
f'option "{self.impl_get_display_name()}", is not '
f'a list ({values})'))
for val in values:
cval = self.convert_suffix_to_path(val)
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
if __debug__ and cval is not None:
raise ValueError(_('invalid suffix "{}" for option "{}"'
'').format(cval,
self.impl_get_display_name()))
else:
values_.append(val)
if __debug__ and len(values_) > len(set(values_)):
raise ValueError(_(f'DynOptionDescription "{self._name}" suffixes return a list with '
f'same values "{values_}"'''))
return values_
def split_path(self,
option,
*,
dynoption=None,
) -> Tuple[str, str]:
"""self.impl_getpath() is something like root.xxx.dynoption_path
option.impl_getpath() is something like root.xxx.dynoption_path.sub.path
must return ('root.xxx.', '.sub')
"""
if dynoption is None:
self_path = self.impl_getpath()
else:
self_path = dynoption.impl_getpath()
root_path = self_path.rsplit('.', 1)[0] if '.' in self_path else None
#
if self.option_is_self(option):
sub_path = ''
else:
option_path = option.impl_getpath()
if root_path:
if isinstance(option, SynDynLeadership):
count_root_path = option_path.count('.') - root_path.count('.')
root_path = option_path.rsplit('.', count_root_path)[0]
root_path += '.'
self_number_child = self_path.count('.') + 1
option_sub_path = option_path.split('.', self_number_child)[-1]
sub_path = '.' + option_sub_path.rsplit('.', 1)[0] if '.' in option_sub_path else ''
return root_path, sub_path
class Syn:
__slots__ = ('rootpath',
'opt',
'_current_suffixes',
'__weakref__')
def __init__(self,
opt: BaseOption,
rootpath: str,
suffixes: list,
) -> None:
self.opt = opt
self.rootpath = rootpath
self._current_suffixes = suffixes
def __getattr__(self,
name: str,
) -> Any:
# if not in SynDynOptionDescription, get value in self.opt
return getattr(self.opt,
name,
)
def impl_get_display_name(self) -> str:
return self.opt.impl_get_display_name(self)
def get_current_suffixes(self) -> str:
"""get suffixes
"""
return self.current__suffixes
def impl_is_dynsymlinkoption(self) -> bool:
"""it's a dynsymlinkoption
"""
return True
def impl_getpath(self) -> str:
"""get path
"""
path = self.impl_getname()
if self.rootpath:
path = f'{self.rootpath}.{path}'
return path
class SynDescr(Syn):
__slots__ = ('opt',
'rootpath',
'_current_suffixes',
)
def get_child(self,
name: str,
config_bag: ConfigBag,
*,
allow_dynoption: bool=False,
):
"""get children
"""
# if not dyn
option = self.get_child_not_dynamic(name,
allow_dynoption,
)
if option:
if allow_dynoption and option.impl_is_dynoptiondescription():
return option
return option.to_dynoption(self.impl_getpath(),
self._current_suffixes,
)
for child in self.opt._children[1]: # pylint: disable=no-member
if not child.impl_is_dynoptiondescription():
continue
for suffix in child.get_suffixes(config_bag):
if name != child.impl_getname(suffix):
continue
return child.to_dynoption(self.impl_getpath(),
self._current_suffixes + [suffix],
)
raise AttributeError(_(f'unknown option "{name}" '
f'in optiondescription "{self.impl_get_display_name()}"'
))
def get_children(self,
config_bag: ConfigBag,
):
# pylint: disable=unused-argument
"""get children
"""
for child in self.opt._children[1]:
if child.impl_is_dynoptiondescription():
dynchild = self.get_child(child.impl_getname(),
config_bag,
allow_dynoption=True,
)
for d in dynchild.get_sub_children(dynchild,
config_bag,
):
yield d.option
# yield from dynchild.get_sub_children(dynchild,
# config_bag,
# )
#for suffix in dynchild.get_suffixes(config_bag):
# yield child.to_dynoption(self.impl_getpath(),
# self._suffixes + [suffix],
# )
else:
yield child.to_dynoption(self.impl_getpath(),
self._current_suffixes,
)
def get_children_recursively(self,
bytype: Optional[BaseOption],
byname: Optional[str],
config_bag: ConfigBag,
self_opt: BaseOption=None,
) -> BaseOption:
# pylint: disable=unused-argument
"""get children recursively
"""
for option in self.opt.get_children_recursively(bytype,
byname,
config_bag,
self,
):
yield option
def get_child_not_dynamic(self,
name,
allow_dynoption,
):
children = self.opt._children
if name in children[0]: # pylint: disable=no-member
option = children[1][children[0].index(name)] # pylint: disable=no-member
if option.impl_is_dynoptiondescription() and not allow_dynoption:
raise AttributeError(_(f'unknown option "{name}" '
"in root optiondescription (it's a dynamic option)"
))
return SubDynOptionDescription(option,
self.impl_getpath(),
self._current_suffixes,
)
class SynDynOption(Syn):
"""SynDynOption is an Option include un DynOptionDescription with specified prefix
"""
__slots__ = ()
def impl_get_leadership(self): # pylint: disable=inconsistent-return-statements
"""is it a leadership?
"""
leadership = self.opt.impl_get_leadership()
if leadership:
rootpath = self.rootpath.rsplit('.', 1)[0]
return leadership.to_dynoption(rootpath,
self._current_suffixes,
)
#
#
#class SubDynOptionDescription(SynDescr, CommonDyn):
# def option_is_self(self,
# option,
# ) -> bool:
# return self.opt.option_is_self(option.opt)
#
# def get_sub_children(self,
# option,
# config_bag,
# *,
# index=None,
# properties=undefined,
# ):
# root_path, sub_path = self.split_path(option)
# for suffix in self.get_suffixes(config_bag):
# if self.option_is_self(option):
# parent_path = root_path
# elif root_path:
# parent_path = root_path + self.impl_getname(suffix) + sub_path
# else:
# parent_path = self.impl_getname(suffix) + sub_path
# yield OptionBag(option.to_dynoption(parent_path,
# [suffix],
# ),
# index,
# config_bag,
# properties=properties,
# ori_option=option
# )
#
#
#class SynDynOptionDescription(SynDescr):
# """SynDynOptionDescription internal option, it's an instanciate synoptiondescription
# """
# def impl_getname(self) -> str:
# """get name
# """
# if self.opt.impl_is_dynoptiondescription():
# return self.opt.impl_getname(self._current_suffixes[-1])
# return self.opt.impl_getname()
#
# def getsubdyn(self):
# return self.opt
#
#
#class SynDynLeadership(SynDynOptionDescription):
# """SynDynLeadership internal option, it's an instanciate synoptiondescription
# """
# def get_leader(self) -> SynDynOption:
# """get the leader
# """
# return self.opt.get_leader().to_dynoption(self.impl_getpath(),
# self._current_suffixes,
# )
#
# def get_followers(self) -> Iterator[SynDynOption]:
# """get followers
# """
# subpath = self.impl_getpath()
# for follower in self.opt.get_followers():
# yield follower.to_dynoption(subpath,
# self._current_suffixes,
# )
#
# def pop(self,
# *args,
# **kwargs,
# ) -> None:
# """pop value for a follower
# """
# self.opt.pop(*args,
# followers=self.get_followers(),
# **kwargs,
# )
#
# def follower_force_store_value(self,
# value,
# config_bag,
# owner,
# ) -> None:
# """force store value for a follower
# """
# self.opt.follower_force_store_value(value,
# config_bag,
# owner,
# dyn=self,
# )

View file

@ -1,235 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017-2023 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# 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/>.
#
# The original `Config` design model is unproudly borrowed from
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
"""SynDynOptionDescription and SynDynLeadership internal option
it's an instanciate synoptiondescription
"""
from typing import Optional, Iterator, Any, List
from ..i18n import _
from ..setting import ConfigBag, undefined
from .baseoption import BaseOption
from .syndynoption import SynDynOption
class Syn:
__slots__ = ('opt',
'rootpath',
'_suffixes',
)
def __init__(self,
opt: BaseOption,
rootpath: str,
suffixes: list,
) -> None:
self.opt = opt
self.rootpath = rootpath
self._suffixes = suffixes
def impl_get_display_name(self) -> str:
return self.opt.impl_get_display_name(self)
def get_child(self,
name: str,
config_bag: ConfigBag,
*,
allow_dynoption: bool=False,
):
"""get children
"""
# if not dyn
option = self.opt.get_child_not_dynamic(name,
allow_dynoption,
)
if option:
if allow_dynoption and option.impl_is_dynoptiondescription():
return option
return option.to_dynoption(self.impl_getpath(),
self._suffixes,
)
for child in self.opt._children[1]: # pylint: disable=no-member
if not child.impl_is_dynoptiondescription():
continue
for suffix in child.get_suffixes(config_bag,
dynoption=self,
):
if name != child.impl_getname(suffix):
continue
return child.to_dynoption(self.impl_getpath(),
self._suffixes + [suffix],
)
raise AttributeError(_(f'unknown option "{name}" '
f'in optiondescription "{self.impl_get_display_name()}"'
))
def get_children(self,
config_bag: ConfigBag,
):
# pylint: disable=unused-argument
"""get children
"""
for child in self.opt._children[1]:
if child.impl_is_dynoptiondescription():
for suffix in child.get_suffixes(config_bag,
dynoption=self,
):
yield child.to_dynoption(self.impl_getpath(),
self._suffixes + [suffix],
)
else:
yield child.to_dynoption(self.impl_getpath(),
self._suffixes,
)
def get_children_recursively(self,
bytype: Optional[BaseOption],
byname: Optional[str],
config_bag: ConfigBag,
self_opt: BaseOption=None,
) -> BaseOption:
# pylint: disable=unused-argument
"""get children recursively
"""
for option in self.opt.get_children_recursively(bytype,
byname,
config_bag,
self,
):
yield option
def get_suffixes(self) -> str:
"""get suffixes
"""
return self._suffixes
def impl_is_dynsymlinkoption(self) -> bool:
"""it's a dynsymlinkoption
"""
return True
class SubDynOptionDescription(Syn):
def impl_getpath(self) -> str:
"""get path
"""
path = self.opt.impl_getname()
if self.rootpath:
path = f'{self.rootpath}.{path}'
return path
def getsubdyn(self):
return self.opt.getsubdyn()
def impl_is_optiondescription(self):
return True
def impl_is_symlinkoption(self):
return False
def impl_is_leadership(self):
return False
def impl_is_dynoptiondescription(self) -> bool:
return True
def impl_getproperties(self):
return self.opt.impl_getproperties()
class SynDynOptionDescription(Syn):
"""SynDynOptionDescription internal option, it's an instanciate synoptiondescription
"""
def __getattr__(self,
name: str,
) -> Any:
# if not in SynDynOptionDescription, get value in self.opt
return getattr(self.opt,
name,
)
def impl_getname(self) -> str:
"""get name
"""
if self.opt.impl_is_dynoptiondescription():
return self.opt.impl_getname(self._suffixes[-1])
return self.opt.impl_getname()
def impl_getpath(self) -> str:
"""get path
"""
path = self.impl_getname()
if self.rootpath:
path = f'{self.rootpath}.{path}'
return path
def getsubdyn(self):
return self.opt
class SynDynLeadership(SynDynOptionDescription):
"""SynDynLeadership internal option, it's an instanciate synoptiondescription
"""
def get_leader(self) -> SynDynOption:
"""get the leader
"""
return self.opt.get_leader().to_dynoption(self.impl_getpath(),
self._suffixes,
)
def get_followers(self) -> Iterator[SynDynOption]:
"""get followers
"""
subpath = self.impl_getpath()
for follower in self.opt.get_followers():
yield follower.to_dynoption(subpath,
self._suffixes,
)
def pop(self,
*args,
**kwargs,
) -> None:
"""pop value for a follower
"""
self.opt.pop(*args,
followers=self.get_followers(),
**kwargs,
)
def follower_force_store_value(self,
value,
config_bag,
owner,
) -> None:
"""force store value for a follower
"""
self.opt.follower_force_store_value(value,
config_bag,
owner,
dyn=self,
)
def get_suffixes(self) -> str:
"""get suffix
"""
return self._suffixes

View file

@ -17,7 +17,7 @@
# ____________________________________________________________ # ____________________________________________________________
from typing import Union, Set from typing import Union, Set
from itertools import chain from itertools import chain
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list
from .i18n import _ from .i18n import _
@ -156,63 +156,6 @@ class Undefined:
undefined = Undefined() undefined = Undefined()
#
#
#class OptionBag:
# """Object to store information for an option
# """
# __slots__ = ('option', # current option
# 'path',
# 'index',
# 'config_bag',
# 'ori_option', # original option (for example useful for symlinkoption)
# 'properties', # properties of current option
# 'apply_requires', # apply requires or not for this option
# 'suffixes',
# )
#
# # pylint: disable=too-many-arguments
# def __init__(self,
# option,
# index,
# config_bag,
# *,
# path=None,
# properties=undefined,
# parent: 'SubConfig'=None,
# ori_option=None,
# apply_requires=True,
# suffixes=None
# ):
# self.index = index
# self.config_bag = config_bag
# self.option = option
# if ori_option is not None:
# self.ori_option = ori_option
# if config_bag is undefined:
# self.path = path
# elif option:
# if properties is not undefined:
# self.properties = properties
# self.suffixes = suffixes
#
# def __getattr__(self, key):
# if key == 'ori_option':
# return self.option
# if key == 'apply_requires':
# return True
# return None
#
# def copy(self):
# """copy OptionBag
# """
# option_bag = OptionBag(None,
# None,
# None,
# )
# for key in self.__slots__:
# setattr(option_bag, key, getattr(self, key))
# return option_bag
class ConfigBag: class ConfigBag:
@ -390,7 +333,6 @@ class Settings:
'ro_remove', 'ro_remove',
'rw_append', 'rw_append',
'rw_remove', 'rw_remove',
'default_properties',
) )
def __init__(self): def __init__(self):
@ -401,9 +343,8 @@ class Settings:
:param storage: the storage type :param storage: the storage type
""" """
# generic owner # generic owner
self._properties = {} self._properties = {None: {None: DEFAULT_PROPERTIES}}
self._permissives = {} self._permissives = {}
self.default_properties = DEFAULT_PROPERTIES
self.ro_append = RO_APPEND self.ro_append = RO_APPEND
self.ro_remove = RO_REMOVE self.ro_remove = RO_REMOVE
self.rw_append = RW_APPEND self.rw_append = RW_APPEND
@ -412,35 +353,19 @@ class Settings:
# ____________________________________________________________ # ____________________________________________________________
# get properties and permissive methods # get properties and permissive methods
def get_context_properties(self, def get_context_properties(self):
cache,
):
"""get context properties """get context properties
""" """
is_cached, props, _ = cache.getcache(None, return self.get_personalize_properties()
'context_props',
expiration=False,
)
if not is_cached:
props = self.get_stored_properties(None,
None,
self.default_properties,
)
cache.setcache(None,
props,
type_='properties',
)
return props
def get_stored_properties(self, def get_personalize_properties(self,
path: Union[None, str], path: Union[None, str]=None,
index: Union[None, int], index: Union[None, int]=None,
default_properties: Set[str], ) -> Set[str]:
) -> Set[str]:
"""Get the properties modified by user for a path or index """Get the properties modified by user for a path or index
""" """
if path not in self._properties or index not in self._properties[path]: if path not in self._properties or index not in self._properties[path]:
return frozenset(default_properties) return frozenset()
return self._properties[path][index] return self._properties[path][index]
def getproperties(self, def getproperties(self,
@ -467,18 +392,17 @@ class Settings:
if not is_cached: if not is_cached:
props = set() props = set()
# if index, get option's properties (without index) too # if index, get option's properties (without index) too
p_props = self.get_stored_properties(subconfig.path, p_props = [option.impl_getproperties()]
None, props_config = self.get_personalize_properties(subconfig.path)
option.impl_getproperties(), if props_config:
) p_props.append(props_config)
if subconfig.index is not None: if subconfig.index is not None:
p_props = chain(p_props, props_config = self.get_personalize_properties(subconfig.path,
self.get_stored_properties(subconfig.path, subconfig.index,
subconfig.index, )
option.impl_getproperties(), if props_config:
) p_props.append(props_config)
) for prop in chain(*p_props):
for prop in p_props:
if uncalculated or isinstance(prop, str): if uncalculated or isinstance(prop, str):
if not help_property: if not help_property:
props.add(prop) props.add(prop)
@ -520,6 +444,12 @@ class Settings:
props, props,
type_='properties', type_='properties',
) )
if subconfig.parent and subconfig.parent.raises_properties:
parent_properties = subconfig.parent.raises_properties
parent_properties -= self.getpermissives(subconfig)
if help_property:
parent_properties = {(prop, prop) for prop in parent_properties}
return props | parent_properties
return props return props
def get_context_permissives(self): def get_context_permissives(self):
@ -566,7 +496,7 @@ class Settings:
def set_context_properties(self, properties, context): def set_context_properties(self, properties, context):
"""set context properties """set context properties
""" """
self._properties.setdefault(None, {})[None] = properties self._properties[None][None] = properties
context.reset_cache(None) context.reset_cache(None)
def setproperties(self, def setproperties(self,
@ -580,8 +510,8 @@ class Settings:
if not opt.impl_is_optiondescription() and opt.impl_is_leader(): if not opt.impl_is_optiondescription() and opt.impl_is_leader():
not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES
if not_allowed_properties: if not_allowed_properties:
raise LeadershipError(_('leader cannot have "{list(not_allowed_properties)}" ' raise LeadershipError(_(f'leader cannot have "{display_list(not_allowed_properties)}" '
'property')) 'property'))
if ('force_default_on_freeze' in properties or \ if ('force_default_on_freeze' in properties or \
'force_metaconfig_on_freeze' in properties) and 'frozen' not in properties: 'force_metaconfig_on_freeze' in properties) and 'frozen' not in properties:
raise LeadershipError(_('a leader ({opt.impl_get_display_name()}) cannot have ' raise LeadershipError(_('a leader ({opt.impl_get_display_name()}) cannot have '
@ -682,9 +612,11 @@ class Settings:
# validate properties # validate properties
def calc_raises_properties(self, def calc_raises_properties(self,
subconfig, subconfig,
*,
apply_requires=True, apply_requires=True,
uncalculated=False, uncalculated=False,
transitive_raise=True, transitive_raise=True,
not_unrestraint=False,
): ):
"""raise if needed """raise if needed
""" """
@ -698,16 +630,23 @@ class Settings:
) )
return self._calc_raises_properties(subconfig, return self._calc_raises_properties(subconfig,
option_properties, option_properties,
not_unrestraint,
) )
def _calc_raises_properties(self, def _calc_raises_properties(self,
subconfig, subconfig,
option_properties, option_properties,
not_unrestraint,
): ):
raises_properties = subconfig.config_bag.properties - SPECIAL_PROPERTIES config_bag =subconfig.config_bag
if not_unrestraint and config_bag.is_unrestraint:
context_properties = config_bag.true_properties
else:
context_properties = config_bag.properties
raises_properties = context_properties - SPECIAL_PROPERTIES
# remove global permissive properties # remove global permissive properties
if raises_properties and 'permissive' in raises_properties: if raises_properties and 'permissive' in raises_properties:
raises_properties -= subconfig.config_bag.permissives raises_properties -= config_bag.permissives
properties = option_properties & raises_properties properties = option_properties & raises_properties
# at this point it should not remain any property for the option # at this point it should not remain any property for the option
return properties return properties
@ -736,6 +675,7 @@ class Settings:
calc_properties = [] calc_properties = []
for property_ in self._calc_raises_properties(subconfig, for property_ in self._calc_raises_properties(subconfig,
set(help_properties.keys()), set(help_properties.keys()),
False,
): ):
calc_properties.append(help_properties[property_]) calc_properties.append(help_properties[property_])
calc_properties = frozenset(calc_properties) calc_properties = frozenset(calc_properties)
@ -799,10 +739,7 @@ class Settings:
append, append,
config_bag, config_bag,
): ):
props = self.get_stored_properties(None, props = self.get_personalize_properties()
None,
self.default_properties,
)
modified = False modified = False
if remove & props: if remove & props:
props = props - remove props = props - remove

View file

@ -6,7 +6,7 @@ from copy import copy
from itertools import chain from itertools import chain
from .error import ValueWarning, ValueErrorWarning, PropertiesOptionError, ConfigError from .error import ValueWarning, ValueErrorWarning, PropertiesOptionError, ConfigError
from .setting import undefined from .setting import undefined
from .option.syndynoption import SynDynOption #from .option.syndynoption import SynDynOption
from . import RegexpOption, ChoiceOption, ParamOption from . import RegexpOption, ChoiceOption, ParamOption
from .i18n import _ from .i18n import _
@ -233,8 +233,8 @@ class Requires(object):
def add(self, path, childapi, form): def add(self, path, childapi, form):
#collect id of all options #collect id of all options
child = childapi.get() child = childapi.get()
if isinstance(child, SynDynOption): # if isinstance(child, SynDynOption):
child = child.opt # child = child.opt
self.options[child] = path self.options[child] = path
current_action = None current_action = None

View file

@ -18,7 +18,7 @@
from typing import Union, Optional, List, Any from typing import Union, Optional, List, Any
from .error import ConfigError from .error import ConfigError
from .setting import owners, undefined, forbidden_owners from .setting import owners, undefined, forbidden_owners
from .autolib import Calculation from .autolib import Calculation, get_calculated_value
from .i18n import _ from .i18n import _
@ -106,9 +106,9 @@ class Values:
# the value is a default value # the value is a default value
# get it # get it
value = self.get_default_value(subconfig) value = self.get_default_value(subconfig)
value, has_calculation = self.get_calculated_value(subconfig, value, has_calculation = get_calculated_value(subconfig,
value, value,
) )
return value, has_calculation return value, has_calculation
def get_default_value(self, def get_default_value(self,
@ -125,9 +125,9 @@ class Values:
return msubconfig.config_bag.context.get_values().get_cached_value(msubconfig) return msubconfig.config_bag.context.get_values().get_cached_value(msubconfig)
# now try to get calculated value: # now try to get calculated value:
value, _has_calculation = self.get_calculated_value(subconfig, value, _has_calculation = get_calculated_value(subconfig,
subconfig.option.impl_getdefault(), subconfig.option.impl_getdefault(),
) )
if subconfig.index is not None and isinstance(value, (list, tuple)) \ if subconfig.index is not None and isinstance(value, (list, tuple)) \
and (not subconfig.option.impl_is_submulti() or \ and (not subconfig.option.impl_is_submulti() or \
not value or isinstance(value[0], list)): not value or isinstance(value[0], list)):
@ -139,38 +139,14 @@ class Values:
else: else:
# no value for this index, retrieve default multi value # no value for this index, retrieve default multi value
# default_multi is already a list for submulti # default_multi is already a list for submulti
value, _has_calculation = self.get_calculated_value(subconfig, value, _has_calculation = get_calculated_value(subconfig,
subconfig.option.impl_getdefault_multi(), subconfig.option.impl_getdefault_multi(),
) )
self.reset_cache_after_calculation(subconfig,
value,
)
return value return value
def get_calculated_value(self,
subconfig: "SubConfig",
value: Any,
*,
reset_cache: bool=True,
) -> Any:
"""value could be a calculation, in this case do calculation
"""
has_calculation = False
if isinstance(value, Calculation):
value = value.execute(subconfig)
has_calculation = True
elif isinstance(value, list):
# if value is a list, do subcalculation
for idx, val in enumerate(value):
value[idx], _has_calculation = self.get_calculated_value(subconfig,
val,
reset_cache=False,
)
if _has_calculation:
has_calculation = True
if reset_cache:
self.reset_cache_after_calculation(subconfig,
value,
)
return value, has_calculation
#______________________________________________________________________ #______________________________________________________________________
def check_force_to_metaconfig(self, def check_force_to_metaconfig(self,
subconfig: "OptionBag", subconfig: "OptionBag",
@ -210,7 +186,9 @@ class Values:
# calculated value is a new value, so reset cache # calculated value is a new value, so reset cache
subconfig.config_bag.context.reset_cache(subconfig) subconfig.config_bag.context.reset_cache(subconfig)
# and manage force_store_value # and manage force_store_value
# self._set_force_value_suffix(subconfig) self._set_force_value_suffix(subconfig,
value,
)
def isempty(self, def isempty(self,
subconfig: "SubConfig", subconfig: "SubConfig",
@ -279,12 +257,14 @@ class Values:
elif 'validator' in setting_properties and has_calculation: elif 'validator' in setting_properties and has_calculation:
cache = subconfig.config_bag.context.get_values_cache() cache = subconfig.config_bag.context.get_values_cache()
cache.delcache(subconfig.path) cache.delcache(subconfig.path)
# if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader(): if 'force_store_value' in setting_properties and subconfig.option.impl_is_leader():
# leader = option_bag.option.impl_get_leadership() leader = subconfig.option.impl_get_leadership()
# leader.follower_force_store_value(value, parent = subconfig.parent
# option_bag.config_bag, parent._length = len(value)
# owners.forced, leader.follower_force_store_value(value,
# ) parent,
owners.forced,
)
def setvalue_validation(self, def setvalue_validation(self,
subconfig: "SubConfig", subconfig: "SubConfig",
@ -296,10 +276,9 @@ class Values:
# First validate properties with this value # First validate properties with this value
opt = subconfig.option opt = subconfig.option
settings.validate_frozen(subconfig) settings.validate_frozen(subconfig)
val, has_calculation = self.get_calculated_value(subconfig, val, has_calculation = get_calculated_value(subconfig,
value, value,
reset_cache=False, )
)
settings.validate_mandatory(subconfig, settings.validate_mandatory(subconfig,
val, val,
) )
@ -327,7 +306,9 @@ class Values:
value, value,
owner, owner,
) )
# self._set_force_value_suffix(option_bag) self._set_force_value_suffix(subconfig,
value,
)
def set_storage_value(self, def set_storage_value(self,
path, path,
@ -339,47 +320,44 @@ class Values:
""" """
self._values.setdefault(path, {})[index] = [value, owner] self._values.setdefault(path, {})[index] = [value, owner]
# def _set_force_value_suffix(self, def _set_force_value_suffix(self,
# option_bag: OptionBag, subconfig: 'SubConfig',
# ) -> None: suffix_values,
# """ force store value for an option for suffixes ) -> None:
# """ """ force store value for an option for suffixes
# # pylint: disable=too-many-locals """
# if 'force_store_value' not in option_bag.config_bag.properties: # pylint: disable=too-many-locals
# return if 'force_store_value' not in subconfig.config_bag.properties:
# return
# for woption in option_bag.option._get_suffixes_dependencies(): # pylint: disable=protected-access
# # options from dependencies are weakref config_bag = subconfig.config_bag
# option = woption() context = config_bag.context
# force_store_options = [] for woption in subconfig.option._get_suffixes_dependencies(): # pylint: disable=protected-access
# for coption in option.get_children_recursively(None, options = subconfig.get_common_child(woption(),
# None, true_path=subconfig.path,
# option_bag.config_bag, validate_properties=False,
# option_suffixes=[], )
# ): if not isinstance(options, list):
# if 'force_store_value' in coption.impl_getproperties(): options = [options]
# force_store_options.append(coption) for option in options:
# if not force_store_options: parent = option.parent
# continue for suffix in suffix_values:
# for coption in force_store_options: name = option.option.impl_getname(suffix)
# if coption.impl_is_follower(): opt_subconfig = parent.get_child(option.option,
# leader = coption.impl_get_leadership().get_leader() None,
# loption_bag = OptionBag(leader, False,
# None, suffix=suffix,
# option_bag.config_bag, name=name,
# properties=frozenset(), )
# )
# indexes = range(len(self.get_value(loption_bag)[0])) for walk_subconfig in context.walk(opt_subconfig,
# else: no_value=True,
# indexes = [None] validate_properties=False,
# for index in indexes: ):
# for coption_bag in option.get_sub_children(coption, if 'force_store_value' not in walk_subconfig.properties:
# option_bag.config_bag, continue
# index=index, default_value = [self.get_value(walk_subconfig)[0], owners.forced]
# properties=frozenset(), self._values.setdefault(walk_subconfig.path, {})[walk_subconfig.index] = default_value
# ):
# default_value = [self.get_value(coption_bag)[0], owners.forced]
# self._values.setdefault(coption_bag.path, {})[index] = default_value
def _get_modified_parent(self, def _get_modified_parent(self,
subconfig: "SubConfig", subconfig: "SubConfig",
@ -462,9 +440,9 @@ class Values:
was present was present
:returns: a `setting.owners.Owner` object :returns: a `setting.owners.Owner` object
""" """
context = subconfig.config_bag.context # context = subconfig.config_bag.context
settings = context.get_settings() # settings = context.get_settings()
settings.validate_properties(subconfig) # settings.validate_properties(subconfig)
if 'frozen' in subconfig.properties and \ if 'frozen' in subconfig.properties and \
'force_default_on_freeze' in subconfig.properties: 'force_default_on_freeze' in subconfig.properties:
return owners.default return owners.default
@ -509,7 +487,7 @@ class Values:
if not self.hasvalue(subconfig.path, if not self.hasvalue(subconfig.path,
index=subconfig.index, index=subconfig.index,
): ):
raise ConfigError(_(f'no value for {subconfig.path} cannot change owner to {owner}')) raise ConfigError(_(f'"{subconfig.path}" is a default value, so we cannot change owner to "{owner}"'))
subconfig.config_bag.context.get_settings().validate_frozen(subconfig) subconfig.config_bag.context.get_settings().validate_frozen(subconfig)
self._values[subconfig.path][subconfig.index][1] = owner self._values[subconfig.path][subconfig.index][1] = owner
#______________________________________________________________________ #______________________________________________________________________
@ -517,59 +495,58 @@ class Values:
def reset(self, def reset(self,
subconfig: "SubConfig", subconfig: "SubConfig",
*,
validate: bool=True,
) -> None: ) -> None:
"""reset value for an option """reset value for an option
""" """
config_bag = subconfig.config_bag config_bag = subconfig.config_bag
context = config_bag.context
hasvalue = self.hasvalue(subconfig.path) hasvalue = self.hasvalue(subconfig.path)
context = config_bag.context
setting_properties = config_bag.properties setting_properties = config_bag.properties
if hasvalue and 'validator' in config_bag.properties: if validate:
fake_context = context.gen_fake_context() if hasvalue and 'validator' in setting_properties:
fake_config_bag = config_bag.copy() fake_context = context.gen_fake_context()
fake_config_bag.remove_validation() fake_config_bag = config_bag.copy()
fake_config_bag.context = fake_context fake_config_bag.remove_validation()
fake_subconfig = fake_context.get_sub_config(fake_config_bag, fake_config_bag.context = fake_context
subconfig.path, fake_subconfig = fake_context.get_sub_config(fake_config_bag,
subconfig.index, subconfig.path,
validate_properties=False, subconfig.index,
follower_not_apply_requires=False, validate_properties=False,
) )
fake_values = fake_context.get_values() fake_values = fake_context.get_values()
fake_values.reset(fake_subconfig) fake_values.reset(fake_subconfig)
fake_subconfig.config_bag.properties = setting_properties fake_subconfig.config_bag.properties = setting_properties
value = fake_values.get_default_value(fake_subconfig) value = fake_values.get_default_value(fake_subconfig)
fake_values.setvalue_validation(fake_subconfig, fake_values.setvalue_validation(fake_subconfig,
value, value,
) )
# if hasvalue:
opt = subconfig.option opt = subconfig.option
if opt.impl_is_leader(): if opt.impl_is_leader():
opt.impl_get_leadership().reset(subconfig.parent) opt.impl_get_leadership().reset(subconfig.parent)
if hasvalue: if 'force_store_value' in setting_properties and \
if 'force_store_value' in subconfig.config_bag.properties and \ 'force_store_value' in subconfig.properties:
'force_store_value' in subconfig.properties: value = self.get_default_value(subconfig)
value = self.get_default_value(subconfig)
self._setvalue(subconfig, self._setvalue(subconfig,
value, value,
owners.forced, owners.forced,
) )
else: else:
# for leader only value = None
value = None if subconfig.path in self._values:
if subconfig.path in self._values: del self._values[subconfig.path]
del self._values[subconfig.path] if 'force_store_value' in setting_properties and subconfig.option.impl_is_leader():
context.reset_cache(subconfig) if value is None:
# if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader(): value = self.get_default_value(subconfig)
# if value is None: leader = subconfig.option.impl_get_leadership()
# value = self.get_default_value(option_bag, leader.follower_force_store_value(value,
# parent, subconfig.parent,
# ) owners.forced,
# leader = option_bag.option.impl_get_leadership() )
# leader.follower_force_store_value(value, context.reset_cache(subconfig)
# option_bag.config_bag,
# owners.forced,
# )
#______________________________________________________________________ #______________________________________________________________________
# Follower # Follower
@ -602,7 +579,6 @@ class Values:
subconfig.path, subconfig.path,
subconfig.index, subconfig.index,
validate_properties=False, validate_properties=False,
follower_not_apply_requires=False,
) )
fake_values = fake_context.get_values() fake_values = fake_context.get_values()
fake_values.reset_follower(fake_subconfig) fake_values.reset_follower(fake_subconfig)
@ -611,19 +587,18 @@ class Values:
fake_values.setvalue_validation(fake_subconfig, fake_values.setvalue_validation(fake_subconfig,
value, value,
) )
# if 'force_store_value' in setting_properties and \ if 'force_store_value' in setting_properties and \
# 'force_store_value' in option_bag.properties: 'force_store_value' in subconfig.properties:
# value = self.get_default_value(option_bag, value = self.get_default_value(subconfig,
# parent, )
# )
# self._setvalue(subconfig,
# self._setvalue(option_bag, value,
# value, owners.forced,
# owners.forced, )
# ) else:
# else: self.resetvalue_index(subconfig)
self.resetvalue_index(subconfig) context.reset_cache(subconfig)
context.reset_cache(subconfig)
def resetvalue_index(self, def resetvalue_index(self,
subconfig: "SubConfig", subconfig: "SubConfig",
@ -688,14 +663,26 @@ class Values:
config_bag = subconfig.config_bag config_bag = subconfig.config_bag
context = config_bag.context context = config_bag.context
for key, options in subconfig.option.get_dependencies_information().items(): for key, options in subconfig.option.get_dependencies_information().items():
for option in options: if key is None:
option_subconfig = context.get_sub_config(config_bag, continue
option.impl_getpath(), for woption in options:
None, if woption is None:
validate_properties=False, continue
follower_not_apply_requires=False, option = woption()
) if option.issubdyn():
context.reset_cache(option_subconfig) option_subconfigs = subconfig.get_common_child(option,
validate_properties=False,
)
if not isinstance(option_subconfigs, list):
option_subconfigs = [option_subconfigs]
else:
option_subconfigs = [context.get_sub_config(config_bag,
option.impl_getpath(),
None,
validate_properties=False,
)]
for option_subconfig in option_subconfigs:
context.reset_cache(option_subconfig)
def get_information(self, def get_information(self,
subconfig, subconfig,
@ -706,18 +693,25 @@ class Values:
:param name: the item string (ex: "help") :param name: the item string (ex: "help")
""" """
if subconfig is None: if subconfig.option.impl_is_symlinkoption():
path = None option = subconfig.option.impl_getopt()
path = option.impl_getpath()
else: else:
option = subconfig.option
path = subconfig.path path = subconfig.path
try: try:
return self._informations[path][name] return self._informations[path][name]
except KeyError as err: except KeyError as err:
if subconfig: pass
return subconfig.option.impl_get_information(name, default) if option is not None:
if default is not undefined: return option._get_information(subconfig,
return default name,
raise ValueError(_("information's item not found: {0}").format(name)) from err default,
)
return subconfig.config_bag.context.get_description()._get_information(subconfig,
name,
default,
)
def del_information(self, def del_information(self,
key: Any, key: Any,