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():
od1 = make_description()
cfg = Config(od1)
cfg.option('u2').permissive.set(frozenset(['prop']))
cfg.option('u2').permissive.add('prop')
export = cfg.permissive.exportation()
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'}
cfg.permissive.importation(export)
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'][0][0] is None
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.ip_admin_eth0'].keys()) == set([None])
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'][1][0] is None
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.ip_admin_eth0'].keys()) == set([None])
assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == set([0, 1])
@ -376,8 +376,7 @@ def test_cache_leader_and_followers():
idx_val2 = None
values = cfg._config_bag.context._impl_values_cache
settings = cfg._config_bag.context.properties_cache
compare(settings.get_cached(), {None: {None: (global_props, None)},
'val1': {None: (val1_props, None)},
compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
'val1.val1': {None: (val1_val1_props, None)},
})
# len is 0 so don't get any value
@ -385,17 +384,14 @@ def test_cache_leader_and_followers():
#
cfg.option('val1.val1').value.set([None])
val_val2_props = {idx_val2: (val1_val2_props, None), None: (set(), None)}
compare(settings.get_cached(), {None: {None: (set(global_props), None)},
# 'val1.val1': {None: (val1_val1_props, None)},
})
compare(settings.get_cached(), {'val1.val1': {None: ({'empty', 'unique'}, None, True)}})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.get()
#has value
idx_val2 = 0
val_val2 = None
val_val2_props = {idx_val2: (val1_val2_props, None)}
compare(settings.get_cached(), {None: {None: (global_props, None)},
'val1': {None: (val1_props, None)},
compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
'val1.val1': {None: (val1_val1_props, None)},
'val1.val2': val_val2_props})
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.value.get()
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)}})
val1_val2_props = {0: (frozenset([]), None), 1: (frozenset([]), None)}
# assert not list_sessions()
@ -428,15 +424,12 @@ def test_cache_leader_callback():
val1_val2_props = frozenset(val1_val2_props)
values = cfg._config_bag.context._impl_values_cache
settings = cfg._config_bag.context.properties_cache
compare(settings.get_cached(), {None: {None: (global_props, None)},
'val1': {None: (val1_props, None)},
compare(settings.get_cached(), {'val1': {None: (val1_props, None)},
'val1.val1': {None: (val1_val1_props, None)},
})
compare(values.get_cached(), {'val1.val1': {None: ([], None)}})
cfg.option('val1.val1').value.set([None])
compare(settings.get_cached(), {None: {None: (set(global_props), None)},
# 'val1.val1': {None: (val1_val1_props, None)},
})
compare(settings.get_cached(), {'val1.val1': {None: ({'unique', 'empty'}, None, True)}})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.get()
@ -458,38 +451,33 @@ def test_cache_requires():
settings = cfg._config_bag.context.properties_cache
assert values.get_cached() == {}
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)},
'activate_service': {None: (set([]), None)},
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}})
cfg.value.get()
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
'activate_service': {None: (set([]), None)},
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}})
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)},
'activate_service': {None: (set([]), None)}})
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)}})
compare(values.get_cached(), {'activate_service': {None: (True, None)}, 'ip_address_service': {None: ('1.1.1.1', None, True)}})
cfg.value.get()
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
'activate_service': {None: (set([]), None)},
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: ('1.1.1.1', None)},
'activate_service': {None: (True, None)}})
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)}})
cfg.value.get()
compare(settings.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings', 'force_store_value']), None)},
'activate_service': {None: (set([]), None)},
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set(['disabled']), None)}})
compare(values.get_cached(), {'activate_service': {None: (False, None)}})
@ -511,21 +499,18 @@ def test_cache_global_properties():
settings = cfg._config_bag.context.properties_cache
assert values.get_cached() == {}
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)},
'activate_service': {None: (set([]), None)},
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
compare(values.get_cached(), {'ip_address_service': {None: (None, None)},
'activate_service': {None: (True, None)}})
cfg.property.remove('disabled')
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)},
'activate_service': {None: (set([]), None)},
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
cfg.property.add('test')
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)},
'activate_service': {None: (set([]), None)},
compare(settings.get_cached(), {'activate_service': {None: (set([]), None)},
'ip_address_service': {None: (set([]), None)}})
# assert not list_sessions()

View file

@ -1,10 +1,9 @@
# coding: utf-8
from py.test import raises
from .autopath import 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, \
undefined, Params, ParamValue, ParamOption
from tiramisu.error import ConfigError
@ -76,6 +75,29 @@ def test_choiceoption_function(config_type):
# 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():
choice = ChoiceOption('choice', '', values=Calculation(return_error))
od1 = OptionDescription('od', '', [choice])
@ -262,3 +284,13 @@ def test_choiceoption_calc_not_list():
with raises(ConfigError):
cfg.option('choice').value.set(['val1'])
# 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)
stroption = StrOption('str', 'Test string option', default="abc", properties=('mandatory', ))
boolop = BoolOption('boolop', 'Test boolean option op', default=True, properties=('hidden',))
wantref_option = BoolOption('wantref', 'Test requires', default=False)
wantref_option.impl_set_information('info', 'default value')
wantref_option = BoolOption('wantref', 'Test requires', default=False, informations={'info': 'default value'})
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False)
@ -143,11 +142,11 @@ def test_information_config():
with pytest.raises(ValueError):
cfg.information.get('noinfo')
assert cfg.information.get('noinfo', 'default') == 'default'
cfg.information.reset('info')
cfg.information.remove('info')
with pytest.raises(ValueError):
cfg.information.get('info')
cfg.information.remove('info')
with pytest.raises(ValueError):
cfg.information.reset('noinfo')
cfg.information.remove('noinfo')
assert list(cfg.information.list()) == ['doc']
# assert not list_sessions()
@ -194,26 +193,23 @@ def test_information_option():
with pytest.raises(ValueError):
cfg.option('gc.name').information.get('noinfo')
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):
cfg.option('gc.name').information.get('info')
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 cfg.option('wantref').information.get('info') == 'default value'
cfg.option('wantref').information.set('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 not list_sessions()
def test_information_option_2():
i1 = IntOption('test1', '')
i1.impl_set_information('info', 'value')
# it's a dict
assert set(i1.impl_list_information()) == {'info', 'doc'}
i1 = IntOption('test1', '', informations={'info': 'value'})
od1 = OptionDescription('test', '', [i1])
cfg = Config(od1)
# it's tuples
@ -234,11 +230,11 @@ def test_information_optiondescription():
with pytest.raises(ValueError):
cfg.option('gc').information.get('noinfo')
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):
cfg.option('gc').information.get('info')
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 not list_sessions()

View file

@ -412,7 +412,6 @@ def test_help():
cfg = Config(od2)
cfg.help(_display=False)
cfg.config.help(_display=False)
cfg.option.help(_display=False)
cfg.option('o').help(_display=False)
cfg.option('o.s').help(_display=False)
# assert not list_sessions()
@ -430,7 +429,7 @@ def test_config_reset():
#
cfg.option('gc.gc2.bool').value.set(True)
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')
assert cfg.option('gc.gc2.bool').value.get()
assert cfg.option('boolop').property.get()

View file

