From f33b4ebc2a7ba1f9b6c07cf6d73123e175df4bc2 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Fri, 11 Mar 2022 13:13:24 +0100 Subject: [PATCH] dyn option with not dyn option --- tests/test_dyn_optiondescription.py | 20 ++++++- tiramisu/autolib.py | 90 +++++++++++++++++------------ 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/tests/test_dyn_optiondescription.py b/tests/test_dyn_optiondescription.py index d14bc40..30427fc 100644 --- a/tests/test_dyn_optiondescription.py +++ b/tests/test_dyn_optiondescription.py @@ -13,7 +13,7 @@ from tiramisu import BoolOption, StrOption, ChoiceOption, IPOption, \ Params, ParamOption, ParamValue, ParamSuffix, ParamSelfOption, ParamDynOption, ParamIndex, \ Calculation, calc_value, \ delete_session -from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError +from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError, ValueOptionError from tiramisu.storage import list_sessions from .config import event_loop @@ -344,7 +344,7 @@ async def test_callback_dyndescription_outside_wrong_param(): od = OptionDescription('od', '', [dod, out]) od2 = OptionDescription('od', '', [od, lst]) async with await Config(od2) as cfg: - with pytest.raises(ConfigError): + with pytest.raises(ValueOptionError): await cfg.value.dict() assert not await list_sessions() @@ -1953,3 +1953,19 @@ async def test_dyn_symlink(): assert await config.option('name').option.issubmulti() == False assert await config.value.dict() == {'remotes': ['a', 'b', 'c'], 'remote_a.remote_ip_a': 'a', 'remote_b.remote_ip_b': 'b', 'remote_c.remote_ip_c': 'c', 'name': ['a', 'b', 'c']} assert not await list_sessions() + + +@pytest.mark.asyncio +async def test_dyn_callback_with_not_dyn(): + remotes = StrOption("remotes", "Remotes", ['a', 'b', 'c'], multi=True) + remote_ip = StrOption("remote_ip_", "Remote IP", Calculation(calc_value, Params(ParamSuffix()))) + dyn_remote = DynOptionDescription("remote_", "Account for ", suffixes=Calculation(calc_value, Params((ParamOption(remotes)))), children=[remote_ip]) + names = StrOption('names', '', Calculation(calc_value, Params(ParamOption(remote_ip))), multi=True) + accounts = OptionDescription(name="accounts", doc="accounts.remote_.remote_ip_", children=[remotes, dyn_remote, names]) + + async with await Config(accounts) as config: + assert await config.option('names').value.get() == ['a', 'b', 'c'] + assert await config.option('names').option.ismulti() == True + assert await config.option('names').option.issubmulti() == False + assert await config.value.dict() == {'remotes': ['a', 'b', 'c'], 'remote_a.remote_ip_a': 'a', 'remote_b.remote_ip_b': 'b', 'remote_c.remote_ip_c': 'c', 'names': ['a', 'b', 'c']} + assert not await list_sessions() diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index ceb613a..a6c27ec 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -351,57 +351,75 @@ async def manager_callback(callbk: Param, if isinstance(callbk, ParamOption): callbk_option = callbk.option + callbk_options = None if callbk_option.issubdyn(): if isinstance(callbk, ParamDynOption): subdyn = callbk.dynoptiondescription rootpath = subdyn.impl_getpath() + callbk.suffix suffix = callbk.suffix + callbk_option = callbk_option.to_dynoption(rootpath, + suffix, + subdyn) + elif not option.impl_is_dynsymlinkoption(): + callbk_options = [] + dynopt = callbk_option.getsubdyn() + rootpath = dynopt.impl_getpath() + subpaths = [rootpath] + callbk_option.impl_getpath()[len(rootpath) + 1:].split('.')[:-1] + for suffix in await dynopt.get_suffixes(config_bag): + path_suffix = dynopt.convert_suffix_to_path(suffix) + subpath = '.'.join([subp + path_suffix for subp in subpaths]) + doption = callbk_option.to_dynoption(subpath, + suffix, + dynopt) + callbk_options.append(doption) else: - if not option.impl_is_dynsymlinkoption(): - if callbk_option.issubdyn(): - msg = 'internal error: option "{}" is dynamic but is not a DynSymlinkOption' - else: - msg = 'option "{}" is not dynamic but has an argument with the dynamic option "{}" in a callback' - raise ConfigError(_(msg).format(option.impl_get_display_name(), - callbk_option.impl_get_display_name(), - )) #FIXME in same dynamic option? - suffix = option.impl_getsuffix() rootpath = option.rootpath - subdyn = callbk_option.getsubdyn() if len(callbk_option.impl_getpath().split('.')) == len(rootpath.split('.')): rootpath = rootpath.rsplit('.', 1)[0] - callbk_option = callbk_option.to_dynoption(rootpath, - suffix, - subdyn) + suffix = option.impl_getsuffix() + subdyn = callbk_option.getsubdyn() + callbk_option = callbk_option.to_dynoption(rootpath, + suffix, + subdyn) if leadership_must_have_index and callbk_option.impl_get_leadership() and index is None: raise Break() if config_bag is undefined: return undefined - if index is not None and callbk_option.impl_get_leadership() and \ - callbk_option.impl_get_leadership().in_same_group(option): - if not callbk_option.impl_is_follower(): - # leader - index_ = None - with_index = True - else: - # follower - index_ = index - with_index = False + if callbk_options is None: + callbk_options = [callbk_option] + values = None else: - index_ = None - with_index = False - path = callbk_option.impl_getpath() - option_bag = await get_option_bag(config_bag, - callbk_option, - index_, - False) - value = await get_value(callbk, - option_bag, - path, - ) - if with_index: - value = value[index] + values = [] + for callbk_option in callbk_options: + if index is not None and callbk_option.impl_get_leadership() and \ + callbk_option.impl_get_leadership().in_same_group(option): + if not callbk_option.impl_is_follower(): + # leader + index_ = None + with_index = True + else: + # follower + index_ = index + with_index = False + else: + index_ = None + with_index = False + path = callbk_option.impl_getpath() + option_bag = await get_option_bag(config_bag, + callbk_option, + index_, + False) + value = await get_value(callbk, + option_bag, + path, + ) + if with_index: + value = value[index] + if values is not None: + values.append(value) + if values is not None: + value = values if not callbk.todict: return value return {'name': callbk_option.impl_get_display_name(),