TiramisuOption.list() with follower

This commit is contained in:
egarette@silique.fr 2023-06-26 19:25:57 +02:00
parent ad31fc85bb
commit 3641eb39d8
6 changed files with 51 additions and 21 deletions

View file

@ -268,7 +268,7 @@ def test_cache_leadership():
assert set(cache.keys()) == set([None, '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, None])
assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == {0}
#
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1'])
cfg.option('ip_admin_eth0.ip_admin_eth0').value.get()
@ -286,7 +286,7 @@ def test_cache_leadership():
assert set(cache.keys()) == set([None, '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([None, 0, 1])
assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == set([0, 1])
#DEL, insert, ...
# assert not list_sessions()
@ -398,19 +398,20 @@ def test_cache_leader_and_followers():
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)},
'val1.val2': val_val2_props})
})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.dict()
#has value
idx_val2 = 0
val_val2 = None
val_val2_props = {idx_val2: (val1_val2_props, None), None: (set(), None)}
val_val2_props = {idx_val2: (val1_val2_props, None)}
compare(settings.get_cached(), {None: {None: (global_props, None)},
'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)},
'val1.val2': {idx_val2: (val_val2, None)}})
'val1.val2': {idx_val2: (val_val2, None)},
})
cfg.option('val1.val1').value.set([undefined, undefined])
cfg.value.dict()
cfg.option('val1.val2', 1).value.set('oui')
@ -446,7 +447,7 @@ def test_cache_leader_callback():
cfg.option('val1.val1').value.set([undefined])
compare(settings.get_cached(), {None: {None: (set(global_props), None)},
'val1.val1': {None: (val1_val1_props, None)},
'val1.val2': {None: (val1_val2_props, None)}})
})
compare(values.get_cached(), {'val1.val1': {None: ([None], None, True)}})
cfg.value.dict()

View file

@ -880,3 +880,17 @@ def test_pprint_not_todict():
def test_property_invalid_type():
with pytest.raises(ValueError):
s3 = StrOption("string3", "", default=["string"], default_multi="string", multi=True, properties=(1,))
def test_settings_list_with_follower():
leader = StrOption("leader", "leader", default=['leader'], multi=True)
option = StrOption("str", "str", default_multi="dhcp", multi=True, properties=frozenset({'disabled'}))
ip = StrOption(name="ip",
doc="ip",
multi=True,
properties=frozenset({"basic", "mandatory", Calculation(calc_value, Params(ParamValue('disabled'), kwargs={'condition': ParamOption(option, notraisepropertyerror=True), 'expected': ParamValue("ipv4"), 'reverse_condition': ParamValue(True)}), calc_value_property_help)}),
)
descr = Leadership("root", "", [leader, option, ip])
cfg = Config(OptionDescription('root', 'root', [descr]))
cfg.property.read_write()
assert len(cfg.option('root').list('all')) == 2

View file

@ -89,12 +89,15 @@ class TiramisuHelp:
class CommonTiramisu(TiramisuHelp):
_validate_properties = True
def _get_options_bag(self) -> OptionBag:
def _get_options_bag(self,
follower_not_apply_requires: bool,
) -> OptionBag:
try:
options_bag = self._config_bag.context.get_sub_option_bag(self._config_bag,
self._path,
self._index,
self._validate_properties,
follower_not_apply_requires=follower_not_apply_requires,
)
except AssertionError as err:
raise ConfigError(str(err))
@ -122,7 +125,7 @@ def option_type(typ):
)]
kwargs['is_group'] = True
return func(self, options_bag, *args[1:], **kwargs)
options_bag = self._get_options_bag()
options_bag = self._get_options_bag('with_index' not in types)
option = options_bag[-1].option
if option.impl_is_optiondescription() and 'optiondescription' in types or \
not option.impl_is_optiondescription() and (
@ -135,12 +138,13 @@ def option_type(typ):
if not option.impl_is_optiondescription() and \
not option.impl_is_symlinkoption() and \
option.impl_is_follower():
# default is "without_index"
if 'with_index' not in types and 'with_or_without_index' not in types and \
self._index is not None:
msg = _('please do not specify index '
f'({self.__class__.__name__}.{func.__name__})')
raise ConfigError(_(msg))
if 'with_index' in types and self._index is None:
if self._index is None and 'with_index' in types:
msg = _('please specify index with a follower option '
f'({self.__class__.__name__}.{func.__name__})')
raise ConfigError(msg)
@ -251,7 +255,7 @@ class _TiramisuOptionOptionDescription:
option_bag = options_bag[-1]
return option_bag.path
@option_type(['optiondescription', 'option', 'symlink'])
@option_type(['optiondescription', 'option', 'symlink', 'with_or_without_index'])
def has_dependency(self,
options_bag: List[OptionBag],
self_is_dep=True,
@ -355,7 +359,7 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
return 'optiondescription'
return option_bag.option.get_type()
@option_type('option')
@option_type(['option', 'with_or_without_index'])
def pattern(self, options_bag: List[OptionBag]) -> str:
"""Get the option pattern"""
option_bag = options_bag[-1]

View file

@ -539,6 +539,8 @@ def carry_out_calculation(option,
- tuple with option and boolean's force_permissive (True when don't raise
if PropertiesOptionError)
Values could have multiple values only when key is ''."""
if not option.impl_is_optiondescription() and option.impl_is_follower() and index is None:
raise Exception('follower must have index in carry_out_calculation!')
def fake_items(iterator):
return ((None, i) for i in iterator)
args = []

View file

@ -342,6 +342,7 @@ class _SubConfig:
opt.impl_getpath(),
None,
True,
follower_not_apply_requires=flatten_leadership,
)[-1],
types=types,
recursive=recursive,
@ -721,6 +722,7 @@ class _CommonConfig(_SubConfig):
validate_properties: bool,
leadership_length: int=None,
properties=undefined,
follower_not_apply_requires: bool=False,
) -> List[OptionBag]:
"""Get the suboption for path and the name of the option
:returns: tuple (config, name)"""
@ -734,12 +736,12 @@ class _CommonConfig(_SubConfig):
option_bag = bag
if option_bag.option != option_bag.config_bag.context.get_description():
path = path[len(option_bag.path) + 1:]
path = path.split('.')
last_idx = len(path) - 1
split_path = path.split('.')
last_idx = len(split_path) - 1
suboption = option_bag.option
options_bag = []
sub_option_bag = option_bag
for idx, step in enumerate(path):
for idx, step in enumerate(split_path):
if not suboption.impl_is_optiondescription():
raise TypeError(f'{suboption.impl_getpath()} is not an optiondescription')
@ -753,9 +755,9 @@ class _CommonConfig(_SubConfig):
)
if idx == last_idx:
option_index = index
else:
option_index = None
if idx == last_idx:
apply_requires = not follower_not_apply_requires or \
option.impl_is_optiondescription() or \
not option.impl_is_follower()
if option_index is not None:
if option.impl_is_optiondescription() or \
option.impl_is_symlinkoption() or \
@ -771,11 +773,14 @@ class _CommonConfig(_SubConfig):
f'"{option.impl_get_display_name()}"'))
option_properties = properties
else:
option_index = None
apply_requires = True
option_properties = undefined
sub_option_bag = OptionBag(option,
option_index,
option_bag.config_bag,
properties=option_properties,
apply_requires=apply_requires,
)
if validate_properties:
self.get_settings().validate_properties(sub_option_bag)

View file

@ -165,16 +165,20 @@ class Leadership(OptionDescription):
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
if idx == 0:
indexes = [None]
else:
indexes = range(len(value))
for index in indexes:
foption_bag_index = OptionBag(follower,
index,