@ -59,27 +59,27 @@ def test_copy_information():
ncfg = cfg.config.copy()
assert ncfg.information.get('key') == 'value'
# assert not list_sessions()
def test_copy_force_store_value():
od1 = make_description()
conf = Config(od1)
conf2 = Config(od1)
assert conf.value.exportation() == {}
assert conf2.value.exportation() == {}
#
conf.property.read_write()
assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
assert conf2.value.exportation() == {}
#
#def test_copy_force_store_value():
# od1 = make_description()
# conf = Config(od1)
# conf2 = Config(od1)
# assert conf.value.exportation() == {}
# assert conf2.value.exportation() == {}
# #
# conf.property.read_write()
# assert conf.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
# assert conf2.value.exportation() == {}
# #
# conf2.property.read_only()
# assert conf.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)
# assert conf.value.exportation() == {'creole.general.wantref': {None: [True, 'user']}}
# assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
## assert not list_sessions()
conf2.property.read_only()
assert conf.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)
assert conf.value.exportation() == {'creole.general.wantref': {None: [True, 'user']}}
assert conf2.value.exportation() == {'creole.general.wantref': {None: [False, 'forced']}}
# assert not list_sessions()
#
#
#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()
#def test_force_store_value():
# od1 = make_description_freeze()
# cfg = Config(od1)
# compare(cfg.value.exportation(), {})
# cfg.property.read_write()
# compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
# cfg.option('bool').value.set(False)
# cfg.option('wantref').value.set(True)
# cfg.option('bool').value.reset()
# compare(cfg.value.exportation(), {'wantref': {None: [True, 'user']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
# cfg.option('bool').value.set(False)
# cfg.option('wantref').value.reset()
# cfg.option('bool').value.reset()
# compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
## assert not list_sessions()
#
#
#def test_force_store_value_leadership_sub():
# b = IntOption('int', 'Test int option', multi=True, properties=('force_store_value',))
# c = StrOption('str', 'Test string option', multi=True)
# descr = Leadership("int", "", [b, c])
# od1 = OptionDescription('odr', '', [descr])
# cfg = Config(od1)
# cfg.property.read_only()
# compare(cfg.value.exportation(), {'int.int': {None: [[], 'forced']}})
## assert not list_sessions()
#
#
#def test_force_store_value_callback():
# b = IntOption('int', 'Test int option', Calculation(return_val), properties=('force_store_value',))
# od1 = OptionDescription("int", "", [b])
# cfg = Config(od1)
# cfg.property.read_only()
# compare(cfg.value.exportation(), {'int': {None: [1, 'forced']}})
## assert not list_sessions()
#
#
#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',))
# od1 = OptionDescription("int", "", [b])
# cfg = Config(od1)
# cfg.property.read_only()
# compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
## assert not list_sessions()
#
#
#def test_force_store_value_callback_params_with_opt():
# a = IntOption('val1', "", 2)
# b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamOption(a)})), properties=('force_store_value',))
# od1 = OptionDescription("int", "", [a, b])
# cfg = Config(od1)
# cfg.property.read_only()
# compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
## assert not list_sessions()
def test_force_store_value():
od1 = make_description_freeze()
cfg = Config(od1)
compare(cfg.value.exportation(), {})
cfg.property.read_write()
compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
cfg.option('bool').value.set(False)
cfg.option('wantref').value.set(True)
cfg.option('bool').value.reset()
compare(cfg.value.exportation(), {'wantref': {None: [True, 'user']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
cfg.option('bool').value.set(False)
cfg.option('wantref').value.reset()
cfg.option('bool').value.reset()
compare(cfg.value.exportation(), {'wantref': {None: [False, 'forced']}, 'wantref2': {None: [False, 'forced']}, 'wantref3': {None: [[False], 'forced']}})
# assert not list_sessions()
def test_force_store_value_leadership_sub():
b = IntOption('int', 'Test int option', multi=True, properties=('force_store_value',))
c = StrOption('str', 'Test string option', multi=True)
descr = Leadership("int", "", [b, c])
od1 = OptionDescription('odr', '', [descr])
cfg = Config(od1)
cfg.property.read_only()
compare(cfg.value.exportation(), {'int.int': {None: [[], 'forced']}})
# assert not list_sessions()
def test_force_store_value_callback():
b = IntOption('int', 'Test int option', Calculation(return_val), properties=('force_store_value',))
od1 = OptionDescription("int", "", [b])
cfg = Config(od1)
cfg.property.read_only()
compare(cfg.value.exportation(), {'int': {None: [1, 'forced']}})
# assert not list_sessions()
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',))
od1 = OptionDescription("int", "", [b])
cfg = Config(od1)
cfg.property.read_only()
compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
# assert not list_sessions()
def test_force_store_value_callback_params_with_opt():
a = IntOption('val1', "", 2)
b = IntOption('int', 'Test int option', Calculation(return_val2, Params(kwargs={'value': ParamOption(a)})), properties=('force_store_value',))
od1 = OptionDescription("int", "", [a, b])
cfg = Config(od1)
cfg.property.read_only()
compare(cfg.value.exportation(), {'int': {None: [2, 'forced']}})
# assert not list_sessions()

View file

@ -159,7 +159,7 @@ def test_iter_on_empty_group():
od1 = OptionDescription("name", "descr", [])
cfg = Config(od1)
cfg.property.read_write()
result = list(cfg.option.list())
result = list(cfg.list())
assert result == []
# assert not list_sessions()
@ -207,7 +207,7 @@ def test_leader_list(config_type):
od1 = OptionDescription('od', '', [interface1])
cfg = Config(od1)
cfg = get_config(cfg, config_type)
ret = cfg.option.list()
ret = cfg.list()
assert len(ret) == 1
assert ret[0].name() == 'leadership'
#
@ -983,65 +983,65 @@ def test_follower_not_multi():
# assert not list_sessions()
#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'])
# 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])
# od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2)
# cfg.property.read_write()
# assert cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions()
#
#
#def test_follower_force_store_value():
# 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',))
# interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
# od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2)
# cfg.property.read_write()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions()
#
#
#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'])
# 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])
# od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2)
# cfg.property.read_only()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions()
#
#
#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'])
# 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])
# od1 = OptionDescription('od', '', [interface0])
# od2 = OptionDescription('toto', '', [od1])
# cfg = Config(od2)
# cfg.property.read_write()
# 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', 1).owner.isdefault()
# #
# cfg.option('od.interface0.netmask_admin_eth0', 1).value.reset()
# 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)
# assert cfg.option('od.interface0.ip_admin_eth0').value.get() == []
# cfg.option('od.interface0.ip_admin_eth0').value.reset()
# assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
## assert not list_sessions()
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'])
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])
od1 = OptionDescription('od', '', [interface0])
od2 = OptionDescription('toto', '', [od1])
cfg = Config(od2)
cfg.property.read_write()
assert cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
# assert not list_sessions()
def test_follower_force_store_value():
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',))
interface0 = Leadership('interface0', '', [ip_admin_eth0, netmask_admin_eth0])
od1 = OptionDescription('od', '', [interface0])
od2 = OptionDescription('toto', '', [od1])
cfg = Config(od2)
cfg.property.read_write()
assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
# assert not list_sessions()
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'])
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])
od1 = OptionDescription('od', '', [interface0])
od2 = OptionDescription('toto', '', [od1])
cfg = Config(od2)
cfg.property.read_only()
assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
# assert not list_sessions()
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'])
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])
od1 = OptionDescription('od', '', [interface0])
od2 = OptionDescription('toto', '', [od1])
cfg = Config(od2)
cfg.property.read_write()
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', 1).owner.isdefault()
#
cfg.option('od.interface0.netmask_admin_eth0', 1).value.reset()
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)
assert cfg.option('od.interface0.ip_admin_eth0').value.get() == []
cfg.option('od.interface0.ip_admin_eth0').value.reset()
assert not cfg.option('od.interface0.netmask_admin_eth0', 0).owner.isdefault()
# assert not list_sessions()
#def test_follower_properties():
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',))

View file

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

View file

@ -415,8 +415,7 @@ def test_callback_information(config_type):
def test_callback_information2(config_type):
val1 = StrOption('val1', "", Calculation(return_value, Params(ParamSelfInformation('information', 'no_value'))))
val2 = StrOption('val2', "", Calculation(return_value, Params(ParamSelfInformation('information'))))
val2.impl_set_information('information', 'new_value')
val2 = StrOption('val2', "", Calculation(return_value, Params(ParamSelfInformation('information'))), informations={'information': 'new_value'})
val3 = StrOption('val3', "", Calculation(return_value, Params(ParamSelfInformation('information'))))
od1 = OptionDescription('rootconfig', '', [val1, val2, val3])
cfg = Config(od1)
@ -432,9 +431,8 @@ def test_callback_information2(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))))
val1.impl_set_information('information', 'new_value')
od1 = OptionDescription('rootconfig', '', [val1, val2])
cfg = Config(od1)
cfg.property.read_write()
@ -1691,3 +1689,38 @@ def test_calc_dependencies(config_type):
def test_callback__kwargs_wrong(config_type):
with pytest.raises(ValueError):
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()
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):
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('notunique',))
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',
}
#
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='remove', properties=frozenset(['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):
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', 'remove') == {'hidden'}
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([])
#
config.property.read_only()
assert config.property.get() == {'cache', 'disabled'}
assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled'}
config.property.read_write()
assert config.property.get() == {'cache', 'disabled', 'hidden'}
assert config.property.get() == {'warnings', 'validator', 'cache', 'disabled', 'hidden'}
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('read_only', 'append') == {'frozen',
@ -138,6 +138,19 @@ def test_mod_read_only_write():
# 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):
s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True)
od1 = OptionDescription("options", "", [s])
@ -365,8 +378,7 @@ def test_apply_requires_from_config():
with pytest.raises(PropertiesOptionError):
cfg.option('opt.str').value.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').properties(only_raises=True)
assert 'hidden' not in cfg.forcepermissive.option('opt.str').property.get(only_raises=True)
# assert not list_sessions()
@ -386,8 +398,7 @@ def test_apply_requires_with_disabled():
cfg.option('int').value.set(1)
with pytest.raises(PropertiesOptionError):
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').properties(only_raises=True)
assert 'disabled' not in cfg.unrestraint.option('opt.str').property.get(only_raises=True, apply_requires=False)
assert 'disabled' in cfg.unrestraint.option('opt.str').property.get()
# assert not list_sessions()
@ -607,7 +618,7 @@ def test_properties_get_add_reset():
cfg.property.add('frozen')
assert cfg.property.get() == {'validator', 'warnings', 'cache', 'frozen'}
cfg.property.reset()
assert cfg.property.get() == {'validator', 'warnings', 'cache'}
assert cfg.property.get() == frozenset()
def test_reset_properties_force_store_value():
@ -615,28 +626,25 @@ def test_reset_properties_force_store_value():
gcgroup = OptionDescription('gc', '', [gcdummy])
od1 = OptionDescription('tiramisu', '', [gcgroup])
cfg = Config(od1)
assert cfg.property.exportation() == {}
assert cfg.property.exportation() == {None: {None: frozenset({'validator', 'warnings', 'cache'})}}
cfg.property.add('frozen')
assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'cache', 'validator', 'warnings'))}}
cfg.property.reset()
assert cfg.property.exportation() == {None: {}}
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()
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')
assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))},
'gc.dummy': {None: set(('test', 'force_store_value'))}}
{None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}}
cfg.property.add('frozen')
assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))},
'gc.dummy': {None: set(('test', 'force_store_value'))}}
{None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}}
cfg.option('gc.dummy').property.add('test')
assert cfg.property.exportation() == \
{None: {None: set(('frozen', 'validator', 'cache', 'warnings'))},
'gc.dummy': {None: set(('test', 'force_store_value'))}}
{None: {None: frozenset({'frozen'})}, 'gc.dummy': {None: frozenset({'test'})}}
# assert not list_sessions()
@ -666,7 +674,7 @@ def test_set_modified_value():
gcgroup = OptionDescription('gc', '', [gcdummy])
od1 = OptionDescription('tiramisu', '', [gcgroup])
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'))}})
assert cfg.property.exportation() == \
{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):
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.property.read_write()
cfg_ori.option('gc').property.add('hidden')
@ -73,14 +76,14 @@ def test_group_is_hidden(config_type):
cfg.option('gc.dummy').value.get()
if config_type == 'tiramisu-api':
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)
with pytest.raises(PropertiesOptionError):
cfg.option('gc.float').value.get()
# manually set the subconfigs to "show"
if config_type == 'tiramisu-api':
cfg.send()
cfg_ori.forcepermissive.option('gc').property.remove('hidden')
cfg_ori.option('gc').property.remove('hidden')
cfg = get_config(cfg_ori, config_type)
assert not 'hidden' in cfg.option('gc').property.get()
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):
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')
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)
with pytest.raises(ConfigError):
cfg.option('opt1').value.get()
with pytest.raises(ConfigError):
cfg.option('opt3').value.get()
cfg.option('opt1').information.set('key', 'val')
assert cfg.option('opt1').value.get() == 'val'
assert cfg.option('opt3').value.get() == 'val'
cfg.option('opt1').information.set('key', 'val1')
with pytest.raises(ValueError):
cfg.option('opt1').value.get()
with pytest.raises(ValueError):
cfg.option('opt3').value.get()
#
with pytest.raises(ConfigError):
assert cfg.option('opt2').value.get()
cfg.option('opt2').value.get()
cfg.information.set('key', 'val')
assert cfg.option('opt2').value.get() == 'val'
cfg.information.set('key', 'val1')

View file

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

View file

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

View file

@ -141,7 +141,7 @@ def test_symlink_getpermissive():
od1 = OptionDescription('opt', '', [boolopt, linkopt])
cfg = Config(od1)
cfg.property.read_write()
cfg.option('b').permissive.set(frozenset(['perm']))
cfg.option('b').permissive.add('perm')
cfg.option('c').permissive.get() == frozenset(['perm'])
# assert not list_sessions()
@ -266,14 +266,26 @@ def test_symlink_owner(config_type):
def test_symlink_get_information():
boolopt = BoolOption("b", "", default=False)
boolopt = BoolOption("b", "", default=False, informations={'test': 'test'})
linkopt = SymLinkOption("c", boolopt)
boolopt.impl_set_information('test', 'test')
assert boolopt.impl_get_information('test') == 'test'
assert linkopt.impl_get_information('test') == 'test'
boolopt.impl_set_information('test', 'test2')
assert boolopt.impl_get_information('test') == 'test2'
assert linkopt.impl_get_information('test') == 'test2'
od1 = OptionDescription('opt', '', [linkopt, boolopt])
cfg = Config(od1)
assert cfg.option('b').information.get('test') == 'test'
assert cfg.option('c').information.get('test') == 'test'
cfg.option('b').information.set('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():
@ -359,9 +371,9 @@ def test_symlink_dependency():
[linkopt, OptionDescription("s1", "", [boolopt])])
cfg = Config(od1)
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('c').has_dependency(False) is False
assert cfg.option('c').has_dependency(False) is True
# assert not list_sessions()
@ -385,7 +397,7 @@ def test_symlink_list(config_type):
[linkopt, OptionDescription("s1", "", [boolopt])])
cfg = Config(od1)
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 not list_sessions()

View file

@ -24,14 +24,15 @@ from copy import deepcopy
from .error import ConfigError, LeadershipError, ValueErrorWarning
from .i18n import _
from .setting import ConfigBag, owners, groups, undefined, \
FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES
FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, \
DEFAULT_PROPERTIES
from .config import KernelConfig, KernelGroupConfig, KernelMetaConfig, KernelMixConfig, SubConfig
from .option import RegexpOption, OptionDescription, ChoiceOption, Leadership
from .todict import TiramisuDict
from .autolib import Calculation
TIRAMISU_VERSION = 4
TIRAMISU_VERSION = 5
class TiramisuHelp:
@ -70,10 +71,6 @@ class TiramisuHelp:
_('Do not warnings during validation')
).expandtabs(max_len + 10))
display()
if isinstance(self, TiramisuDispatcherOption):
doc = _(getdoc(self.__call__))
display(_('Call: {}').format(doc))
display()
display(_('Commands:'))
for module_name in modules:
module = getattr(self, module_name)
@ -90,21 +87,6 @@ class TiramisuHelp:
class CommonTiramisu(TiramisuHelp):
_validate_properties = True
def _get_subconfig(self,
follower_not_apply_requires: bool,
) -> "OptionBag":
try:
return self._config_bag.context.get_sub_config(self._config_bag,
self._path,
self._index,
validate_properties=self._validate_properties,
follower_not_apply_requires=follower_not_apply_requires,
)
except AssertionError as err:
raise ConfigError(str(err))
except Exception as err:
raise err
def option_type(typ):
if not isinstance(typ, list):
@ -126,17 +108,39 @@ def option_type(typ):
kwargs['is_group'] = True
return func(self, options_bag, *args[1:], **kwargs)
if not self._subconfig:
self._subconfig = self._get_subconfig('with_index' not in types)
self._subconfig = self._config_bag.context.get_sub_config(self._config_bag,
self._path,
self._index,
validate_properties=False,
)
option = self._subconfig.option
if option.impl_is_optiondescription() and 'optiondescription' in types or \
option.impl_is_optiondescription() and option.impl_is_leadership() and 'leadership' in types or \
not option.impl_is_optiondescription() and (
option.impl_is_symlinkoption() and 'symlink' in types or \
not option.impl_is_symlinkoption() and (
'option' in types or \
option.impl_is_leader() and 'leader' in types or \
option.impl_is_follower() and 'follower' in types or \
isinstance(option, ChoiceOption) and 'choice' in types)):
error_type = None
if 'dynamic' in types:
if not self._subconfig.is_dynamic:
error_type = 'only available for dynamic option'
elif option.impl_is_optiondescription():
if 'optiondescription' not in types:
if option.impl_is_leadership():
if 'leadership' not in types:
error_type = 'not available for a Leadership'
else:
error_type = 'not available for an OptionDescription'
elif option.impl_is_symlinkoption():
if 'symlink' not in types:
error_type = 'this function is not available for a SymLinkOption'
elif 'option' not in types:
if 'choice' in types:
if not isinstance(option, ChoiceOption):
error_type = 'only available for ChoiceOption'
elif option.impl_is_leader():
if 'leader' not in types:
error_type = 'not available for a Leader'
elif option.impl_is_follower():
if 'follower' not in types:
error_type = 'not available for a Follower'
else:
error_type = 'not available for an Option'
if not error_type:
if not option.impl_is_optiondescription() and \
not option.impl_is_symlinkoption() and \
option.impl_is_follower():
@ -150,9 +154,23 @@ def option_type(typ):
msg = _('please specify index with a follower option '
f'({self.__class__.__name__}.{func.__name__})')
raise ConfigError(msg)
if self._validate_properties:
settings = self._config_bag.context.get_settings()
parent = self._subconfig.parent
if parent and parent.raises_properties:
while parent:
if not parent.parent.raises_properties:
settings.validate_properties(parent,
need_help=True,
)
break
parent = parent.parent
settings.validate_properties(self._subconfig,
need_help=True,
)
return func(self, *args[1:], **kwargs)
msg = _('please specify a valid sub function '
f'({self.__class__.__name__}.{func.__name__})')
f'({self.__class__.__name__}.{func.__name__}): {error_type}')
raise ConfigError(msg)
wrapped.func = func
return wrapped
@ -201,20 +219,28 @@ class _TiramisuOptionOptionDescription:
"""Get Tiramisu option"""
return self._subconfig.option
@option_type(['optiondescription', 'option', 'with_or_without_index', 'symlink'])
def isoptiondescription(self):
"""Test if option is an optiondescription"""
return self._subconfig.option.impl_is_optiondescription()
@option_type(['optiondescription'])
def isleadership(self):
"""Test if option is a leader or a follower"""
return self._subconfig.option.impl_is_leadership()
@option_type(['optiondescription', 'option', 'with_or_without_index'])
@option_type(['optiondescription', 'option', 'with_or_without_index', 'symlink'])
def doc(self):
"""Get option document"""
return self._subconfig.option.impl_get_display_name()
return self._subconfig.option.impl_get_display_name(self._subconfig)
@option_type(['optiondescription', 'option', 'with_or_without_index'])
@option_type(['optiondescription', 'option', 'with_or_without_index', 'symlink'])
def description(self):
"""Get option description"""
return self._subconfig.option.impl_get_information('doc', None)
return self._subconfig.option._get_information(self._subconfig,
'doc',
None,
)
@option_type(['optiondescription', 'option', 'symlink', 'with_or_without_index'])
def name(self) -> str:
@ -235,7 +261,7 @@ class _TiramisuOptionOptionDescription:
"""Test if option has dependency"""
return self._subconfig.option.impl_has_dependency(self_is_dep)
@option_type(['optiondescription', 'option'])
@option_type(['optiondescription', 'option', 'symlink', 'with_or_without_index'])
def dependencies(self):
"""Get dependencies from this option"""
options = []
@ -246,31 +272,42 @@ class _TiramisuOptionOptionDescription:
))
return options
@option_type(['optiondescription', 'option', 'with_or_without_index', 'symlink'])
def isoptiondescription(self):
"""Test if option is an optiondescription"""
return self._subconfig.option.impl_is_optiondescription()
@option_type(['option', 'optiondescription', 'symlink', 'with_or_without_index'])
def type(self):
"""Get de option type"""
option = self._subconfig.option
if option.impl_is_optiondescription():
return 'optiondescription'
return option.get_type()
@option_type(['optiondescription', 'option', 'with_or_without_index', 'symlink'])
def properties(self,
only_raises=False,
uncalculated=False,
):
"""Get properties for an option"""
settings = self._config_bag.context.get_settings()
if uncalculated:
return settings.getproperties(self._subconfig,
uncalculated=True,
@option_type(['option', 'optiondescription', 'symlink', 'with_or_without_index'])
def isdynamic(self):
"""Test if option is a dynamic optiondescription"""
return self._subconfig.is_dynamic
@option_type(['option', 'leadership'])
def leader(self):
"""Get the leader option for a follower option"""
option = self._subconfig.option
if isinstance(option, Leadership):
leadership = self._subconfig
else:
leadership = self._subconfig.parent
leader_subconfig = leadership.get_child(leadership.option.get_leader(),
None,
False,
)
if not only_raises:
return settings.getproperties(self._subconfig,
apply_requires=False,
)
return settings.calc_raises_properties(self._subconfig,
apply_requires=False,
uncalculated=uncalculated,
return TiramisuOption(leader_subconfig.path,
None,
self._config_bag,
subconfig=leader_subconfig,
)
@option_type(['dynamic', 'with_or_without_index'])
def suffixes(self):
"""Get suffixes for dynamic option"""
return self._subconfig.suffixes
class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
"""Manage option"""
@ -284,7 +321,7 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
"""Test if option could have submulti value"""
return self._subconfig.option.impl_is_submulti()
@option_type(['option', 'with_or_without_index'])
@option_type(['option', 'with_or_without_index', 'symlink'])
def isleader(self):
"""Test if option is a leader"""
return self._subconfig.option.impl_is_leader()
@ -294,11 +331,6 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
"""Test if option is a follower"""
return self._subconfig.option.impl_is_follower()
@option_type(['option', 'optiondescription', 'with_or_without_index'])
def isdynamic(self):
"""Test if option is a dynamic optiondescription"""
return self._subconfig.is_dynamic
@option_type(['option', 'symlink', 'with_or_without_index'])
def issymlinkoption(self) -> bool:
"""Test if option is a symlink option"""
@ -316,14 +348,6 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
raise ConfigError(_('only multi value has defaultmulti'))
return self._subconfig.option.impl_getdefault_multi()
@option_type(['option', 'optiondescription', 'symlink', 'with_or_without_index'])
def type(self):
"""Get de option type"""
option = self._subconfig.option
if option.impl_is_optiondescription():
return 'optiondescription'
return option.get_type()
@option_type(['option', 'with_or_without_index'])
def pattern(self) -> str:
"""Get the option pattern"""
@ -340,46 +364,57 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
#FIXME only from 0.0.0.0 to 255.255.255.255
return r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
@option_type(['option', 'leadership'])
def leader(self):
"""Get the leader option for a follower option"""
option = self._subconfig.option
if isinstance(option, Leadership):
leadership = self._subconfig
else:
leadership = self._subconfig.parent
leader_subconfig = leadership.get_child(leadership.option.get_leader(),
None,
True,
)
return TiramisuOption(leader_subconfig.path,
None,
self._config_bag,
subconfig=leader_subconfig,
)
@option_type(['option', 'with_or_without_index'])
@option_type(['option', 'with_or_without_index', 'symlink'])
def index(self):
"""Get then index of option"""
"""Get index of option"""
return self._subconfig.index
@option_type(['symlink', 'optiondescription'])
def option(self, *args, **kwargs):
"""For OptionDescription get sub option, for symlinkoption get the linked option"""
if self._subconfig.option.impl_is_optiondescription():
return self._option_description(*args, **kwargs)
return self._option_symlink(*args, **kwargs)
class TiramisuOptionOption(CommonTiramisuOption):
"""Manage option"""
def __call__(self,
name: str,
index: Optional[int]=None,
) -> 'TiramisuOption':
"""Select an option by path"""
return TiramisuOption(self._path + '.' + name,
def _option_description(self,
path,
index=None,
):
sub_path = self._path + '.' + path
return TiramisuOption(sub_path,
index,
self._config_bag,
)
def _option_symlink(self):
subconfig = self._subconfig.config_bag.context._get(self._subconfig,
need_help=True,
validate_properties=self._validate_properties,
)
return TiramisuOption(subconfig.path,
subconfig.index,
self._config_bag,
subconfig=subconfig,
)
#
#
#class TiramisuOptionOption(CommonTiramisuOption):
# """Manage option"""
# _validate_properties = False
# def __call__(self,
# name: str,
# index: Optional[int]=None,
# ) -> 'TiramisuOption':
# """Select an option by path"""
# return TiramisuOption(self._path + '.' + name,
# index,
# self._config_bag,
# )
class TiramisuOptionOwner(CommonTiramisuOption):
#FIXME optiondescription must not have Owner!
"""Manage option's owner"""
_validate_properties=True
@option_type(['symlink', 'option', 'with_index'])
def get(self):
@ -410,17 +445,22 @@ class TiramisuOptionProperty(CommonTiramisuOption):
"""Manage option's property"""
_validate_properties = False
@option_type(['option', 'optiondescription', 'with_or_without_index'])
@option_type(['option', 'optiondescription', 'with_index', 'symlink'])
def get(self,
only_raises=False,
uncalculated=False,
only_raises: bool=False,
apply_requires: bool=True,
uncalculated: bool=False,
):
"""Get properties for an option"""
settings = self._config_bag.context.get_settings()
if not only_raises:
return settings.getproperties(self._subconfig)
return settings.getproperties(self._subconfig,
uncalculated=uncalculated,
apply_requires=apply_requires,
)
return settings.calc_raises_properties(self._subconfig,
uncalculated=uncalculated,
apply_requires=apply_requires,
)
@option_type(['option', 'optiondescription', 'with_or_without_index'])
@ -430,9 +470,8 @@ class TiramisuOptionProperty(CommonTiramisuOption):
raise ConfigError(_('cannot add this property: "{0}"').format(
' '.join(prop)))
settings = self._config_bag.context.get_settings()
props = settings.get_stored_properties(self._path,
props = settings.get_personalize_properties(self._path,
self._index,
self._subconfig.option.impl_getproperties(),
)
settings.setproperties(self._subconfig,
props | {prop},
@ -444,7 +483,19 @@ class TiramisuOptionProperty(CommonTiramisuOption):
):
"""Remove new property for an option"""
settings = self._config_bag.context.get_settings()
props = settings.getproperties(self._subconfig)
props = settings.get_personalize_properties(self._path,
self._index,
)
if prop not in props:
if prop in settings.getproperties(self._subconfig):
msg = f'cannot remove option\'s property "{prop}", use permissive instead'
else:
msg = f'cannot find "{prop}"'
msg += f' in option "{self._path}"'
if self._index is not None:
msg += f' at index "{self._index}"'
raise ConfigError(msg)
settings.setproperties(self._subconfig,
props - {prop},
)
@ -457,6 +508,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
class TiramisuOptionPermissive(CommonTiramisuOption):
"""Manage option's permissive"""
_validate_properties = False
@option_type(['option', 'optiondescription', 'symlink', 'with_or_without_index'])
def get(self):
@ -464,15 +516,27 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
return self._config_bag.context.get_settings().getpermissives(self._subconfig)
@option_type(['option', 'optiondescription', 'with_or_without_index'])
def set(self,
permissives,
def add(self,
permissive,
):
"""Set permissives value"""
permissives = self._config_bag.context.get_settings().getpermissives(self._subconfig)
self._config_bag.context.get_settings().setpermissives(self._subconfig,
permissives=permissives,
frozenset(permissives | {permissive}),
)
@option_type(['option', 'optiondescription', 'with_index'])
@option_type(['option', 'optiondescription', 'with_or_without_index'])
def remove(self, permissive):
"""Remove a config property"""
permissives = set(self.get())
if permissive not in permissives:
msg = f'cannot find "{permissive}"'
raise ConfigError(msg)
self._config_bag.context.get_settings().setpermissives(self._subconfig,
frozenset(permissives - {permissive}),
)
@option_type(['option', 'optiondescription', 'with_or_without_index'])
def reset(self):
"""Reset all personalised permissive"""
self._config_bag.context.get_settings().reset_permissives(self._subconfig)
@ -480,6 +544,7 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
class TiramisuOptionInformation(CommonTiramisuOption):
"""Manage option's informations"""
_validate_properties = False
@option_type(['option', 'optiondescription', 'with_or_without_index', 'symlink'])
def get(self,
@ -487,13 +552,10 @@ class TiramisuOptionInformation(CommonTiramisuOption):
default=undefined,
) -> Any:
"""Get information"""
try:
return self._config_bag.context.get_values().get_information(self._subconfig,
name,
undefined,
default,
)
except ValueError:
return self._subconfig.option.impl_get_information(name, default)
@option_type(['option', 'optiondescription'])
def set(self,
@ -506,7 +568,7 @@ class TiramisuOptionInformation(CommonTiramisuOption):
)
@option_type(['option', 'optiondescription'])
def reset(self,
def remove(self,
key: str,
) -> None:
"""Remove information"""
@ -517,7 +579,7 @@ class TiramisuOptionInformation(CommonTiramisuOption):
@option_type(['option', 'optiondescription', 'with_or_without_index', 'symlink'])
def list(self) -> list:
"""List information's keys"""
lst1 = set(self._subconfig.option.impl_list_information())
lst1 = set(self._subconfig.option._list_information())
lst2 = set(self._config_bag.context.get_values().list_information(self._path))
return lst1 | lst2
@ -584,9 +646,10 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
if not isinstance(value, Calculation) and option.impl_is_leader() and \
len(value) < self._subconfig.parent.get_length_leadership():
raise LeadershipError(_('cannot reduce length of the leader "{}"'
'').format(option.impl_get_display_name()))
return self._subconfig.config_bag.context.set_value(self._subconfig,
value,
'').format(option.impl_get_display_name(self._subconfig)))
values = self._config_bag.context.get_values()
return values.set_value(self._subconfig,
value
)
@option_type(['group', 'option', 'with_index'])
@ -624,7 +687,7 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
return False
return True
@option_type(['choice', 'with_or_without_index'])
@option_type(['choice', 'with_index'])
def list(self):
"""All values available for a ChoiceOption"""
return self._subconfig.option.impl_get_values(self._subconfig)
@ -640,7 +703,7 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
@option_type(['leader', 'follower', 'with_or_without_index'])
def len(self):
"""Length for a follower option"""
"""Length for a leadership"""
return self._subconfig.parent.get_length_leadership()
@ -674,18 +737,6 @@ class TiramisuConfig(TiramisuHelp, _TiramisuOptionWalk):
if isinstance(config, KernelGroupConfig):
return GroupConfig(config)
def _reset_config_properties(self):
config = self._config_bag.context
settings = config.get_settings()
properties = settings.get_context_properties(config.properties_cache)
permissives = settings.get_context_permissives()
self._config_bag.properties = properties
self._config_bag.permissives = permissives
if self._orig_config_bags:
for config_bag in self._orig_config_bags:
config_bag.properties = properties
config_bag.permissives = permissives
def name(self):
"""get the name"""
return self._config_bag.context.impl_getname()
@ -714,7 +765,7 @@ class TiramisuOption(CommonTiramisu,
_registers(self._registers, 'TiramisuOption')
def __repr__(self):
msg = f'<TiramisuOption path={self._path}'
msg = f'<TiramisuOption path="{self._path}"'
if self._index is not None:
msg += f', index={self._index}'
msg += '>'
@ -726,7 +777,7 @@ class TiramisuOption(CommonTiramisu,
self._index,
self._config_bag,
)
raise ConfigError(_(f'please specify a valid sub function ({self.__class__.__name__}.{subfunc})'))
raise ConfigError(_(f'please specify a valid sub function ({self.__class__.__name__}.{subfunc}) for {self._path}'))
#
# @option_type('optiondescription')
# def find(self,
@ -806,14 +857,13 @@ class TiramisuContextInformation(TiramisuConfig):
default=undefined,
):
"""Get an information"""
values = self._config_bag.context.get_values()
try:
return values.get_information(None,
context = self._config_bag.context
values = context.get_values()
subconfig = context.get_root(self._config_bag)
return values.get_information(subconfig,
name,
undefined,
default,
)
except ValueError:
return self._config_bag.context.get_description().impl_get_information(name, default)
def set(self,
name,
@ -825,7 +875,7 @@ class TiramisuContextInformation(TiramisuConfig):
value,
)
def reset(self,
def remove(self,
name,
):
"""Remove an information"""
@ -833,7 +883,7 @@ class TiramisuContextInformation(TiramisuConfig):
def list(self):
"""List information's keys"""
lst1 = set(self._config_bag.context.get_description().impl_list_information())
lst1 = set(self._config_bag.context.get_description()._list_information())
lst2 = set(self._config_bag.context.impl_list_information())
return lst1 | lst2
@ -946,30 +996,54 @@ class TiramisuContextOwner(TiramisuConfig):
values.set_context_owner(obj_owner)
class TiramisuContextProperty(TiramisuConfig):
"""Manage config properties"""
def read_only(self):
"""Set config to read only mode"""
old_props = self._config_bag.properties
settings = self._config_bag.context.get_settings()
settings.read_only(self._config_bag)
self._reset_config_properties()
# if 'force_store_value' not in old_props and \
# 'force_store_value' in self._config_bag.properties:
# self._force_store_value()
def read_write(self):
"""Set config to read and write mode"""
old_props = self._config_bag.properties
settings = self._config_bag.context.get_settings()
settings.read_write(self._config_bag)
class PropertyPermissive:
def _set_default_permissive(self,
settings,
):
or_properties = settings.rw_append - settings.ro_append - SPECIAL_PROPERTIES
permissives = frozenset(settings.get_context_permissives() | or_properties)
settings.set_context_permissives(permissives)
self._reset_config_properties()
# if 'force_store_value' not in old_props and \
# 'force_store_value' in self._config_bag.properties:
# self._force_store_value()
def _reset_config_properties(self,
settings,
):
properties = settings.get_context_properties()
permissives = settings.get_context_permissives()
self._config_bag.properties = properties
self._config_bag.permissives = permissives
if self._orig_config_bags:
for config_bag in self._orig_config_bags:
config_bag.properties = properties
config_bag.permissives = permissives
class TiramisuContextProperty(TiramisuConfig, PropertyPermissive):
"""Manage config properties"""
def read_only(self):
"""Set config to read only mode"""
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context property in unrestraint mode')
old_props = self._config_bag.properties
settings = self._config_bag.context.get_settings()
settings.read_only(self._config_bag)
self._set_default_permissive(settings)
self._reset_config_properties(settings)
if 'force_store_value' not in old_props and \
'force_store_value' in self._config_bag.properties:
self._force_store_value()
def read_write(self):
"""Set config to read and write mode"""
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context property in unrestraint mode')
old_props = self._config_bag.properties
settings = self._config_bag.context.get_settings()
settings.read_write(self._config_bag)
self._set_default_permissive(settings)
self._reset_config_properties(settings)
if 'force_store_value' not in old_props and \
'force_store_value' in self._config_bag.properties:
self._force_store_value()
def add(self, prop):
"""Add a config property"""
@ -981,35 +1055,47 @@ class TiramisuContextProperty(TiramisuConfig):
def remove(self, prop):
"""Remove a config property"""
props = set(self.get())
if prop in props:
if prop not in props:
msg = f'cannot find "{prop}"'
raise ConfigError(msg)
props.remove(prop)
self._set(frozenset(props))
def get(self):
def get(self,
only_raises: bool=False,
apply_requires: bool=True,
uncalculated: bool=False,
) -> Set:
"""Get all config properties"""
if only_raises:
return set()
return self._config_bag.properties
def _set(self,
props,
):
"""Personalise config properties"""
# if 'force_store_value' in props:
# force_store_value = 'force_store_value' not in self._config_bag.properties
# else:
# force_store_value = False
context = self._config_bag.context
context.get_settings().set_context_properties(props,
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context property in unrestraint mode')
if 'force_store_value' in props:
force_store_value = 'force_store_value' not in self._config_bag.properties
else:
force_store_value = False
settings = self._config_bag.context.get_settings()
settings.set_context_properties(props,
self._config_bag.context,
)
self._reset_config_properties()
# if force_store_value:
# self._force_store_value()
self._reset_config_properties(settings)
if force_store_value:
self._force_store_value()
def reset(self):
"""Remove config properties"""
context = self._config_bag.context
context.get_settings().reset(self._config_bag)
self._reset_config_properties()
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context property in unrestraint mode')
settings = self._config_bag.context.get_settings()
settings.reset(self._config_bag)
self._reset_config_properties(settings)
def exportation(self):
"""Export config properties"""
@ -1017,30 +1103,31 @@ class TiramisuContextProperty(TiramisuConfig):
def importation(self, properties):
"""Import config properties"""
# if 'force_store_value' in properties.get(None, {}).get(None, []):
# force_store_value = 'force_store_value' not in self._config_bag.properties
# else:
# force_store_value = False
self._config_bag.context.get_settings()._properties = deepcopy(properties)
self._config_bag.context.reset_cache(None, None)
self._reset_config_properties()
# if force_store_value:
# self._force_store_value()
#
# def _force_store_value(self):
# descr = self._config_bag.context.get_description()
# descr.impl_build_force_store_values(self._config_bag)
if 'force_store_value' in properties.get(None, {}).get(None, []):
force_store_value = 'force_store_value' not in self._config_bag.properties
else:
force_store_value = False
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context property in unrestraint mode')
context = self._config_bag.context
settings = context.get_settings()
settings._properties = deepcopy(properties)
context.reset_cache(None, None)
self._reset_config_properties(settings)
if force_store_value:
self._force_store_value()
def _force_store_value(self):
descr = self._config_bag.context.get_description()
descr.impl_build_force_store_values(self._config_bag)
def setdefault(self,
properties: Set[str],
type: Optional[str]=None,
type: Optional[str],
when: Optional[str]=None) -> None:
if not isinstance(properties, frozenset):
raise TypeError(_('properties must be a frozenset'))
setting = self._config_bag.context.get_settings()
if type is None and when is None:
setting.default_properties = properties
else:
if when not in ['append', 'remove']:
raise ValueError(_('unknown when {} (must be in append or remove)').format(when))
if type == 'read_only':
@ -1062,7 +1149,7 @@ class TiramisuContextProperty(TiramisuConfig):
) -> Set[str]:
setting = self._config_bag.context.get_settings()
if type is None and when is None:
return setting.default_properties
return DEFAULT_PROPERTIES
if type == 'current':
return setting.get_context_properties(self._config_bag.context.properties_cache)
if when not in ['append', 'remove']:
@ -1078,7 +1165,7 @@ class TiramisuContextProperty(TiramisuConfig):
raise ValueError(_('unknown type {}').format(type))
class TiramisuContextPermissive(TiramisuConfig):
class TiramisuContextPermissive(TiramisuConfig, PropertyPermissive):
"""Manage config permissives"""
def get(self):
"""Get config permissives"""
@ -1091,8 +1178,11 @@ class TiramisuContextPermissive(TiramisuConfig):
permissives,
):
"""Set config permissives"""
self._config_bag.context.get_settings().set_context_permissives(permissives)
self._reset_config_properties()
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context permissive in unrestraint mode')
settings = self._config_bag.context.get_settings()
settings.set_context_permissives(permissives)
self._reset_config_properties(settings)
def exportation(self):
"""Export config permissives"""
@ -1100,32 +1190,39 @@ class TiramisuContextPermissive(TiramisuConfig):
def importation(self, permissives):
"""Import config permissives"""
settings = self._config_bag.context.get_settings()
self._config_bag.context.get_settings()._permissives = deepcopy(permissives)
self._config_bag.context.reset_cache(None,
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context permissive in unrestraint mode')
context = self._config_bag.context
settings = context.get_settings()
settings._permissives = deepcopy(permissives)
context.reset_cache(None,
None,
)
self._reset_config_properties()
self._reset_config_properties(settings)
def reset(self):
"""Remove config permissives"""
context = self._config_bag.context
settings = context.get_settings()
if self._config_bag.is_unrestraint:
raise ConfigError('cannot change context permissive in unrestraint mode')
settings = self._config_bag.context.get_settings()
settings.reset_permissives(self._config_bag)
self._reset_config_properties()
self._set_default_permissive(settings)
self._reset_config_properties(settings)
def add(self, prop):
def add(self, permissive):
"""Add a config permissive"""
props = set(self._get())
props.add(prop)
self._set(frozenset(props))
permissives = set(self._get())
permissives.add(permissive)
self._set(frozenset(permissives))
def remove(self, prop):
def remove(self, permissive):
"""Remove a config permissive"""
props = set(self._get())
if prop in props:
props.remove(prop)
self._set(frozenset(props))
permissives = set(self._get())
if permissive not in permissives:
msg = f'cannot find "{permissive}"'
raise ConfigError(msg)
permissives.remove(permissive)
self._set(frozenset(permissives))
class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
@ -1134,31 +1231,49 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
**kwargs) -> None:
self._tiramisu_dict = None
super().__init__(*args, **kwargs)
#
# def find(self,
# name,
# value=undefined,
# type=None,
# first=False):
# """Find an or a list of options"""
# options = []
# option_bag = OptionBag(self._config_bag.context.get_description(),
# None,
# self._config_bag,
# )
# for path in self._config_bag.context.find(option_bag,
# byname=name,
# byvalue=value,
# bytype=type,
# ):
# option = TiramisuOption(path,
# None,
# self._config_bag,
# )
# if first:
# return option
# options.append(option)
# return options
def get(self):
"""Get Tiramisu option"""
return None
def isleadership(self):
"""Test if option is a leader or a follower"""
return False
def doc(self):
"""Get option document"""
return self._config_bag.context.get_description().impl_get_display_name(None)
def description(self):
"""Get option description"""
return self._config_bag.context.get_description()._get_information(None, 'doc', None)
def name(self):
"""Get option name"""
return None
def path(self,
):
"""Get option path"""
return None
def has_dependency(self,
self_is_dep=True,
) -> bool:
"""Test if option has dependency"""
return False
def isoptiondescription(self):
"""Test if option is an optiondescription"""
return True
def isdynamic(self):
"""Test if option is a dynamic optiondescription"""
return False
def type(self):
"""Get de option type"""
return 'optiondescription'
def list(self,
validate_properties: bool=True,
@ -1362,12 +1477,17 @@ class TiramisuAPI(TiramisuHelp):
if not self._registers:
_registers(self._registers, 'TiramisuContext')
def __getattr__(self, subfunc: str) -> Any:
if subfunc == 'option':
config_bag = self._config_bag
return TiramisuDispatcherOption(config_bag,
self._orig_config_bags,
def option(self,
path: str,
index: Optional[int]=None,
) -> TiramisuOption:
"""Select an option by path"""
return TiramisuOption(path,
index,
self._config_bag,
)
def __getattr__(self, subfunc: str) -> Any:
if subfunc in ['forcepermissive', 'unrestraint', 'nowarnings']:
if self._orig_config_bags:
msg = _('do not use unrestraint, nowarnings or forcepermissive together')
@ -1379,7 +1499,7 @@ class TiramisuAPI(TiramisuHelp):
config_bag.nowarnings()
else:
config_bag.set_permissive()
return TiramisuAPI(config_bag, [self._config_bag])
return ConfigProp(config_bag, [self._config_bag])
if subfunc == 'config':
config_type = self._config_bag.context.impl_type
if config_type == 'group':
@ -1404,20 +1524,12 @@ class TiramisuAPI(TiramisuHelp):
['unrestraint', 'forcepermissive', 'nowarnings', 'config']
class TiramisuDispatcherOption(TiramisuContextOption):
"""Select an option"""
def __call__(self,
path: str,
index: Optional[int]=None,
) -> TiramisuOption:
"""Select an option by path"""
return TiramisuOption(path,
index,
self._config_bag,
)
class ConfigProp(TiramisuAPI, TiramisuContextOption):
def __repr__(self):
return f'<Config path=None>'
class Config(TiramisuAPI):
class Config(TiramisuAPI, TiramisuContextOption):
"""Root config object that enables us to handle the configuration options"""
def __init__(self,
descr: OptionDescription,
@ -1432,7 +1544,7 @@ class Config(TiramisuAPI):
display_name=display_name,
)
settings = config.get_settings()
properties = settings.get_context_properties(config.properties_cache)
properties = settings.get_context_properties()
permissives = settings.get_context_permissives()
config_bag = ConfigBag(config,
properties=properties,
@ -1448,6 +1560,9 @@ class Config(TiramisuAPI):
except ConfigError:
pass
def __repr__(self):
return f'<Config path=None>'
class MetaConfig(TiramisuAPI):
"""MetaConfig object that enables us to handle the sub configuration's options
@ -1478,7 +1593,7 @@ class MetaConfig(TiramisuAPI):
display_name=display_name,
)
settings = config.get_settings()
properties = settings.get_context_properties(config.properties_cache)
properties = settings.get_context_properties()
permissives = settings.get_context_permissives()
config_bag = ConfigBag(config,
properties=properties,

View file

@ -19,16 +19,47 @@
# ____________________________________________________________
"enables us to carry out a calculation and return an option's value"
from typing import Any, Optional, Union, Callable, Dict, List
from os.path import commonprefix
from itertools import chain
import weakref
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
from .i18n import _
from .setting import undefined, ConfigBag, Undefined
from .setting import undefined, ConfigBag
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:
__slots__ = ('args', 'kwargs')
def __init__(self, args=None, kwargs=None, **kwgs):
@ -85,13 +116,11 @@ class ParamOption(Param):
class ParamDynOption(ParamOption):
__slots__ = ('suffixes',
'dynoptiondescription',
'optional',
)
def __init__(self,
option: 'Option',
suffixes: list[str],
dynoptiondescription: 'DynOptionDescription'=None,
notraisepropertyerror: bool=False,
raisepropertyerror: bool=False,
optional: bool=False,
@ -101,7 +130,6 @@ class ParamDynOption(ParamOption):
raisepropertyerror,
)
self.suffixes = suffixes
self.dynoptiondescription = dynoptiondescription
self.optional = optional
@ -125,6 +153,7 @@ class ParamInformation(Param):
__slots__ = ('information_name',
'default_value',
'option',
'self_option',
)
def __init__(self,
information_name: str,
@ -133,7 +162,22 @@ class ParamInformation(Param):
) -> None:
self.information_name = information_name
self.default_value = default_value
self.self_option = None
self.option = None
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():
raise ValueError(_('option in ParamInformation cannot be a symlinkoption'))
if option.impl_is_follower():
@ -141,10 +185,27 @@ class ParamInformation(Param):
if option.impl_is_dynsymlinkoption():
raise ValueError(_('option in ParamInformation cannot be a dynamic 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):
__slots__ = tuple()
def __init__(self,
information_name: str,
default_value: Any=undefined,
) -> None:
return super().__init__(information_name,
default_value,
)
class ParamIndex(Param):
@ -152,7 +213,11 @@ class ParamIndex(Param):
class ParamSuffix(Param):
__slots__ = tuple()
__slots__ = ('suffix_index',)
def __init__(self,
suffix_index: int=-1,
) -> None:
self.suffix_index = suffix_index
class Calculation:
@ -190,6 +255,7 @@ class Calculation:
allow_value_error: bool=False,
force_value_warning: bool=False,
for_settings: bool=False,
validate_properties: bool=True,
) -> Any:
return carry_out_calculation(subconfig,
callback=self.function,
@ -200,6 +266,7 @@ class Calculation:
allow_value_error=allow_value_error,
force_value_warning=force_value_warning,
for_settings=for_settings,
validate_properties=validate_properties,
)
def help(self,
@ -229,6 +296,7 @@ def manager_callback(callback: Callable,
orig_value,
config_bag: ConfigBag,
for_settings: bool,
validate_properties: bool,
) -> Any:
"""replace Param by true value"""
option = subconfig.option
@ -297,18 +365,18 @@ def manager_callback(callback: Callable,
return value
def _get_value(param: Params,
subconfig: SubConfig,
subconfig: 'SubConfig',
) -> Any:
try:
# get value
value = config_bag.context.get_value(subconfig)
except PropertiesOptionError as err:
# 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 ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from 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
except AttributeError as err:
if isinstance(param, ParamDynOption) and param.optional:
@ -317,7 +385,7 @@ def manager_callback(callback: Callable,
['configerror'],
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
return value
@ -341,7 +409,7 @@ def manager_callback(callback: Callable,
config_bag.remove_validation()
# root = config_bag.context.get_root(config_bag)
try:
subconfig = config_bag.context.get_sub_config(config_bag,
subsubconfig = config_bag.context.get_sub_config(config_bag,
opt.impl_getpath(),
index_,
validate_properties=not self_calc,
@ -351,10 +419,10 @@ def manager_callback(callback: Callable,
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
if param.notraisepropertyerror or param.raisepropertyerror:
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
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:
if isinstance(param, ParamDynOption) and param.optional:
# cannot acces, simulate a propertyerror
@ -362,19 +430,9 @@ def manager_callback(callback: Callable,
['configerror'],
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
return subconfig
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
return subsubconfig
if isinstance(param, ParamValue):
return param.value
@ -383,6 +441,14 @@ def manager_callback(callback: Callable,
if isinstance(param, ParamSelfInformation):
isubconfig = subconfig
elif param.option:
if param.option.issubdyn():
search_option = param.option
isubconfig = subconfig.get_common_child(search_option,
true_path=subconfig.path,
)
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,
@ -391,14 +457,14 @@ def manager_callback(callback: Callable,
#properties=properties,
)
else:
isubconfig = None
isubconfig = config_bag.context.get_root(config_bag)
try:
return config_bag.context.get_values().get_information(isubconfig,
param.information_name,
param.default_value,
)
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
if isinstance(param, ParamIndex):
@ -406,9 +472,9 @@ def manager_callback(callback: Callable,
if isinstance(param, ParamSuffix):
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'))
return subconfig.suffixes[-1]
return subconfig.suffixes[param.suffix_index]
if isinstance(param, ParamSelfOption):
value = calc_self(param,
@ -418,45 +484,13 @@ def manager_callback(callback: Callable,
)
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
return value
return {'name': option.impl_get_display_name(),
return {'name': option.impl_get_display_name(subconfig),
'value': value,
}
if isinstance(param, ParamOption):
callbk_option = param.option
callbk_options = None
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)
config_bag = subconfig.config_bag
if index is not None and callbk_option.impl_get_leadership() and \
callbk_option.impl_get_leadership().in_same_leadership(option):
if not callbk_option.impl_is_follower():
@ -470,7 +504,69 @@ def manager_callback(callback: Callable,
else:
index_ = None
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,
callbk_option,
param,
@ -479,13 +575,7 @@ def manager_callback(callback: Callable,
#properties=properties,
)
]
# callbk_options = [callbk_option]
values = None
else:
values = []
#FIXME
values = None
# for callbk_option in callbk_options:
for subconfig in subconfigs:
callbk_option = subconfig.option
value = get_value(config_bag,
@ -501,7 +591,7 @@ def manager_callback(callback: Callable,
value = values
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
return value
return {'name': callbk_option.impl_get_display_name(),
return {'name': callbk_option.impl_get_display_name(subconfig),
'value': value}
@ -514,6 +604,8 @@ def carry_out_calculation(subconfig: 'SubConfig',
allow_value_error: bool=False,
force_value_warning: bool=False,
for_settings: bool=False,
*,
validate_properties: bool=True,
):
"""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 ''."""
option = subconfig.option
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):
return ((None, i) for i in iterator)
args = []
@ -548,20 +640,21 @@ def carry_out_calculation(subconfig: 'SubConfig',
orig_value,
config_bag,
for_settings,
validate_properties,
)
if key is None:
args.append(value)
else:
kwargs[key] = value
except PropertiesOptionError as err:
if param.raisepropertyerror:
if isinstance(param, ParamSelfOption) or param.raisepropertyerror:
raise err
if callback.__name__ in FUNCTION_WAITING_FOR_DICT:
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:
kwargs[key] = {'propertyerror': str(err), 'name': option.impl_get_display_name()}
ret = calculate(option,
kwargs[key] = {'propertyerror': str(err), 'name': option.impl_get_display_name(subconfig)}
ret = calculate(subconfig,
callback,
allow_value_error,
force_value_warning,
@ -579,17 +672,17 @@ def carry_out_calculation(subconfig: 'SubConfig',
args,
kwargs,
ret,
option.impl_get_display_name()))
option.impl_get_display_name(subconfig)))
else:
raise LeadershipError(_('the "{}" function must not return a list ("{}") '
'for the follower option "{}"'
'').format(callback.__name__,
ret,
option.impl_get_display_name()))
option.impl_get_display_name(subconfig)))
return ret
def calculate(option,
def calculate(subconfig,
callback: Callable,
allow_value_error: bool,
force_value_warning: bool,
@ -617,12 +710,12 @@ def calculate(option,
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
'for option "{2}"').format(str(error),
callback.__name__,
option.impl_get_display_name(),
subconfig.option.impl_get_display_name(subconfig),
args,
kwargs)
else:
msg = _('unexpected error "{0}" in function "{1}" for option "{2}"'
'').format(str(error),
callback.__name__,
option.impl_get_display_name())
subconfig.option.impl_get_display_name(subconfig))
raise ConfigError(msg) from error

View file

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

View file

@ -23,6 +23,7 @@
import weakref
from copy import copy, deepcopy
from typing import Optional, List, Any, Union
from os.path import commonprefix
from .error import PropertiesOptionError, ConfigError, ConflictError, \
LeadershipError
@ -35,6 +36,17 @@ from .autolib import Calculation
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:
__slots__ = tuple()
# =============================================================================
@ -171,6 +183,7 @@ class SubConfig:
'path',
'true_path',
'properties',
'raises_properties',
'is_dynamic',
'suffixes',
'_length',
@ -187,8 +200,6 @@ class SubConfig:
properties: Union[list[str], undefined]=undefined,
validate_properties: bool=True,
) -> None:
if path and '.' in path and not parent:
raise Exception('pff connard')
self.index = index
self.suffixes = suffixes
self.option = option
@ -198,12 +209,14 @@ class SubConfig:
self.path = path
if true_path is None:
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
settings = config_bag.context.get_settings()
if properties is undefined:
if path is None:
self.properties = frozenset()
else:
settings = config_bag.context.get_settings()
self.properties = frozenset()
if validate_properties:
self.properties = settings.getproperties(self,
@ -211,7 +224,7 @@ class SubConfig:
)
self.config_bag.context.get_settings().validate_properties(self)
self.properties = settings.getproperties(self,
apply_requires=True,
apply_requires=apply_requires,
)
else:
self.properties = properties
@ -221,6 +234,15 @@ class SubConfig:
self.is_dynamic = False
if validate_properties:
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):
return f'<SubConfig path={self.path}, index={self.index}>'
@ -228,7 +250,8 @@ class SubConfig:
def dyn_to_subconfig(self,
child: Option,
validate_properties: bool,
follower_not_apply_requires: bool=False,
*,
true_path: Optional[str]=None,
) -> List['SubConfig']:
config_bag = self.config_bag
for suffix in child.get_suffixes(self):
@ -241,10 +264,10 @@ class SubConfig:
yield self.get_child(child,
None,
validate_properties,
follower_not_apply_requires=follower_not_apply_requires,
suffix=suffix,
name=name,
properties=properties,
true_path=true_path,
)
except PropertiesOptionError as err:
if err.proptype in (['mandatory'], ['empty']):
@ -298,7 +321,6 @@ class SubConfig:
validate_properties: bool,
*,
properties=undefined,
follower_not_apply_requires: bool=False,
allow_dynoption: bool=False,
suffix: Optional[str]=None,
name: Optional[str]=None,
@ -312,24 +334,6 @@ class SubConfig:
if not self.option.impl_is_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,
option,
)
@ -340,7 +344,7 @@ class SubConfig:
suffixes = self.suffixes + [suffix]
else:
suffixes = [suffix]
return SubConfig(option,
subsubconfig = SubConfig(option,
index,
path,
self.config_bag,
@ -350,6 +354,17 @@ class SubConfig:
validate_properties=validate_properties,
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,
name: str,
@ -379,10 +394,77 @@ class SubConfig:
cconfig_bag,
self,
self.suffixes,
validate_properties=False,
)
self._length = len(cconfig_bag.context.get_value(subconfig))
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):
@ -486,7 +568,6 @@ class _Config(CCache):
path,
None,
validate_properties=True,
follower_not_apply_requires=False,
)
except PropertiesOptionError:
continue
@ -541,7 +622,6 @@ class _Config(CCache):
index,
*,
validate_properties: bool=True,
follower_not_apply_requires: bool=False,
properties=undefined,
true_path: Optional[str]=None,
):
@ -577,7 +657,6 @@ class _Config(CCache):
subconfig = subconfig.get_child(option,
index_,
validate_properties,
follower_not_apply_requires=follower_not_apply_requires,
properties=properties,
name=name,
suffix=suffix,
@ -647,17 +726,6 @@ class _Config(CCache):
# =============================================================================
# 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,
subconfig,
need_help=True,
@ -672,8 +740,9 @@ class _Config(CCache):
if isinstance(subconfig, list):
value = []
follower_subconfig = None
is_follower = not subconfig or subconfig[0].option.impl_is_follower()
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,
sconfig.path,
sconfig.index,
@ -692,7 +761,7 @@ class _Config(CCache):
length = subconfig.parent.get_length_leadership()
follower_len = self.get_values().get_max_length(subconfig.path)
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}" '
f'has greater length ({follower_len}) than the leader '
f'length ({length})'))
@ -704,6 +773,7 @@ class _Config(CCache):
def _get(self,
subconfig: "SubConfig",
need_help: bool,
validate_properties: bool=True,
) -> "OptionBag":
# pylint: disable=too-many-locals
option = subconfig.option
@ -712,17 +782,15 @@ class _Config(CCache):
suboption = option.impl_getopt()
if suboption.issubdyn():
dynopt = suboption.getsubdyn()
return list(dynopt.get_sub_children(suboption,
suboption.config_bag,
index=suboption.index,
return subconfig.get_common_child(suboption,
true_path=subconfig.path,
))
validate_properties=validate_properties,
)
if suboption.impl_is_follower():
subconfig = self.get_sub_config(subconfig.config_bag, # pylint: disable=no-member
suboption.impl_getpath(),
None,
validate_properties=True,
follower_not_apply_requires=False,
validate_properties=validate_properties,
true_path=subconfig.path,
)
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
suboption.impl_getpath(),
None,
validate_properties=True,
follower_not_apply_requires=False,
validate_properties=validate_properties,
true_path=subconfig.path,
)
return self._get(s_subconfig,
@ -818,6 +885,7 @@ class _CommonConfig(_Config):
self.reset_cache(option_bag)
def impl_get_information(self,
subconfig,
key,
default,
):
@ -893,7 +961,7 @@ class _CommonConfig(_Config):
duplicated_settings.rw_append = self.get_settings().rw_append
duplicated_settings.ro_remove = self.get_settings().ro_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)
if child is not None:
duplicated_config._impl_children.append(child) # pylint: disable=protected-access
@ -1412,7 +1480,7 @@ class KernelMixConfig(KernelGroupConfig):
)
# Copy context properties/permissives
settings = config.get_settings()
properties = settings.get_context_properties(config.properties_cache)
properties = settings.get_context_properties()
settings.set_context_properties(properties,
config,
)
@ -1421,7 +1489,7 @@ class KernelMixConfig(KernelGroupConfig):
settings.rw_append = settings.rw_append
settings.ro_remove = settings.ro_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))
self._impl_children.append(config)

View file

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

View file

@ -944,7 +944,7 @@ msgstr "option \"{0}\" inconnue dans l'optiondescription \"{1}\""
#: tiramisu/option/optiondescription.py:279
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
msgid "duplicate option name: \"{0}\""

View file

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

View file

@ -20,22 +20,23 @@
# ____________________________________________________________
"""DynOptionDescription
"""
import re
import weakref
from typing import List, Any, Optional
from typing import List, Any, Optional, Dict
from itertools import chain
from ..autolib import ParamOption
from ..i18n import _
from .optiondescription import OptionDescription
from .syndynoption import CommonDyn #, SynDynLeadership
from .baseoption import BaseOption
from ..setting import ConfigBag, undefined
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
"""
__slots__ = ('_suffixes',
@ -48,25 +49,28 @@ class DynOptionDescription(OptionDescription, CommonDyn):
children: List[BaseOption],
suffixes: Calculation,
properties=None,
informations: Optional[Dict]=None,
) -> None:
# pylint: disable=too-many-arguments
super().__init__(name,
doc,
children,
properties,
informations=informations,
)
# check children + set relation to this dynoptiondescription
wself = weakref.ref(self)
for child in children:
child._setsubdyn(wself)
# add suffixes
if __debug__ and not isinstance(suffixes, Calculation):
raise ConfigError(_('suffixes in dynoptiondescription has to be a calculation'))
for param in chain(suffixes.params.args, suffixes.params.kwargs.values()):
if isinstance(param, ParamOption):
param.option._add_dependency(self,
is_suffix=True,
)
self.value_dependencies(suffixes, is_suffix=True)
# if __debug__ and not isinstance(suffixes, Calculation):
# raise ConfigError(_('suffixes in dynoptiondescription has to be a calculation'))
# for param in chain(suffixes.params.args, suffixes.params.kwargs.values()):
# if isinstance(param, ParamOption):
# param.option._add_dependency(self,
# is_suffix=True,
# )
self._suffixes = suffixes
def convert_suffix_to_path(self,
@ -98,3 +102,42 @@ class DynOptionDescription(OptionDescription, CommonDyn):
return name
path_suffix = self.convert_suffix_to_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):
if child.impl_is_symlinkoption():
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):
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():
raise ValueError(_('only multi option allowed in leadership "{0}" but option '
'"{1}" is not a multi'
'').format(self.impl_get_display_name(),
child.impl_get_display_name()))
'').format(self.impl_get_display_name(None),
child.impl_get_display_name(None)))
def _check_default_value(self, child: BaseOption):
default = child.impl_getdefault()
@ -100,8 +100,8 @@ class Leadership(OptionDescription):
calculation = isinstance(default, Calculation)
if not calculation:
raise ValueError(_('not allowed default value for follower option '
f'"{child.impl_get_display_name()}" in leadership '
f'"{self.impl_get_display_name()}"'))
f'"{child.impl_get_display_name(None)}" in leadership '
f'"{self.impl_get_display_name(None)}"'))
def _setsubdyn(self,
subdyn,
@ -143,58 +143,54 @@ class Leadership(OptionDescription):
def reset(self, parent: "SubConfig") -> None:
"""reset follower value
"""
#config_bag = parent.option_bag.config_bag
values = parent.config_bag.context.get_values()
#config_bag = config_bag.copy()
#config_bag.remove_validation()
for follower in self.get_followers():
subconfig_follower = parent.get_child(follower,
None,
False,
)
# OptionBag(follower,
# None,
# config_bag,
# )
values.reset(subconfig_follower)
#
# def follower_force_store_value(self,
# value,
# config_bag: 'ConfigBag',
# owner,
# dyn=None,
# ) -> None:
# """apply force_store_value to follower
# """
# if value:
# if dyn is None:
# dyn = self
# values = config_bag.context.get_values()
# for idx, follower in enumerate(dyn.get_children(config_bag)):
# if not idx:
# # it's a master
# apply_requires = True
# indexes = [None]
# else:
# apply_requires = False
# indexes = range(len(value))
# foption_bag = OptionBag(follower,
# None,
# config_bag,
# apply_requires=apply_requires,
# )
# if 'force_store_value' not in foption_bag.properties:
# continue
# for index in indexes:
# foption_bag_index = OptionBag(follower,
# index,
# config_bag,
# )
# values.set_storage_value(foption_bag_index.path,
# index,
# values.get_value(foption_bag_index)[0],
# owner,
# )
values.reset(subconfig_follower,
validate=False,
)
def follower_force_store_value(self,
value,
subconfig: 'SubConfig',
owner,
) -> None:
"""apply force_store_value to follower
"""
if not value:
return
config_bag = subconfig.config_bag
values = config_bag.context.get_values()
for idx, follower in enumerate(self.get_children()):
sub_subconfig = subconfig.get_child(follower,
None,
False,
config_bag=config_bag,
)
if 'force_store_value' not in sub_subconfig.properties:
continue
self_path = sub_subconfig.path
if not idx:
# it's a master
apply_requires = True
indexes = [None]
else:
apply_requires = False
indexes = range(len(value))
for index in indexes:
i_sub_subconfig = subconfig.get_child(follower,
index,
False,
config_bag=config_bag,
)
values.set_storage_value(self_path,
index,
values.get_value(i_sub_subconfig)[0],
owner,
)
def pop(self,
subconfig: 'SubConfig',

View file

@ -26,9 +26,8 @@ from itertools import chain
from .baseoption import BaseOption, submulti
from ..i18n import _
from ..setting import undefined
from ..autolib import Calculation, ParamOption, ParamInformation, ParamSelfInformation
from ..autolib import Calculation
from ..error import ValueWarning, ValueErrorWarning, ValueOptionError
from .syndynoption import SynDynOption
class Option(BaseOption):
@ -48,7 +47,6 @@ class Option(BaseOption):
#
'_validators',
#
'_dependencies_information',
'_leadership',
'_choice_values',
'_choice_values_params',
@ -63,7 +61,9 @@ class Option(BaseOption):
validators: Optional[List[Calculation]]=None,
properties: Optional[List[str]]=None,
warnings_only: bool=False,
extra: Optional[Dict]=None):
extra: Optional[Dict]=None,
informations: Optional[Dict]=None,
):
_setattr = object.__setattr__
if not multi and default_multi is not None:
raise ValueError(_("default_multi is set whereas multi is False"
@ -92,8 +92,10 @@ class Option(BaseOption):
default = []
super().__init__(name,
doc,
informations,
properties=properties,
is_multi=is_multi)
is_multi=is_multi,
)
if validators is not None:
if __debug__ and not isinstance(validators, list):
raise ValueError(_(f'validators must be a list of Calculation for "{name}"'))
@ -126,10 +128,10 @@ class Option(BaseOption):
if not str_err:
raise ValueError(_('invalid default_multi value "{0}" '
'for option "{1}"').format(str(value),
self.impl_get_display_name())
self.impl_get_display_name(None))
) from err
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
if _multi is submulti:
if not isinstance(default_multi, Calculation):
@ -137,7 +139,7 @@ class Option(BaseOption):
raise ValueError(_('invalid default_multi value "{0}" '
'for option "{1}", must be a list for a submulti'
'').format(str(default_multi),
self.impl_get_display_name()))
self.impl_get_display_name(None)))
for value in default_multi:
test_multi_value(value)
else:
@ -164,43 +166,6 @@ class Option(BaseOption):
default = tuple(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
@ -326,7 +291,8 @@ class Option(BaseOption):
**kwargs,
)
except ValueWarning as warn:
warnings.warn_explicit(ValueWarning(val,
warnings.warn_explicit(ValueWarning(subconfig,
val,
self.get_type(),
self,
str(warn),
@ -343,7 +309,7 @@ class Option(BaseOption):
return
if isinstance(_value, list):
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:
return
@ -361,7 +327,8 @@ class Option(BaseOption):
is_warnings_only)
except ValueError as err:
if is_warnings_only:
warnings.warn_explicit(ValueWarning(_value,
warnings.warn_explicit(ValueWarning(subconfig,
_value,
self.get_type(),
self,
str(err),
@ -420,12 +387,14 @@ class Option(BaseOption):
except ValueError as err:
if not subconfig or \
'demoting_error_warning' not in subconfig.config_bag.properties:
raise ValueOptionError(val,
raise ValueOptionError(subconfig,
val,
self.get_type(),
self,
str(err),
err_index) from err
warnings.warn_explicit(ValueErrorWarning(val,
warnings.warn_explicit(ValueErrorWarning(subconfig,
val,
self.get_type(),
self,
str(err),
@ -476,16 +445,6 @@ class Option(BaseOption):
#pylint: disable=not-callable
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):
"""option needs a validate function
"""

View file

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

View file

@ -20,7 +20,7 @@
# ____________________________________________________________
"""SymLinkOption link to an other option
"""
from typing import Any
from typing import Any, Optional, Dict
from .baseoption import BaseOption, valid_name
from ..error import ConfigError
from ..i18n import _
@ -41,55 +41,46 @@ class SymLinkOption(BaseOption):
if not isinstance(opt, BaseOption) or \
opt.impl_is_optiondescription() or \
opt.impl_is_symlinkoption():
raise ValueError(_('malformed symlinkoption must be an option for symlink {0}'
'').format(name))
_setattr = object.__setattr__
_setattr(self, '_name', name)
_setattr(self, '_opt', opt)
raise ValueError(_(f'malformed symlink second parameters must be an option for "{name}", not {opt}'))
self._name = name
self._opt = opt
opt._add_dependency(self)
def __getattr__(self,
name: str,
) -> Any:
if name == '_subdyns':
return None
if name == '_path':
raise AttributeError()
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:
"""it's a symlinkoption
"""
return True
def impl_is_leader(self) -> bool:
return False
def impl_is_follower(self) -> bool:
return False
def impl_getopt(self) -> BaseOption:
"""get to linked option
"""
return self._opt
def issubdyn(self) -> bool:
"""it's not a sub dyn option
"""
return False
def impl_is_multi(self) -> bool:
"""is it a multi?
"""
if self._opt.issubdyn():
if self._opt.impl_is_multi():
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:
"""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 itertools import chain
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list
from .i18n import _
@ -156,63 +156,6 @@ class 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:
@ -390,7 +333,6 @@ class Settings:
'ro_remove',
'rw_append',
'rw_remove',
'default_properties',
)
def __init__(self):
@ -401,9 +343,8 @@ class Settings:
:param storage: the storage type
"""
# generic owner
self._properties = {}
self._properties = {None: {None: DEFAULT_PROPERTIES}}
self._permissives = {}
self.default_properties = DEFAULT_PROPERTIES
self.ro_append = RO_APPEND
self.ro_remove = RO_REMOVE
self.rw_append = RW_APPEND
@ -412,35 +353,19 @@ class Settings:
# ____________________________________________________________
# get properties and permissive methods
def get_context_properties(self,
cache,
):
def get_context_properties(self):
"""get context properties
"""
is_cached, props, _ = cache.getcache(None,
'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
return self.get_personalize_properties()
def get_stored_properties(self,
path: Union[None, str],
index: Union[None, int],
default_properties: Set[str],
def get_personalize_properties(self,
path: Union[None, str]=None,
index: Union[None, int]=None,
) -> Set[str]:
"""Get the properties modified by user for a path or index
"""
if path not in self._properties or index not in self._properties[path]:
return frozenset(default_properties)
return frozenset()
return self._properties[path][index]
def getproperties(self,
@ -467,18 +392,17 @@ class Settings:
if not is_cached:
props = set()
# if index, get option's properties (without index) too
p_props = self.get_stored_properties(subconfig.path,
None,
option.impl_getproperties(),
)
p_props = [option.impl_getproperties()]
props_config = self.get_personalize_properties(subconfig.path)
if props_config:
p_props.append(props_config)
if subconfig.index is not None:
p_props = chain(p_props,
self.get_stored_properties(subconfig.path,
props_config = self.get_personalize_properties(subconfig.path,
subconfig.index,
option.impl_getproperties(),
)
)
for prop in p_props:
if props_config:
p_props.append(props_config)
for prop in chain(*p_props):
if uncalculated or isinstance(prop, str):
if not help_property:
props.add(prop)
@ -520,6 +444,12 @@ class Settings:
props,
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
def get_context_permissives(self):
@ -566,7 +496,7 @@ class Settings:
def set_context_properties(self, properties, context):
"""set context properties
"""
self._properties.setdefault(None, {})[None] = properties
self._properties[None][None] = properties
context.reset_cache(None)
def setproperties(self,
@ -580,7 +510,7 @@ class Settings:
if not opt.impl_is_optiondescription() and opt.impl_is_leader():
not_allowed_properties = properties - ALLOWED_LEADER_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'))
if ('force_default_on_freeze' in properties or \
'force_metaconfig_on_freeze' in properties) and 'frozen' not in properties:
@ -682,9 +612,11 @@ class Settings:
# validate properties
def calc_raises_properties(self,
subconfig,
*,
apply_requires=True,
uncalculated=False,
transitive_raise=True,
not_unrestraint=False,
):
"""raise if needed
"""
@ -698,16 +630,23 @@ class Settings:
)
return self._calc_raises_properties(subconfig,
option_properties,
not_unrestraint,
)
def _calc_raises_properties(self,
subconfig,
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
if raises_properties and 'permissive' in raises_properties:
raises_properties -= subconfig.config_bag.permissives
raises_properties -= config_bag.permissives
properties = option_properties & raises_properties
# at this point it should not remain any property for the option
return properties
@ -736,6 +675,7 @@ class Settings:
calc_properties = []
for property_ in self._calc_raises_properties(subconfig,
set(help_properties.keys()),
False,
):
calc_properties.append(help_properties[property_])
calc_properties = frozenset(calc_properties)
@ -799,10 +739,7 @@ class Settings:
append,
config_bag,
):
props = self.get_stored_properties(None,
None,
self.default_properties,
)
props = self.get_personalize_properties()
modified = False
if remove & props:
props = props - remove

View file

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

View file

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