From 1d18cc74b77abc6986fa870043684f578042ccfc Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 27 Apr 2023 11:34:35 +0200 Subject: [PATCH] remove subconfig --- tests/auto/test_auto.py | 50 +- tests/test_cache.py | 4 +- tests/test_config.py | 1 - tests/test_config_api.py | 12 +- tests/test_dyn_optiondescription.py | 106 +-- tests/test_leadership.py | 43 +- tests/test_mandatory.py | 140 ++- tests/test_metaconfig.py | 32 +- tests/test_mixconfig.py | 28 +- tests/test_option_callback.py | 16 +- tests/test_option_owner.py | 2 +- tests/test_option_setting.py | 4 +- tests/test_requires.py | 164 +--- tests/test_slots.py | 23 - tests/test_symlink.py | 36 +- tiramisu/api.py | 914 ++++++++++--------- tiramisu/autolib.py | 115 ++- tiramisu/cacheobj.py | 3 +- tiramisu/config.py | 990 ++++++++++----------- tiramisu/option/leadership.py | 18 +- tiramisu/option/syndynoption.py | 8 +- tiramisu/option/syndynoptiondescription.py | 80 +- tiramisu/setting.py | 93 +- tiramisu/todict.py | 272 +++--- tiramisu/value.py | 153 +--- 25 files changed, 1599 insertions(+), 1708 deletions(-) diff --git a/tests/auto/test_auto.py b/tests/auto/test_auto.py index ae151bc..6d4da95 100644 --- a/tests/auto/test_auto.py +++ b/tests/auto/test_auto.py @@ -856,31 +856,31 @@ def autocheck_reset_value_permissive(cfg, mcfg, pathread, pathwrite, confread, c _autocheck_default_value(cfg, pathread, confread, **kwargs) if confread != confwrite: _autocheck_default_value(cfg, pathwrite, confwrite, **kwargs) - - -@autocheck -def autocheck_display(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kwargs): - """re set value - """ - if kwargs['callback']: - return - make_dict = kwargs['make_dict'] - make_dict_value = kwargs['make_dict_value'] - if confread is not None: - cfg_ = cfg.config(confread) - else: - cfg_ = cfg - if confwrite is not None: - cfg2_ = cfg.config(confwrite) - else: - cfg2_ = cfg - assert cfg_.value.dict() == make_dict - if confread != confwrite: - assert(cfg2_.value.dict()) == make_dict - _set_value(cfg, pathwrite, confwrite, **kwargs) - assert cfg_.value.dict() == make_dict_value - if confread != confwrite: - assert(cfg2_.value.dict()) == make_dict_value +#FIXME +#FIXME +#FIXME@autocheck +#FIXMEdef autocheck_display(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kwargs): +#FIXME """re set value +#FIXME """ +#FIXME if kwargs['callback']: +#FIXME return +#FIXME make_dict = kwargs['make_dict'] +#FIXME make_dict_value = kwargs['make_dict_value'] +#FIXME if confread is not None: +#FIXME cfg_ = cfg.config(confread) +#FIXME else: +#FIXME cfg_ = cfg +#FIXME if confwrite is not None: +#FIXME cfg2_ = cfg.config(confwrite) +#FIXME else: +#FIXME cfg2_ = cfg +#FIXME assert cfg_.value.dict() == make_dict +#FIXME if confread != confwrite: +#FIXME assert(cfg2_.value.dict()) == make_dict +#FIXME _set_value(cfg, pathwrite, confwrite, **kwargs) +#FIXME assert cfg_.value.dict() == make_dict_value +#FIXME if confread != confwrite: +#FIXME assert(cfg2_.value.dict()) == make_dict_value @autocheck diff --git a/tests/test_cache.py b/tests/test_cache.py index 9333d4e..c6b426b 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -390,7 +390,7 @@ def test_cache_leader_and_followers(): compare(settings.get_cached(), {None: {None: (global_props, None)}, 'val1': {None: (val1_props, None)}, 'val1.val1': {None: (val1_val1_props, None)}, - 'val1.val2': {idx_val2: (val1_val2_props, None)}}) + }) # len is 0 so don't get any value compare(values.get_cached(), {'val1.val1': {None: ([], None)}}) # @@ -441,7 +441,7 @@ def test_cache_leader_callback(): compare(settings.get_cached(), {None: {None: (global_props, None)}, 'val1': {None: (val1_props, None)}, 'val1.val1': {None: (val1_val1_props, None)}, - 'val1.val2': {None: (val1_val2_props, None)}}) + }) compare(values.get_cached(), {'val1.val1': {None: ([], None)}}) cfg.option('val1.val1').value.set([undefined]) compare(settings.get_cached(), {None: {None: (set(global_props), None)}, diff --git a/tests/test_config.py b/tests/test_config.py index 5c3aea8..dc1be5d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -10,7 +10,6 @@ from .config import config_type, get_config, value_list, global_owner import pytest from tiramisu import Config -from tiramisu.config import SubConfig from tiramisu.i18n import _ from tiramisu import Config, IntOption, FloatOption, ChoiceOption, \ BoolOption, StrOption, SymLinkOption, OptionDescription, undefined diff --git a/tests/test_config_api.py b/tests/test_config_api.py index 06b98d9..03c6702 100644 --- a/tests/test_config_api.py +++ b/tests/test_config_api.py @@ -82,8 +82,6 @@ def test_make_dict(config_type): cfg.option('s1.a').value.set(True) d = cfg.value.dict() assert d == {"s1.a": True, "int": 43} - d2 = cfg.value.dict(flatten=True) - assert d2 == {'a': True, 'int': 43} if config_type == 'tiramisu': assert cfg.forcepermissive.value.dict() == {"s1.a": True, "s1.b": False, "int": 43} # assert not list_sessions() @@ -100,7 +98,7 @@ def test_make_dict_sub(config_type): cfg.property.read_write() cfg.permissive.add('hidden') cfg = get_config(cfg, config_type) - assert cfg.option('s1').value.dict() == {'a': False} + assert cfg.option('s1').value.dict() == {'s1.a': False} def test_make_dict_not_value(config_type): @@ -169,13 +167,7 @@ def test_make_dict_fullpath(config_type): cfg.property.read_only() cfg = get_config(cfg, config_type) assert cfg.value.dict() == {"opt.s1.a": False, "opt.int": 42, "introot": 42} - if config_type == 'tiramisu': - # FIXME - assert cfg.option('opt').value.dict() == {"s1.a": False, "int": 42} - assert cfg.value.dict(fullpath=True) == {"opt.s1.a": False, "opt.int": 42, "introot": 42} - if config_type == 'tiramisu': - # FIXME - assert cfg.option('opt').value.dict(fullpath=True) == {"opt.s1.a": False, "opt.int": 42} + assert cfg.option('opt').value.dict() == {"opt.s1.a": False, "opt.int": 42} # assert not list_sessions() diff --git a/tests/test_dyn_optiondescription.py b/tests/test_dyn_optiondescription.py index 400753b..911390c 100644 --- a/tests/test_dyn_optiondescription.py +++ b/tests/test_dyn_optiondescription.py @@ -406,7 +406,6 @@ def test_mandatory_dyndescription(): cfg.property.read_only() with pytest.raises(PropertiesOptionError): cfg.option('od.dodval1.stval1').value.get() - assert list(cfg.value.mandatory()) == ['od.dodval1.stval1', 'od.dodval2.stval2'] # assert not list_sessions() @@ -582,7 +581,6 @@ def test_mandatory_dyndescription_context(): cfg.property.read_only() with pytest.raises(PropertiesOptionError): cfg.option('od.dodval1.stval1').value.get() - assert list(cfg.value.mandatory()) == ['od.dodval1.stval1', 'od.dodval2.stval2'] # assert not list_sessions() @@ -952,7 +950,6 @@ def test_makedict_dyndescription_context(): cfg = Config(od2) cfg.option('od.dodval1.stval1').value.set('yes') assert cfg.value.dict() == {'od.val1': ['val1', 'val2'], 'od.dodval1.stval1': 'yes', 'od.dodval2.stval2': None} - assert cfg.value.dict(flatten=True) == {'val1': ['val1', 'val2'], 'stval1': 'yes', 'stval2': None} # assert not list_sessions() @@ -1102,14 +1099,14 @@ def test_leadership_dyndescription(): cfg = Config(od1) owner = cfg.owner.get() # - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []} + assert cfg.value.dict() == {'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] assert cfg.option('od.stval1.st1val1.st1val1').owner.isdefault() assert cfg.option('od.stval2.st1val2.st1val2').owner.isdefault() # cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes']} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': None}], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == None assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] @@ -1167,20 +1164,20 @@ def test_leadership_dyndescription_force_store_value_leader(): assert cfg.option('od.stval1.st1val1.st2val1', 1).owner.isdefault() == True assert cfg.option('od.stval2.st1val2.st2val2', 0).owner.isdefault() == True assert cfg.option('od.stval2.st1val2.st2val2', 1).owner.isdefault() == True - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['val1', 'val2'], 'od.stval1.st1val1.st2val1': ['val1', 'val2'], 'od.stval2.st1val2.st1val2': ['val1', 'val2'], 'od.stval2.st1val2.st2val2': ['val1', 'val2'], 'od.val1': ['val1', 'val2']} + assert cfg.value.dict() == {'od.val1': ['val1', 'val2'], 'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'val1', 'od.stval1.st1val1.st2val1': 'val1'}, {'od.stval1.st1val1.st1val1': 'val2', 'od.stval1.st1val1.st2val1': 'val2'}], 'od.stval2.st1val2.st1val2': [{'od.stval2.st1val2.st1val2': 'val1', 'od.stval2.st1val2.st2val2': 'val1'}, {'od.stval2.st1val2.st1val2': 'val2', 'od.stval2.st1val2.st2val2': 'val2'}]} # cfg.option('od.val1').value.set(['val1', 'val2', 'val3']) assert cfg.option('od.stval3.st1val3.st1val3').owner.isdefault() == False assert cfg.option('od.stval3.st1val3.st2val3', 0).owner.isdefault() == True assert cfg.option('od.stval3.st1val3.st2val3', 1).owner.isdefault() == True - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['val1', 'val2'], 'od.stval1.st1val1.st2val1': ['val1', 'val2'], 'od.stval2.st1val2.st1val2': ['val1', 'val2'], 'od.stval2.st1val2.st2val2': ['val1', 'val2'], 'od.stval3.st1val3.st1val3': ['val1', 'val2'], 'od.stval3.st1val3.st2val3': ['val1', 'val2'], 'od.val1': ['val1', 'val2', 'val3']} + assert cfg.value.dict() == {'od.val1': ['val1', 'val2', 'val3'], 'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'val1', 'od.stval1.st1val1.st2val1': 'val1'}, {'od.stval1.st1val1.st1val1': 'val2', 'od.stval1.st1val1.st2val1': 'val2'}], 'od.stval2.st1val2.st1val2': [{'od.stval2.st1val2.st1val2': 'val1', 'od.stval2.st1val2.st2val2': 'val1'}, {'od.stval2.st1val2.st1val2': 'val2', 'od.stval2.st1val2.st2val2': 'val2'}], 'od.stval3.st1val3.st1val3': [{'od.stval3.st1val3.st1val3': 'val1', 'od.stval3.st1val3.st2val3': 'val1'}, {'od.stval3.st1val3.st1val3': 'val2', 'od.stval3.st1val3.st2val3': 'val2'}]} # cfg.option('od.stval3.st1val3.st1val3').value.set(['val1', 'val2', 'val3']) assert cfg.option('od.stval3.st1val3.st1val3').owner.isdefault() == False assert cfg.option('od.stval3.st1val3.st2val3', 0).owner.isdefault() == True assert cfg.option('od.stval3.st1val3.st2val3', 1).owner.isdefault() == True assert cfg.option('od.stval3.st1val3.st2val3', 2).owner.isdefault() == True - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['val1', 'val2'], 'od.stval1.st1val1.st2val1': ['val1', 'val2'], 'od.stval2.st1val2.st1val2': ['val1', 'val2'], 'od.stval2.st1val2.st2val2': ['val1', 'val2'], 'od.stval3.st1val3.st1val3': ['val1', 'val2', 'val3'], 'od.stval3.st1val3.st2val3': ['val1', 'val2', 'val3'], 'od.val1': ['val1', 'val2', 'val3']} + assert cfg.value.dict() == {'od.val1': ['val1', 'val2', 'val3'], 'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'val1', 'od.stval1.st1val1.st2val1': 'val1'}, {'od.stval1.st1val1.st1val1': 'val2', 'od.stval1.st1val1.st2val1': 'val2'}], 'od.stval2.st1val2.st1val2': [{'od.stval2.st1val2.st1val2': 'val1', 'od.stval2.st1val2.st2val2': 'val1'}, {'od.stval2.st1val2.st1val2': 'val2', 'od.stval2.st1val2.st2val2': 'val2'}], 'od.stval3.st1val3.st1val3': [{'od.stval3.st1val3.st1val3': 'val1', 'od.stval3.st1val3.st2val3': 'val1'}, {'od.stval3.st1val3.st1val3': 'val2', 'od.stval3.st1val3.st2val3': 'val2'}, {'od.stval3.st1val3.st1val3': 'val3', 'od.stval3.st1val3.st2val3': 'val3'}]} # assert not list_sessions() @@ -1200,20 +1197,20 @@ def test_leadership_dyndescription_force_store_value(): assert cfg.option('od.stval1.st1val1.st2val1', 1).owner.isdefault() == False assert cfg.option('od.stval2.st1val2.st2val2', 0).owner.isdefault() == False assert cfg.option('od.stval2.st1val2.st2val2', 1).owner.isdefault() == False - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['val1', 'val2'], 'od.stval1.st1val1.st2val1': ['val1', 'val2'], 'od.stval2.st1val2.st1val2': ['val1', 'val2'], 'od.stval2.st1val2.st2val2': ['val1', 'val2'], 'od.val1': ['val1', 'val2']} + assert cfg.value.dict() == {'od.val1': ['val1', 'val2'], 'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'val1', 'od.stval1.st1val1.st2val1': 'val1'}, {'od.stval1.st1val1.st1val1': 'val2', 'od.stval1.st1val1.st2val1': 'val2'}], 'od.stval2.st1val2.st1val2': [{'od.stval2.st1val2.st1val2': 'val1', 'od.stval2.st1val2.st2val2': 'val1'}, {'od.stval2.st1val2.st1val2': 'val2', 'od.stval2.st1val2.st2val2': 'val2'}]} # cfg.option('od.val1').value.set(['val1', 'val2', 'val3']) assert cfg.option('od.stval3.st1val3.st1val3').owner.isdefault() == True assert cfg.option('od.stval3.st1val3.st2val3', 0).owner.isdefault() == False assert cfg.option('od.stval3.st1val3.st2val3', 1).owner.isdefault() == False - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['val1', 'val2'], 'od.stval1.st1val1.st2val1': ['val1', 'val2'], 'od.stval2.st1val2.st1val2': ['val1', 'val2'], 'od.stval2.st1val2.st2val2': ['val1', 'val2'], 'od.stval3.st1val3.st1val3': ['val1', 'val2'], 'od.stval3.st1val3.st2val3': ['val1', 'val2'], 'od.val1': ['val1', 'val2', 'val3']} + assert cfg.value.dict() == {'od.val1': ['val1', 'val2', 'val3'], 'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'val1', 'od.stval1.st1val1.st2val1': 'val1'}, {'od.stval1.st1val1.st1val1': 'val2', 'od.stval1.st1val1.st2val1': 'val2'}], 'od.stval2.st1val2.st1val2': [{'od.stval2.st1val2.st1val2': 'val1', 'od.stval2.st1val2.st2val2': 'val1'}, {'od.stval2.st1val2.st1val2': 'val2', 'od.stval2.st1val2.st2val2': 'val2'}], 'od.stval3.st1val3.st1val3': [{'od.stval3.st1val3.st1val3': 'val1', 'od.stval3.st1val3.st2val3': 'val1'}, {'od.stval3.st1val3.st1val3': 'val2', 'od.stval3.st1val3.st2val3': 'val2'}]} # cfg.option('od.stval3.st1val3.st1val3').value.set(['val1', 'val2', 'val3']) assert cfg.option('od.stval3.st1val3.st1val3').owner.isdefault() == False assert cfg.option('od.stval3.st1val3.st2val3', 0).owner.isdefault() == False assert cfg.option('od.stval3.st1val3.st2val3', 1).owner.isdefault() == False assert cfg.option('od.stval3.st1val3.st2val3', 2).owner.isdefault() == False - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['val1', 'val2'], 'od.stval1.st1val1.st2val1': ['val1', 'val2'], 'od.stval2.st1val2.st1val2': ['val1', 'val2'], 'od.stval2.st1val2.st2val2': ['val1', 'val2'], 'od.stval3.st1val3.st1val3': ['val1', 'val2', 'val3'], 'od.stval3.st1val3.st2val3': ['val1', 'val2', 'val3'], 'od.val1': ['val1', 'val2', 'val3']} + assert cfg.value.dict() == {'od.val1': ['val1', 'val2', 'val3'], 'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'val1', 'od.stval1.st1val1.st2val1': 'val1'}, {'od.stval1.st1val1.st1val1': 'val2', 'od.stval1.st1val1.st2val1': 'val2'}], 'od.stval2.st1val2.st1val2': [{'od.stval2.st1val2.st1val2': 'val1', 'od.stval2.st1val2.st2val2': 'val1'}, {'od.stval2.st1val2.st1val2': 'val2', 'od.stval2.st1val2.st2val2': 'val2'}], 'od.stval3.st1val3.st1val3': [{'od.stval3.st1val3.st1val3': 'val1', 'od.stval3.st1val3.st2val3': 'val1'}, {'od.stval3.st1val3.st1val3': 'val2', 'od.stval3.st1val3.st2val3': 'val2'}, {'od.stval3.st1val3.st1val3': 'val3', 'od.stval3.st1val3.st2val3': 'val3'}]} # assert not list_sessions() @@ -1253,14 +1250,14 @@ def test_leadership_dyndescription_param(): od1 = OptionDescription('od', '', [od]) cfg = Config(od1) owner = cfg.owner.get() - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': [], 'od.odval1.val1': ['val1', 'val2']} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], 'od.stval2.st1val2.st1val2': [], 'od.odval1.val1': ['val1', 'val2']} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owners.default assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default # cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes'], 'od.odval1.val1': ['val1', 'val2']} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': None}], 'od.stval2.st1val2.st1val2': [], 'od.odval1.val1': ['val1', 'val2']} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == None assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] @@ -1333,14 +1330,14 @@ def _test_leadership(cfg): cfg.option('od.val1.val1').value.set(['val1', 'val2']) cfg.option('od.val1.val2', 0).value.set('val1') cfg.option('od.val1.val2', 1).value.set('val2') - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': [], 'od.val1.val1': ['val1', 'val2'], 'od.val1.val2': ['val1', 'val2']} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], 'od.stval2.st1val2.st1val2': [], 'od.val1.val1': [{'od.val1.val1': 'val1', 'od.val1.val2': 'val1'}, {'od.val1.val1': 'val2', 'od.val1.val2': 'val2'}]} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owners.default assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default # cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes'], 'od.val1.val1': ['val1', 'val2'], 'od.val1.val2': ['val1', 'val2']} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': None}], 'od.stval2.st1val2.st1val2': [], 'od.val1.val1': [{'od.val1.val1': 'val1', 'od.val1.val2': 'val1'}, {'od.val1.val1': 'val2', 'od.val1.val2': 'val2'}]} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == None assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] @@ -1504,14 +1501,14 @@ def test_leadership_callback_dyndescription(): od2 = OptionDescription('od', '', [od1]) cfg = Config(od2) owner = cfg.owner.get() - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() ==[] assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] assert cfg.option('od.stval1.st1val1.st1val1').owner.isdefault() assert cfg.option('od.stval2.st1val2.st1val2').owner.isdefault() # cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': ['yes'], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes']} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': 'yes'}], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == 'yes' assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] @@ -1599,36 +1596,21 @@ def test_leadership_callback_samegroup_dyndescription(): od2 = OptionDescription('od', '', [od1]) cfg = Config(od2) owner = cfg.owner.get() - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], - 'od.stval1.st1val1.st2val1': [], - 'od.stval1.st1val1.st3val1': [], - 'od.stval2.st1val2.st1val2': [], - 'od.stval2.st1val2.st2val2': [], - 'od.stval2.st1val2.st3val2': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] assert cfg.option('od.stval1.st1val1.st1val1').owner.isdefault() assert cfg.option('od.stval2.st1val2.st1val2').owner.isdefault() # cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['yes'], - 'od.stval1.st1val1.st2val1': [None], - 'od.stval1.st1val1.st3val1': [None], - 'od.stval2.st1val2.st1val2': [], - 'od.stval2.st1val2.st2val2': [], - 'od.stval2.st1val2.st3val2': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': None, 'od.stval1.st1val1.st3val1': None}], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.isdefault() assert cfg.option('od.stval1.st1val1.st3val1', 0).owner.isdefault() assert cfg.option('od.stval2.st1val2.st1val2').owner.isdefault() # cfg.option('od.stval1.st1val1.st2val1', 0).value.set('yes') - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['yes'], - 'od.stval1.st1val1.st2val1': ['yes'], - 'od.stval1.st1val1.st3val1': ['yes'], - 'od.stval2.st1val2.st1val2': [], - 'od.stval2.st1val2.st2val2': [], - 'od.stval2.st1val2.st3val2': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': 'yes', 'od.stval1.st1val1.st3val1': 'yes'}], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owner assert cfg.option('od.stval1.st1val1.st3val1', 0).owner.isdefault() @@ -1712,14 +1694,14 @@ def test_leadership_dyndescription_convert(): cfg = Config(od1) owner = cfg.owner.get() # - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] assert cfg.option('od.stval1.st1val1.st1val1').owner.isdefault() assert cfg.option('od.stval2.st1val2.st1val2').owner.isdefault() # cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) - assert cfg.value.dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes']} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': None}], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == None assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] @@ -1771,36 +1753,21 @@ def test_leadership_callback_samegroup_dyndescription_convert(): od2 = OptionDescription('od', '', [od1]) cfg = Config(od2) owner = cfg.owner.get() - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], - 'od.stval1.st1val1.st2val1': [], - 'od.stval1.st1val1.st3val1': [], - 'od.stval2.st1val2.st1val2': [], - 'od.stval2.st1val2.st2val2': [], - 'od.stval2.st1val2.st3val2': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] assert cfg.option('od.stval1.st1val1.st1val1').owner.isdefault() assert cfg.option('od.stval2.st1val2.st1val2').owner.isdefault() # cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['yes'], - 'od.stval1.st1val1.st2val1': [None], - 'od.stval1.st1val1.st3val1': [None], - 'od.stval2.st1val2.st1val2': [], - 'od.stval2.st1val2.st2val2': [], - 'od.stval2.st1val2.st3val2': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': None, 'od.stval1.st1val1.st3val1': None}], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.isdefault() assert cfg.option('od.stval1.st1val1.st3val1', 0).owner.isdefault() assert cfg.option('od.stval2.st1val2.st1val2').owner.isdefault() # cfg.option('od.stval1.st1val1.st2val1', 0).value.set('yes') - assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': ['yes'], - 'od.stval1.st1val1.st2val1': ['yes'], - 'od.stval1.st1val1.st3val1': ['yes'], - 'od.stval2.st1val2.st1val2': [], - 'od.stval2.st1val2.st2val2': [], - 'od.stval2.st1val2.st3val2': []} + assert cfg.value.dict() == {'od.stval1.st1val1.st1val1': [{'od.stval1.st1val1.st1val1': 'yes', 'od.stval1.st1val1.st2val1': 'yes', 'od.stval1.st1val1.st3val1': 'yes'}], 'od.stval2.st1val2.st1val2': []} assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owner assert cfg.option('od.stval1.st1val1.st3val1', 0).owner.isdefault() @@ -1824,8 +1791,8 @@ def test_dyn_with_leader_hidden_in_config(): cfg.option('leaderval1.ip_admin_eth0val1.ip_admin_eth0val1').value.get() with pytest.raises(PropertiesOptionError): cfg.option('leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1', 0).value.get() - cfg.value.dict(leader_to_list=True) == {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': [{'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.1'}], - 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': [{'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': '192.168.1.1'}]} + cfg.value.dict() == {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': [{'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.1'}], + 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': [{'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': '192.168.1.1'}]} # assert not list_sessions() @@ -1858,12 +1825,7 @@ def test_dyn_leadership_requires(): assert cfg.option('leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1', 1).value.get() is None cfg.option('leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1', 1).value.set('255.255.255.255') assert cfg.option('leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1', 1).value.get() == '255.255.255.255' - assert cfg.value.dict() == {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': ['192.168.1.2', '192.168.1.2'], - 'leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1': [None, '255.255.255.255'], - 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': [], - 'leaderval2.ip_admin_eth0val2.netmask_admin_eth0val2': []} - - ret = cfg.value.dict(leader_to_list=True) + ret = cfg.value.dict() assert ret == {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': [{'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.2', 'leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1': None}, {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.2', 'leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1': '255.255.255.255'}], 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': []} @@ -1873,24 +1835,8 @@ def test_dyn_leadership_requires(): assert cfg.option('leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1', 0).value.get() is None with pytest.raises(PropertiesOptionError): cfg.option('leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1', 1).value.get() - ret = cfg.value.dict() - assert set(ret.keys()) == set(['leaderval1.ip_admin_eth0val1.ip_admin_eth0val1', 'leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1', 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2', 'leaderval2.ip_admin_eth0val2.netmask_admin_eth0val2']) - assert ret['leaderval1.ip_admin_eth0val1.ip_admin_eth0val1'] == ['192.168.1.2', '192.168.1.1'] - assert len(ret['leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1']) == 2 - assert ret['leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1'][0] is None - assert isinstance(ret['leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1'][1], PropertiesOptionError) - del ret['leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1'][1] - del ret['leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1'][0] - del ret['leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1'] - assert cfg.value.dict(leader_to_list=True) == {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': [{'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.2', - 'leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1': None}, - {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.1'}], - 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': []} + assert cfg.value.dict() == {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': [{'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.2', 'leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1': None}, {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.1'}], 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': []} # - assert cfg.value.dict(leader_to_list=True) == {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': [{'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.2', - 'leaderval1.ip_admin_eth0val1.netmask_admin_eth0val1': None}, - {'leaderval1.ip_admin_eth0val1.ip_admin_eth0val1': '192.168.1.1'}], - 'leaderval2.ip_admin_eth0val2.ip_admin_eth0val2': []} # assert not list_sessions() diff --git a/tests/test_leadership.py b/tests/test_leadership.py index 97424e3..c7e03c2 100644 --- a/tests/test_leadership.py +++ b/tests/test_leadership.py @@ -62,17 +62,7 @@ def test_base_config(config_type): if config_type != 'tiramisu-api': ret = cfg.option.find('nom_machine', first=True) assert ret.value.get() == "eoleng" - result = {'general.numero_etab': None, 'general.nombre_interfaces': 1, - 'general.serveur_ntp': [], 'interface1.ip_admin_eth0.ip_admin_eth0': None, - 'general.mode_conteneur_actif': False, 'general.time_zone': 'Paris', - 'interface1.ip_admin_eth0.netmask_admin_eth0': None, 'general.nom_machine': - 'eoleng', 'general.activer_proxy_client': False} - assert cfg.option('creole').value.dict() == result - result = {'serveur_ntp': [], 'mode_conteneur_actif': False, - 'ip_admin_eth0': None, 'time_zone': 'Paris', 'numero_etab': None, - 'netmask_admin_eth0': None, 'nom_machine': 'eoleng', 'activer_proxy_client': - False, 'nombre_interfaces': 1} - assert cfg.option('creole').value.dict(flatten=True) == result + assert cfg.option('creole').value.dict() == {'creole.general.numero_etab': None, 'creole.general.nom_machine': 'eoleng', 'creole.general.nombre_interfaces': 1, 'creole.general.activer_proxy_client': False, 'creole.general.mode_conteneur_actif': False, 'creole.general.serveur_ntp': [], 'creole.general.time_zone': 'Paris', 'creole.interface1.ip_admin_eth0.ip_admin_eth0': None, 'creole.interface1.ip_admin_eth0.netmask_admin_eth0': None} if config_type == 'tiramisu-api': cfg.send() # assert not list_sessions() @@ -94,11 +84,13 @@ def test_iter_on_groups(): cfg = Config(od1) cfg.property.read_write() result = cfg.option('creole').list('optiondescription', - group_type=groups.family) + group_type=groups.family, + ) group_names = [res.option.name() for res in result] assert group_names == ['general', 'interface1'] for i in cfg.option('creole').list('optiondescription', - group_type=groups.family): + group_type=groups.family, + ): #test StopIteration break result = cfg.option('creole').list('option', @@ -125,7 +117,7 @@ def test_list_recursive(): 'netmask_admin_eth0'] result = list(cfg.option.list(recursive=True, type='optiondescription')) group_names = [res.option.name() for res in result] - assert group_names == ['general', 'ip_admin_eth0', 'interface1', 'creole'] + assert group_names == ['creole', 'general', 'interface1', 'ip_admin_eth0'] # assert not list_sessions() @@ -185,12 +177,8 @@ def test_iter_not_group(): od1 = OptionDescription("name", "descr", []) cfg = Config(od1) cfg.property.read_write() - try: - list(cfg.option.list(type='optiondescription', group_type='family')) - except AssertionError: - pass - else: - raise Exception('must raise') + with pytest.raises(AssertionError): + print(list(cfg.option.list(type='optiondescription', group_type='family'))) # assert not list_sessions() @@ -257,8 +245,7 @@ def test_groups_with_leader_make_dict(config_type): od1 = OptionDescription('root', '', [interface1]) cfg = Config(od1) cfg = get_config(cfg, config_type) - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'ip_admin_eth0.netmask_admin_eth0': []} - assert cfg.value.dict(leader_to_list=True) == {'ip_admin_eth0.ip_admin_eth0': []} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': []} if config_type != 'tiramisu-api': # FIXME useful? already in leadership assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.len() == 0 @@ -268,8 +255,7 @@ def test_groups_with_leader_make_dict(config_type): # FIXME assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.len() == 2 assert cfg.option('ip_admin_eth0.netmask_admin_eth0').value.len() == 2 - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['ip1', 'ip2'], 'ip_admin_eth0.netmask_admin_eth0': [None, None]} - assert cfg.value.dict(leader_to_list=True) == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'ip1', 'ip_admin_eth0.netmask_admin_eth0': None}, {'ip_admin_eth0.ip_admin_eth0': 'ip2', 'ip_admin_eth0.netmask_admin_eth0': None}]} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'ip1', 'ip_admin_eth0.netmask_admin_eth0': None}, {'ip_admin_eth0.ip_admin_eth0': 'ip2', 'ip_admin_eth0.netmask_admin_eth0': None}]} if config_type == 'tiramisu-api': cfg.send() # assert not list_sessions() @@ -292,8 +278,7 @@ def test_groups_with_leader_make_dict2(config_type): od1 = OptionDescription('root', '', [interface1]) cfg = Config(od1) cfg = get_config(cfg, config_type) - assert cfg.value.dict() == {'other.ip_admin_eth0': [], 'other.netmask_admin_eth0': []} - assert cfg.value.dict(leader_to_list=True) == {'other.ip_admin_eth0': []} + assert cfg.value.dict() == {'other.ip_admin_eth0': []} if config_type != 'tiramisu-api': # FIXME useful? already in leadership assert cfg.option('other.ip_admin_eth0').value.len() == 0 @@ -303,8 +288,7 @@ def test_groups_with_leader_make_dict2(config_type): # FIXME assert cfg.option('other.ip_admin_eth0').value.len() == 2 assert cfg.option('other.netmask_admin_eth0').value.len() == 2 - assert cfg.value.dict() == {'other.ip_admin_eth0': ['ip1', 'ip2'], 'other.netmask_admin_eth0': [None, None]} - assert cfg.value.dict(leader_to_list=True) == {'other.ip_admin_eth0': [{'other.ip_admin_eth0': 'ip1', 'other.netmask_admin_eth0': None}, {'other.ip_admin_eth0': 'ip2', 'other.netmask_admin_eth0': None}]} + assert cfg.value.dict() == {'other.ip_admin_eth0': [{'other.ip_admin_eth0': 'ip1', 'other.netmask_admin_eth0': None}, {'other.ip_admin_eth0': 'ip2', 'other.netmask_admin_eth0': None}]} if config_type == 'tiramisu-api': cfg.send() # assert not list_sessions() @@ -344,13 +328,11 @@ def test_groups_with_leader_default_value_2(config_type): assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == 'netmask1' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.default() == 'netmask1' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.default() == 'netmask1' - assert cfg.option('ip_admin_eth0.netmask_admin_eth0').value.default() == ['netmask1', 'netmask1'] cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('netmask2') assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == 'netmask1' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == 'netmask2' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.default() == 'netmask1' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.default() == 'netmask1' - assert cfg.option('ip_admin_eth0.netmask_admin_eth0').value.default() == ['netmask1', 'netmask1'] if config_type == 'tiramisu-api': cfg.send() # assert not list_sessions() @@ -372,7 +354,6 @@ def test_groups_with_leader_hidden_in_config(): with pytest.raises(PropertiesOptionError): cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() assert cfg.value.dict() == {} - assert cfg.value.dict(leader_to_list=True) == {} # assert not list_sessions() diff --git a/tests/test_mandatory.py b/tests/test_mandatory.py index 47e325b..00e44de 100644 --- a/tests/test_mandatory.py +++ b/tests/test_mandatory.py @@ -5,9 +5,9 @@ do_autopath() import pytest from tiramisu import Config -from tiramisu import IntOption, StrOption, OptionDescription, \ +from tiramisu import IntOption, StrOption, OptionDescription, DynOptionDescription, \ SymLinkOption, Leadership, undefined, Calculation, Params, \ - ParamOption, ParamValue, calc_value + ParamOption, ParamValue, ParamIndex, calc_value from tiramisu.error import PropertiesOptionError, ConfigError from tiramisu.setting import groups @@ -36,14 +36,14 @@ def return_value(value): def make_description2(): - stroption = StrOption('str', 'Test string option', default="abc", + stroption = StrOption('str', 'str', default="abc", properties=('mandatory', )) - stroption1 = StrOption('str1', 'Test string option', + stroption1 = StrOption('str1', 'str1', properties=('mandatory', )) stroption2 = SymLinkOption('unicode2', stroption1) - stroption3 = StrOption('str3', 'Test string option', multi=True, + stroption3 = StrOption('str3', 'str3', multi=True, properties=('mandatory', )) - unicode1 = StrOption('unicode1', 'Test string option', Calculation(return_value, Params(ParamOption(stroption))), properties=('mandatory',)) + unicode1 = StrOption('unicode1', 'unicode1', Calculation(return_value, Params(ParamOption(stroption))), properties=('mandatory',)) descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3, unicode1]) return descr @@ -319,6 +319,18 @@ def test_mandatory_unicode(): # assert not list_sessions() +def compare(ret, expected): + assert(len(ret) == len(expected)) + for index, opt in enumerate(ret): + exp = expected[index] + if isinstance(exp, list): + assert opt.option.path() == exp[0] + assert opt.option.index() == exp[1] + else: + assert opt.option.path() == exp + assert opt.option.index() == None + + def test_mandatory_warnings_ro(): od1 = make_description() cfg = Config(od1) @@ -330,11 +342,11 @@ def test_mandatory_warnings_ro(): except PropertiesOptionError as err: prop = err.proptype assert 'mandatory' in prop - assert list(cfg.value.mandatory()) == ['str', 'str1', 'unicode2', 'str3'] + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2', 'str3']) cfg.property.read_write() cfg.option('str').value.set('a') cfg.property.read_only() - assert list(cfg.value.mandatory()) == ['str1', 'unicode2', 'str3'] + compare(cfg.value.mandatory(), ['str1', 'unicode2', 'str3']) # assert not list_sessions() @@ -344,9 +356,9 @@ def test_mandatory_warnings_rw(): cfg.option('str').value.set('') cfg.property.read_write() cfg.option('str').value.get() - assert list(cfg.value.mandatory()) == ['str', 'str1', 'unicode2', 'str3'] + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2', 'str3']) cfg.option('str').value.set('a') - assert list(cfg.value.mandatory()) == ['str1', 'unicode2', 'str3'] + compare(cfg.value.mandatory(), ['str1', 'unicode2', 'str3']) # assert not list_sessions() @@ -356,9 +368,9 @@ def test_mandatory_warnings_disabled(): cfg.option('str').value.set('') cfg.property.read_write() cfg.option('str').value.get() - assert set(cfg.value.mandatory()) == {'str', 'str1', 'unicode2', 'str3'} + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2', 'str3']) cfg.option('str').property.add('disabled') - assert set(cfg.value.mandatory()) == {'str1', 'unicode2', 'str3'} + compare(cfg.value.mandatory(), ['str1', 'unicode2', 'str3']) # assert not list_sessions() @@ -369,9 +381,9 @@ def test_mandatory_warnings_hidden(): cfg.property.read_write() cfg.permissive.add('hidden') cfg.option('str').value.get() - assert set(cfg.value.mandatory()) == {'str', 'str1', 'unicode2', 'str3'} + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2', 'str3']) cfg.option('str').property.add('hidden') - assert set(cfg.value.mandatory()) == {'str', 'str1', 'unicode2', 'str3'} + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2', 'str3']) # assert not list_sessions() @@ -381,10 +393,10 @@ def test_mandatory_warnings_frozen(): cfg.option('str').value.set('') cfg.property.read_write() cfg.option('str').value.get() - assert set(cfg.value.mandatory()) == {'str', 'str1', 'unicode2', 'str3'} + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2', 'str3']) cfg.option('str').property.add('frozen') cfg.property.read_only() - assert set(cfg.value.mandatory()) == {'str', 'str1', 'unicode2', 'str3'} + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2', 'str3']) # assert not list_sessions() @@ -429,7 +441,7 @@ def test_mandatory_warnings_leader(): interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) od1 = OptionDescription('o', '', [interface1]) cfg = Config(od1) - assert list(cfg.value.mandatory()) == ['ip_admin_eth0.ip_admin_eth0'] + compare(cfg.value.mandatory(), ['ip_admin_eth0.ip_admin_eth0']) # assert not list_sessions() @@ -492,17 +504,17 @@ def test_mandatory_warnings_leader_empty(): cfg.option('ip_admin_eth0.ip_admin_eth0').value.set([undefined]) assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == [None] assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None - assert list(cfg.value.mandatory()) == ['ip_admin_eth0.ip_admin_eth0'] + compare(cfg.value.mandatory(), ['ip_admin_eth0.ip_admin_eth0']) cfg.option('ip_admin_eth0.ip_admin_eth0').value.reset() # cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['']) assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == [''] assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None - assert list(cfg.value.mandatory()) == ['ip_admin_eth0.ip_admin_eth0'] + compare(cfg.value.mandatory(), ['ip_admin_eth0.ip_admin_eth0']) # cfg.property.read_write() cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['ip']) - assert list(cfg.value.mandatory()) == [] + compare(cfg.value.mandatory(), []) # assert not list_sessions() @@ -515,8 +527,7 @@ def test_mandatory_follower(): cfg = Config(od1) cfg.property.read_only() assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == [] - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [], - 'ip_admin_eth0.netmask_admin_eth0': []} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': []} # cfg.property.read_write() cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['ip']) @@ -537,8 +548,7 @@ def test_mandatory_follower(): cfg.property.read_only() assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['ip'] assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == 'ip' - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['ip'], - 'ip_admin_eth0.netmask_admin_eth0': ['ip']} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'ip', 'ip_admin_eth0.netmask_admin_eth0': 'ip'}]} # assert not list_sessions() @@ -553,9 +563,9 @@ def test_mandatory_warnings_follower(): assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == [] # cfg.property.read_write() - assert list(cfg.value.mandatory()) == [] + compare(cfg.value.mandatory(), []) cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['ip']) - assert list(cfg.value.mandatory()) == ['ip_admin_eth0.netmask_admin_eth0'] + compare(cfg.value.mandatory(), [['ip_admin_eth0.netmask_admin_eth0', 0]]) # assert not list_sessions() @@ -565,10 +575,10 @@ def test_mandatory_warnings_symlink(): cfg.option('str').value.set('') cfg.property.read_write() cfg.option('str').value.get() - assert list(cfg.value.mandatory()) == ['str', 'str1', 'str3'] + compare(cfg.value.mandatory(), ['str', 'str1', 'str3']) cfg.option('str').property.add('frozen') cfg.property.read_only() - assert list(cfg.value.mandatory()) == ['str', 'str1', 'str3'] + compare(cfg.value.mandatory(), ['str', 'str1', 'str3']) # assert not list_sessions() @@ -577,7 +587,7 @@ def test_mandatory_warnings_validate_empty(): cfg = Config(od1) cfg.option('str').value.set('') cfg.property.read_only() - assert list(cfg.value.mandatory()) == ['str', 'str1', 'str3'] + compare(cfg.value.mandatory(), ['str', 'str1', 'str3', 'unicode1']) # assert not list_sessions() @@ -599,12 +609,12 @@ def test_mandatory_warnings_requires(): cfg.option('str').value.set('') cfg.property.read_write() cfg.option('str').value.get() - assert list(cfg.value.mandatory()) == ['str', 'str1', 'unicode2'] + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2']) cfg.property.read_only() - assert list(cfg.value.mandatory()) == ['str', 'str1', 'unicode2'] + compare(cfg.value.mandatory(), ['str', 'str1', 'unicode2']) cfg.property.read_write() cfg.option('str').value.set('yes') - assert list(cfg.value.mandatory()) == ['str1', 'unicode2', 'str3'] + compare(cfg.value.mandatory(), ['str1', 'unicode2', 'str3']) # assert not list_sessions() @@ -624,9 +634,9 @@ def test_mandatory_warnings_requires_leadership(): cfg = Config(od1) cfg.option('str').value.set('') cfg.option('leader.str1').value.set(['str']) - assert list(cfg.value.mandatory()) == ['str'] + compare(cfg.value.mandatory(), ['str']) cfg.option('str').value.set('yes') - assert list(cfg.value.mandatory()) == ['leader.str2'] + compare(cfg.value.mandatory(), [['leader.str2', 0]]) # assert not list_sessions() @@ -644,9 +654,21 @@ def test_mandatory_warnings_requires_leadership_follower(): od1 = OptionDescription('tiram', '', [leadership]) cfg = Config(od1) cfg.option('leader.str').value.set(['str']) - assert list(cfg.value.mandatory()) == [] + compare(cfg.value.mandatory(), []) cfg.option('leader.str1', 0).value.set('yes') - assert list(cfg.value.mandatory()) == ['leader.str2'] + compare(cfg.value.mandatory(), [['leader.str2', 0]]) + cfg.option('leader.str2', 0).value.set('yes') + compare(cfg.value.mandatory(), []) + # + cfg.option('leader.str').value.set(['str', 'str1']) + compare(cfg.value.mandatory(), []) + cfg.option('leader.str1', 1).value.set('yes') + compare(cfg.value.mandatory(), [['leader.str2', 1]]) + cfg.option('leader.str2', 1).value.set('yes') + compare(cfg.value.mandatory(), []) + cfg.option('leader.str2', 0).value.reset() + cfg.option('leader.str2', 1).value.reset() + compare(cfg.value.mandatory(), [['leader.str2', 0], ['leader.str2', 1]]) # assert not list_sessions() @@ -655,7 +677,49 @@ def test_mandatory_od_disabled(): od1 = OptionDescription('od', '', [descr]) cfg = Config(od1) cfg.property.read_only() - assert list(cfg.value.mandatory()) == ['tiram.str1', 'tiram.unicode2', 'tiram.str3'] + compare(cfg.value.mandatory(), ['tiram.str1', 'tiram.unicode2', 'tiram.str3']) cfg.option('tiram').property.add('disabled') - assert list(cfg.value.mandatory()) == [] + compare(cfg.value.mandatory(), []) +# assert not list_sessions() + + +def return_list(val=None, suffix=None): + if val: + return val + else: + return ['val1', 'val2'] + + +def test_mandatory_dyndescription(): + st = StrOption('st', '', properties=('mandatory',)) + dod = DynOptionDescription('dod', '', [st], suffixes=Calculation(return_list)) + od = OptionDescription('od', '', [dod]) + od2 = OptionDescription('od', '', [od]) + cfg = Config(od2) + cfg.property.read_only() + compare(cfg.value.mandatory(), ['od.dodval1.stval1', 'od.dodval2.stval2']) + + +def test_mandatory_dyndescription_context(): + val1 = StrOption('val1', '', ['val1', 'val2'], multi=True) + st = StrOption('st', '', properties=('mandatory',)) + dod = DynOptionDescription('dod', '', [st], suffixes=Calculation(return_list, Params(ParamOption(val1)))) + od = OptionDescription('od', '', [dod, val1]) + od2 = OptionDescription('od', '', [od]) + cfg = Config(od2) + cfg.property.read_only() + compare(cfg.value.mandatory(), ['od.dodval1.stval1', 'od.dodval2.stval2']) + + +def test_mandatory_callback_leader_and_followers_leader(): + val1 = StrOption('val1', "", multi=True, properties=('mandatory', 'empty')) + val2 = StrOption('val2', "", multi=True, default_multi='val2', properties=('expert',)) + val3 = StrOption('val3', "", Calculation(calc_value, Params(ParamOption(val2), {'index': ParamIndex()})), multi=True) + val4 = StrOption('val4', "", Calculation(calc_value, Params(ParamOption(val3), {'index': ParamIndex()})), multi=True) + interface1 = Leadership('val1', '', [val1, val2, val3, val4]) + od1 = OptionDescription('rootconfig', '', [interface1]) + cfg = Config(od1) + cfg.property.read_write() + # FIXME cfg = get_config(cfg, config_type) + compare(cfg.value.mandatory(), ['val1.val1']) # assert not list_sessions() diff --git a/tests/test_metaconfig.py b/tests/test_metaconfig.py index cfe9766..bcc3fe3 100644 --- a/tests/test_metaconfig.py +++ b/tests/test_metaconfig.py @@ -88,7 +88,7 @@ def test_none(): assert meta.option('od1.i3').value.get() is conf1.option('od1.i3').value.get() is conf2.option('od1.i3').value.get() is None assert meta.option('od1.i3').owner.get() is conf1.option('od1.i3').owner.get() is conf2.option('od1.i3').owner.get() is owners.default # - meta.option('od1.i3').value.set(3) + assert meta.option('od1.i3').value.set(3) == [] assert meta.option('od1.i3').value.get() == conf1.option('od1.i3').value.get() == conf2.option('od1.i3').value.get() == 3 assert meta.option('od1.i3').owner.get() is conf1.option('od1.i3').owner.get() is conf2.option('od1.i3').owner.get() is owners.meta1 # @@ -870,7 +870,7 @@ def test_meta_properties_requires_mandatory(): meta.option('ip_gw').value.set('1.1.1.2') conf1.option('eth0_method').value.set('dhcp') conf1.property.read_only() - assert conf1.value.dict(fullpath=True) == {'probes': True, 'eth0_method': 'dhcp', 'ip_address': '1.1.1.1', 'ip_eth0': '1.1.1.1', 'ip_gw': '1.1.1.2'} + assert conf1.value.dict() == {'ip_gw': '1.1.1.2', 'probes': True, 'eth0_method': 'dhcp', 'ip_address': '1.1.1.1', 'ip_eth0': '1.1.1.1'} def test_meta_callback(): @@ -909,51 +909,51 @@ def test_meta_callback_follower(): conf1 = Config(maconfig, name='conf1') meta = MetaConfig([conf1]) meta.property.read_write() - assert conf1.value.dict() == {'val1.val2': ['val'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val', 'val1.val3': 'val'}]} # conf1.option('val').value.set('val1') - assert conf1.value.dict() == {'val1.val2': ['val1'], 'val1.val1': ['val1'], 'val1.val3': ['val1'], 'val': 'val1'} + assert conf1.value.dict() == {'val': 'val1', 'val1.val1': [{'val1.val1': 'val1', 'val1.val2': 'val1', 'val1.val3': 'val1'}]} # conf1.option('val').value.reset() meta.option('val').value.set('val1') - assert conf1.value.dict() == {'val1.val2': ['val1'], 'val1.val1': ['val1'], 'val1.val3': ['val1'], 'val': 'val1'} + assert conf1.value.dict() == {'val': 'val1', 'val1.val1': [{'val1.val1': 'val1', 'val1.val2': 'val1', 'val1.val3': 'val1'}]} # meta.option('val').value.reset() conf1.option('val1.val2', 0).value.set('val2') - assert conf1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val'}]} # conf1.option('val1.val2', 0).value.reset() - assert conf1.value.dict() == {'val1.val2': ['val'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val', 'val1.val3': 'val'}]} # meta.option('val1.val2', 0).value.set('val2') - assert conf1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val'}]} # meta.option('val1.val1').value.set(['val']) - assert conf1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val'}]} # conf1.option('val1.val3', 0).value.set('val6') - assert conf1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val6'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val6'}]} # meta.option('val1.val2', 0).value.reset() conf1.option('val1.val3', 0).value.reset() conf1.option('val1.val1').value.set(['val3']) - assert conf1.value.dict() == {'val1.val2': ['val3'], 'val1.val1': ['val3'], 'val1.val3': ['val3'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val3', 'val1.val3': 'val3'}]} # conf1.option('val1.val1').value.reset() - assert conf1.value.dict() == {'val1.val2': ['val'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val', 'val1.val3': 'val'}]} # meta.option('val1.val1').value.set(['val3']) - assert conf1.value.dict() == {'val1.val2': ['val3'], 'val1.val1': ['val3'], 'val1.val3': ['val3'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val3', 'val1.val3': 'val3'}]} # conf1.option('val1.val2', 0).value.set('val2') - assert conf1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val3'], 'val1.val3': ['val3'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val2', 'val1.val3': 'val3'}]} # meta.option('val1.val1').value.set(['val3', 'rah']) - assert conf1.value.dict() == {'val1.val2': ['val2', 'rah'], 'val1.val1': ['val3', 'rah'], 'val1.val3': ['val3', 'rah'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val2', 'val1.val3': 'val3'}, {'val1.val1': 'rah', 'val1.val2': 'rah', 'val1.val3': 'rah'}]} # meta.option('val1.val1').value.pop(1) meta.option('val1.val1').value.set(['val4']) - assert conf1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val4'], 'val1.val3': ['val4'], 'val': 'val'} + assert conf1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val4', 'val1.val2': 'val2', 'val1.val3': 'val4'}]} def test_meta_reset(): diff --git a/tests/test_mixconfig.py b/tests/test_mixconfig.py index c765a9c..2660bd8 100644 --- a/tests/test_mixconfig.py +++ b/tests/test_mixconfig.py @@ -709,51 +709,51 @@ def test_mix_callback_follower(): mix = MixConfig(maconfig, [cfg]) mix.property.read_write() newcfg1 = mix.config('cfg1') - assert newcfg1.value.dict() == {'val1.val2': ['val'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val', 'val1.val3': 'val'}]} # newcfg1.option('val').value.set('val1') - assert newcfg1.value.dict() == {'val1.val2': ['val1'], 'val1.val1': ['val1'], 'val1.val3': ['val1'], 'val': 'val1'} + assert newcfg1.value.dict() == {'val': 'val1', 'val1.val1': [{'val1.val1': 'val1', 'val1.val2': 'val1', 'val1.val3': 'val1'}]} # newcfg1.option('val').value.reset() mix.option('val').value.set('val1') - assert newcfg1.value.dict() == {'val1.val2': ['val1'], 'val1.val1': ['val1'], 'val1.val3': ['val1'], 'val': 'val1'} + assert newcfg1.value.dict() == {'val': 'val1', 'val1.val1': [{'val1.val1': 'val1', 'val1.val2': 'val1', 'val1.val3': 'val1'}]} # mix.option('val').value.reset() newcfg1.option('val1.val2', 0).value.set('val2') - assert newcfg1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val'}]} # newcfg1.option('val1.val2', 0).value.reset() - assert newcfg1.value.dict() == {'val1.val2': ['val'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val', 'val1.val3': 'val'}]} # mix.option('val1.val2', 0).value.set('val2') - assert newcfg1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val'}]} # mix.option('val1.val1').value.set(['val']) - assert newcfg1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val'}]} # newcfg1.option('val1.val3', 0).value.set('val6') - assert newcfg1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val'], 'val1.val3': ['val6'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val2', 'val1.val3': 'val6'}]} # mix.option('val1.val2', 0).value.reset() newcfg1.option('val1.val3', 0).value.reset() newcfg1.option('val1.val1').value.set(['val3']) - assert newcfg1.value.dict() == {'val1.val2': ['val3'], 'val1.val1': ['val3'], 'val1.val3': ['val3'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val3', 'val1.val3': 'val3'}]} # newcfg1.option('val1.val1').value.reset() - assert newcfg1.value.dict() == {'val1.val2': ['val'], 'val1.val1': ['val'], 'val1.val3': ['val'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val', 'val1.val2': 'val', 'val1.val3': 'val'}]} # mix.option('val1.val1').value.set(['val3']) - assert newcfg1.value.dict() == {'val1.val2': ['val3'], 'val1.val1': ['val3'], 'val1.val3': ['val3'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val3', 'val1.val3': 'val3'}]} # newcfg1.option('val1.val2', 0).value.set('val2') - assert newcfg1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val3'], 'val1.val3': ['val3'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val2', 'val1.val3': 'val3'}]} # mix.option('val1.val1').value.set(['val3', 'rah']) - assert newcfg1.value.dict() == {'val1.val2': ['val2', 'rah'], 'val1.val1': ['val3', 'rah'], 'val1.val3': ['val3', 'rah'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val3', 'val1.val2': 'val2', 'val1.val3': 'val3'}, {'val1.val1': 'rah', 'val1.val2': 'rah', 'val1.val3': 'rah'}]} # mix.option('val1.val1').value.pop(1) mix.option('val1.val1').value.set(['val4']) - assert newcfg1.value.dict() == {'val1.val2': ['val2'], 'val1.val1': ['val4'], 'val1.val3': ['val4'], 'val': 'val'} + assert newcfg1.value.dict() == {'val': 'val', 'val1.val1': [{'val1.val1': 'val4', 'val1.val2': 'val2', 'val1.val3': 'val4'}]} def test_meta_reset(): diff --git a/tests/test_option_callback.py b/tests/test_option_callback.py index 65c16d1..4842f66 100644 --- a/tests/test_option_callback.py +++ b/tests/test_option_callback.py @@ -776,20 +776,6 @@ def test_callback_leader_and_followers_leader_mandatory4(config_type): # assert not list_sessions() -def test_callback_leader_and_followers_leader3(): - val1 = StrOption('val1', "", multi=True, properties=('mandatory', 'empty')) - val2 = StrOption('val2', "", multi=True, default_multi='val2', properties=('expert',)) - val3 = StrOption('val3', "", Calculation(calc_value, Params(ParamOption(val2), {'index': ParamIndex()})), multi=True) - val4 = StrOption('val4', "", Calculation(calc_value, Params(ParamOption(val3), {'index': ParamIndex()})), multi=True) - interface1 = Leadership('val1', '', [val1, val2, val3, val4]) - od1 = OptionDescription('rootconfig', '', [interface1]) - cfg = Config(od1) - cfg.property.read_write() - # FIXME cfg = get_config(cfg, config_type) - assert list(cfg.value.mandatory()) == ['val1.val1'] -# assert not list_sessions() - - def test_callback_leader_and_followers_leader4(): val1 = StrOption('val1', "", ['val1'], multi=True, properties=('mandatory',)) val2 = StrOption('val2', "", multi=True, default_multi='val2', properties=('expert', 'mandatory')) @@ -996,7 +982,7 @@ def test_callback_leader_and_followers_leader_callback_disabled(): with pytest.raises(ConfigError): cfg.option('val1.val1').value.get() with pytest.raises(ConfigError): - cfg.option('val1.val2').value.get() + cfg.option('val1.val2', 0).value.get() cfg.property.remove('disabled') cfg.option('val1.val1').value.set([]) cfg.property.add('disabled') diff --git a/tests/test_option_owner.py b/tests/test_option_owner.py index b3d2709..e1f1c95 100644 --- a/tests/test_option_owner.py +++ b/tests/test_option_owner.py @@ -219,7 +219,7 @@ def test_setowner_symlinkoption(config_type): assert not cfg.option('tiramisu.symdummy').owner.isdefault() if config_type == 'tiramisu-api': cfg.send() - with pytest.raises(ConfigError): + with pytest.raises(APIError): cfg_ori.option('tiramisu.symdummy').owner.set('user') # assert not list_sessions() diff --git a/tests/test_option_setting.py b/tests/test_option_setting.py index ac91da5..027831b 100644 --- a/tests/test_option_setting.py +++ b/tests/test_option_setting.py @@ -709,7 +709,7 @@ def test_pprint(): kwargs={'condition': ParamOption(intoption, todict=True), 'expected': ParamValue(1)}), calc_value_property_help) - descr2 = OptionDescription("options", "", [val2], properties=(hidden_property,)) + descr2 = OptionDescription("options", "options", [val2], properties=(hidden_property,)) #descr2 = OptionDescription("options", "", [val2], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}]) hidden_property = Calculation(calc_value, @@ -721,7 +721,7 @@ def test_pprint(): val3 = StrOption('val3', "", properties=(hidden_property,)) #val3 = StrOption('val3', "", requires=[{'option': stroption, 'expected': '2', 'action': 'hidden', 'inverse': True}]) - od1 = OptionDescription("options", "", [s, s2, s3, intoption, stroption, descr2, val3]) + od1 = OptionDescription("options", "root option", [s, s2, s3, intoption, stroption, descr2, val3]) cfg = Config(od1) cfg.property.read_write() cfg.option('int').value.set(1) diff --git a/tests/test_requires.py b/tests/test_requires.py index ea5a629..68d31df 100644 --- a/tests/test_requires.py +++ b/tests/test_requires.py @@ -1106,41 +1106,21 @@ def test_leadership_requires(config_type): assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() is None cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('255.255.255.255') assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == '255.255.255.255' - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['192.168.1.2', '192.168.1.2'], - 'ip_admin_eth0.netmask_admin_eth0': [None, '255.255.255.255']} - assert cfg.value.dict(leader_to_list=True) == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', 'ip_admin_eth0.netmask_admin_eth0': None}, - {'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', 'ip_admin_eth0.netmask_admin_eth0': '255.255.255.255'}]} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', 'ip_admin_eth0.netmask_admin_eth0': None}, + {'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', 'ip_admin_eth0.netmask_admin_eth0': '255.255.255.255'}]} # cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1']) assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None with pytest.raises(PropertiesOptionError): cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() - ret = cfg.value.dict() - assert set(ret.keys()) == set(['ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0']) - assert ret['ip_admin_eth0.ip_admin_eth0'] == ['192.168.1.2', '192.168.1.1'] - assert len(ret['ip_admin_eth0.netmask_admin_eth0']) == 2 - assert ret['ip_admin_eth0.netmask_admin_eth0'][0] is None - assert isinstance(ret['ip_admin_eth0.netmask_admin_eth0'][1], PropertiesOptionError) - del ret['ip_admin_eth0.netmask_admin_eth0'][1] - del ret['ip_admin_eth0.netmask_admin_eth0'][0] - del ret['ip_admin_eth0.netmask_admin_eth0'] - assert cfg.value.dict(leader_to_list=True) == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', - 'ip_admin_eth0.netmask_admin_eth0': None}, - {'ip_admin_eth0.ip_admin_eth0': '192.168.1.1'}]} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', + 'ip_admin_eth0.netmask_admin_eth0': None}, + {'ip_admin_eth0.ip_admin_eth0': '192.168.1.1'}]} # cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('255.255.255.255') - ret = cfg.value.dict() - assert set(ret.keys()) == set(['ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0']) - assert ret['ip_admin_eth0.ip_admin_eth0'] == ['192.168.1.2', '192.168.1.1'] - assert len(ret['ip_admin_eth0.netmask_admin_eth0']) == 2 - assert ret['ip_admin_eth0.netmask_admin_eth0'][0] == '255.255.255.255' - assert isinstance(ret['ip_admin_eth0.netmask_admin_eth0'][1], PropertiesOptionError) - del ret['ip_admin_eth0.netmask_admin_eth0'][1] - del ret['ip_admin_eth0.netmask_admin_eth0'][0] - del ret['ip_admin_eth0.netmask_admin_eth0'] - assert cfg.value.dict(leader_to_list=True) == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', - 'ip_admin_eth0.netmask_admin_eth0': '255.255.255.255'}, - {'ip_admin_eth0.ip_admin_eth0': '192.168.1.1'}]} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': '192.168.1.2', + 'ip_admin_eth0.netmask_admin_eth0': '255.255.255.255'}, + {'ip_admin_eth0.ip_admin_eth0': '192.168.1.1'}]} # assert not list_sessions() @@ -1258,7 +1238,7 @@ def test_leadership_requires_no_leader(config_type): cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() with pytest.raises(PropertiesOptionError): cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['192.168.1.2', '192.168.1.1'], 'activate': False} + assert cfg.value.dict() == {'activate': False, 'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': '192.168.1.2'}, {'ip_admin_eth0.ip_admin_eth0': '192.168.1.1'}]} # assert not list_sessions() @@ -1319,53 +1299,10 @@ def test_leadership_requires_complet(config_type): cfg = get_config(cfg, config_type) cfg.option('options.unicode.unicode').value.set(['test', 'trah']) cfg.option('options.unicode.unicode2', 0).value.set('test') - dico = cfg.value.dict() - assert dico.keys() == set(['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicode.unicode6', 'options.unicode.unicode7', 'options.unicodetoto']) - assert dico['options.unicode.unicode'] == ['test', 'trah'] - assert dico['options.unicode.unicode1'] == [None, None] - assert dico['options.unicode.unicode2'] == ['test', None] - assert dico['options.unicode.unicode3'][0] is None - assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError) - assert dico['options.unicode.unicode4'][0] is None - assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode6'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode6'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode7'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode7'][1], PropertiesOptionError) - assert dico['options.unicodetoto'] is None - del dico['options.unicode.unicode3'][1] - del dico['options.unicode.unicode3'] - del dico['options.unicode.unicode4'][1] - del dico['options.unicode.unicode4'] - del dico['options.unicode.unicode6'][1] - del dico['options.unicode.unicode6'][0] - del dico['options.unicode.unicode7'][1] - del dico['options.unicode.unicode7'][0] + assert cfg.value.dict() == {'options.unicode.unicode': [{'options.unicode.unicode': 'test', 'options.unicode.unicode1': None, 'options.unicode.unicode2': 'test', 'options.unicode.unicode3': None, 'options.unicode.unicode4': None}, {'options.unicode.unicode': 'trah', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}], 'options.unicodetoto': None} # cfg.option('options.unicodetoto').value.set('test') - dico = cfg.value.dict() - assert dico.keys() == set(['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicode.unicode5', 'options.unicode.unicode6', 'options.unicode.unicode7', 'options.unicodetoto']) - assert dico['options.unicode.unicode'] == ['test', 'trah'] - assert dico['options.unicode.unicode1'] == [None, None] - assert dico['options.unicode.unicode2'] == ['test', None] - assert dico['options.unicode.unicode3'][0] is None - assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError) - assert dico['options.unicode.unicode4'][0] is None - assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError) - assert dico['options.unicode.unicode5'] == [None, None] - assert dico['options.unicode.unicode6'][0] is None - assert isinstance(dico['options.unicode.unicode6'][1], PropertiesOptionError) - assert dico['options.unicode.unicode7'][0] is None - assert isinstance(dico['options.unicode.unicode7'][1], PropertiesOptionError) - assert dico['options.unicodetoto'] == 'test' - del dico['options.unicode.unicode3'][1] - del dico['options.unicode.unicode3'] - del dico['options.unicode.unicode4'][1] - del dico['options.unicode.unicode4'] - del dico['options.unicode.unicode6'][1] - del dico['options.unicode.unicode6'][0] - del dico['options.unicode.unicode7'][1] - del dico['options.unicode.unicode7'][0] + assert cfg.value.dict() == {'options.unicode.unicode': [{'options.unicode.unicode': 'test', 'options.unicode.unicode1': None, 'options.unicode.unicode2': 'test', 'options.unicode.unicode3': None, 'options.unicode.unicode4': None, 'options.unicode.unicode5': None, 'options.unicode.unicode6': None, 'options.unicode.unicode7': None}, {'options.unicode.unicode': 'trah', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None, 'options.unicode.unicode5': None}], 'options.unicodetoto': 'test'} # assert not list_sessions() @@ -1402,91 +1339,24 @@ def test_leadership_requires_transitive1(config_type): cfg = Config(od1) cfg.property.read_write() cfg = get_config(cfg, config_type) - assert cfg.value.dict() == {'options.unicode.unicode': [], 'options.unicode.unicode1': [], 'options.unicode.unicode3': [], 'options.unicode.unicode4': [], 'options.unicodetoto': None} + assert cfg.value.dict() == {'options.unicode.unicode': [], 'options.unicodetoto': None} # cfg.option('options.unicodetoto').value.set('test') - assert cfg.value.dict() == {'options.unicode.unicode': [], 'options.unicode.unicode1': [], 'options.unicode.unicode2': [], 'options.unicode.unicode3': [], 'options.unicode.unicode4': [], 'options.unicodetoto': 'test'} + assert cfg.value.dict() == {'options.unicode.unicode': [], 'options.unicodetoto': 'test'} # cfg.option('options.unicode.unicode').value.set(['a', 'b', 'c']) - dico = cfg.value.dict() - assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto'] - assert dico['options.unicodetoto'] == 'test' - assert dico['options.unicode.unicode'] == ['a', 'b', 'c'] - assert dico['options.unicode.unicode1'] == [None, None, None] - assert dico['options.unicode.unicode2'] == [None, None, None] - assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError) - del (dico['options.unicode.unicode3'][2]) - del (dico['options.unicode.unicode3'][1]) - del (dico['options.unicode.unicode3'][0]) - del (dico['options.unicode.unicode4'][2]) - del (dico['options.unicode.unicode4'][1]) - del (dico['options.unicode.unicode4'][0]) + assert cfg.value.dict() == {'options.unicode.unicode': [{'options.unicode.unicode': 'a', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}, {'options.unicode.unicode': 'b', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}, {'options.unicode.unicode': 'c', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}], 'options.unicodetoto': 'test'} cfg.option('options.unicode.unicode2', 1).value.set('test') cfg.option('options.unicode.unicode3', 1).value.set('test') - dico = cfg.value.dict() - assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto'] - assert dico['options.unicodetoto'] == 'test' - assert dico['options.unicode.unicode'] == ['a', 'b', 'c'] - assert dico['options.unicode.unicode1'] == [None, None, None] - assert dico['options.unicode.unicode2'] == [None, 'test', None] - assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError) - assert dico['options.unicode.unicode3'][1] == 'test' - assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError) - assert dico['options.unicode.unicode4'][1] == None - assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError) - del (dico['options.unicode.unicode3'][2]) - del (dico['options.unicode.unicode3'][1]) - del (dico['options.unicode.unicode3'][0]) - del (dico['options.unicode.unicode4'][2]) - del (dico['options.unicode.unicode4'][1]) - del (dico['options.unicode.unicode4'][0]) + assert cfg.value.dict() == {'options.unicode.unicode': [{'options.unicode.unicode': 'a', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}, {'options.unicode.unicode': 'b', 'options.unicode.unicode1': None, 'options.unicode.unicode2': 'test', 'options.unicode.unicode3': 'test', 'options.unicode.unicode4': None}, {'options.unicode.unicode': 'c', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}], 'options.unicodetoto': 'test'} # cfg.option('options.unicode.unicode2', 1).value.set('rah') - dico = cfg.value.dict() - assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto'] - assert dico['options.unicodetoto'] == 'test' - assert dico['options.unicode.unicode'] == ['a', 'b', 'c'] - assert dico['options.unicode.unicode1'] == [None, None, None] - assert dico['options.unicode.unicode2'] == [None, 'rah', None] - assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError) - del (dico['options.unicode.unicode3'][2]) - del (dico['options.unicode.unicode3'][1]) - del (dico['options.unicode.unicode3'][0]) - del (dico['options.unicode.unicode4'][2]) - del (dico['options.unicode.unicode4'][1]) - del (dico['options.unicode.unicode4'][0]) + assert cfg.value.dict() == {'options.unicode.unicode': [{'options.unicode.unicode': 'a', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}, {'options.unicode.unicode': 'b', 'options.unicode.unicode1': None, 'options.unicode.unicode2': 'rah'}, {'options.unicode.unicode': 'c', 'options.unicode.unicode1': None, 'options.unicode.unicode2': None}], 'options.unicodetoto': 'test'} # cfg.option('options.unicode.unicode2', 1).value.set('test') cfg.option('options.unicodetoto').value.set('rah') - dico = cfg.value.dict() - assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto'] - assert dico['options.unicodetoto'] == 'rah' - assert dico['options.unicode.unicode'] == ['a', 'b', 'c'] - assert dico['options.unicode.unicode1'] == [None, None, None] - assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError) - assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError) - del (dico['options.unicode.unicode3'][2]) - del (dico['options.unicode.unicode3'][1]) - del (dico['options.unicode.unicode3'][0]) - del (dico['options.unicode.unicode4'][2]) - del (dico['options.unicode.unicode4'][1]) - del (dico['options.unicode.unicode4'][0]) + assert cfg.value.dict() == {'options.unicode.unicode': [{'options.unicode.unicode': 'a', 'options.unicode.unicode1': None}, {'options.unicode.unicode': 'b', 'options.unicode.unicode1': None}, {'options.unicode.unicode': 'c', 'options.unicode.unicode1': None}], 'options.unicodetoto': 'rah'} # assert not list_sessions() diff --git a/tests/test_slots.py b/tests/test_slots.py index 170ac68..e7dfa5a 100644 --- a/tests/test_slots.py +++ b/tests/test_slots.py @@ -11,7 +11,6 @@ try: except: tiramisu_version = 2 from tiramisu import Config -from tiramisu.config import SubConfig from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption,\ StrOption, SymLinkOption, StrOption, IPOption, OptionDescription, \ PortOption, NetworkOption, NetmaskOption, DomainnameOption, EmailOption, \ @@ -158,28 +157,6 @@ def test_slots_option_readonly(): # assert slots == set(OptionDescription.__slots__) -def test_slots_config(): - od1 = OptionDescription('a', '', []) - od2 = OptionDescription('a', '', [od1]) - cfg = Config(od2) - with pytest.raises(AttributeError): - cfg._config_bag.context.x = 1 - with pytest.raises(AttributeError): - cfg._config_bag.context.x = 1 - option_bag = OptionBag(od2, - 'a', - ConfigBag(cfg._config_bag.context, None, None), - properties=None, - ) - sc = cfg._config_bag.context.get_subconfig(option_bag) - assert isinstance(sc, SubConfig) - with pytest.raises(AttributeError): - sc.x = 1 - with pytest.raises(AttributeError): - sc.x = 1 -# assert not list_sessions() - - def test_slots_setting(): od1 = OptionDescription('a', '', []) od2 = OptionDescription('a', '', [od1]) diff --git a/tests/test_symlink.py b/tests/test_symlink.py index eeb03eb..a66e9ac 100644 --- a/tests/test_symlink.py +++ b/tests/test_symlink.py @@ -43,7 +43,7 @@ def test_symlink_assign_option(config_type): [linkopt, OptionDescription("s1", "", [boolopt])]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(ConfigError): + with pytest.raises(APIError): cfg.option('c').value.set(True) # assert not list_sessions() @@ -55,7 +55,7 @@ def test_symlink_del_option(config_type): [linkopt, OptionDescription("s1", "", [boolopt])]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(ConfigError): + with pytest.raises(APIError): cfg.option('c').value.reset() # assert not list_sessions() @@ -191,7 +191,7 @@ def test_symlink_assign(config_type): [linkopt, OptionDescription("s1", "", [boolopt])]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(ConfigError): + with pytest.raises(APIError): cfg.option('c').value.set(True) # assert not list_sessions() @@ -246,9 +246,9 @@ def test_symlink_with_leader(config_type): od1 = OptionDescription('root', '', [interface1, leader]) cfg = Config(od1) cfg = get_config(cfg, config_type) - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'ip_admin_eth0.netmask_admin_eth0': [], 'leader': []} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'leader': []} cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2']) - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['val1', 'val2'], 'ip_admin_eth0.netmask_admin_eth0': [None, None], 'leader': ['val1', 'val2']} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'val1', 'ip_admin_eth0.netmask_admin_eth0': None}, {'ip_admin_eth0.ip_admin_eth0': 'val2', 'ip_admin_eth0.netmask_admin_eth0': None}], 'leader': ['val1', 'val2']} cfg.option('ip_admin_eth0.ip_admin_eth0').value.pop(0) with pytest.raises(APIError): cfg.option('leader').value.pop(0) @@ -263,36 +263,36 @@ def test_symlink_with_follower(config_type): od1 = OptionDescription('root', '', [interface1, follower]) cfg = Config(od1) cfg = get_config(cfg, config_type) - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'ip_admin_eth0.netmask_admin_eth0': [], 'follower': []} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'follower': []} cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2']) - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['val1', 'val2'], 'ip_admin_eth0.netmask_admin_eth0': [None, None], 'follower': [None, None]} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'val1', 'ip_admin_eth0.netmask_admin_eth0': None}, {'ip_admin_eth0.ip_admin_eth0': 'val2', 'ip_admin_eth0.netmask_admin_eth0': None}], 'follower': [None, None]} # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == 'default' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).owner.get() == 'default' - assert cfg.option('follower', 0).owner.get() == 'default' - assert cfg.option('follower', 1).owner.get() == 'default' - assert cfg.option('follower').owner.get() == ['default', 'default'] + with pytest.raises(APIError): + assert cfg.option('follower', 0).owner.get() == 'default' + assert cfg.option('follower').owner.get() == 'default' # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == None - assert cfg.option('follower', 0).value.get() == None - assert cfg.option('follower', 1).value.get() == None + with pytest.raises(APIError): + assert cfg.option('follower', 0).value.get() == None assert cfg.option('follower').value.get() == [None, None] # cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val3') - assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['val1', 'val2'], 'ip_admin_eth0.netmask_admin_eth0': [None, 'val3'], 'follower': [None, 'val3']} + assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'val1', 'ip_admin_eth0.netmask_admin_eth0': None}, {'ip_admin_eth0.ip_admin_eth0': 'val2', 'ip_admin_eth0.netmask_admin_eth0': 'val3'}], 'follower': [None, 'val3']} # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == 'val3' - assert cfg.option('follower', 0).value.get() == None - assert cfg.option('follower', 1).value.get() == 'val3' + with pytest.raises(APIError): + assert cfg.option('follower', 0).value.get() == None assert cfg.option('follower').value.get() == [None, 'val3'] # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == 'default' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).owner.get() == 'user' - assert cfg.option('follower', 0).owner.get() == 'default' - assert cfg.option('follower', 1).owner.get() == 'user' - assert cfg.option('follower').owner.get() == ['default', 'user'] + with pytest.raises(APIError): + assert cfg.option('follower', 0).owner.get() == 'default' + assert cfg.option('follower').owner.get() == 'user' # assert not list_sessions() diff --git a/tiramisu/api.py b/tiramisu/api.py index 45239bb..e258c97 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -26,7 +26,7 @@ from .error import APIError, ConfigError, LeadershipError, PropertiesOptionError from .i18n import _ from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, \ FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, EXPIRATION_TIME -from .config import KernelConfig, SubConfig, KernelGroupConfig, KernelMetaConfig, KernelMixConfig +from .config import KernelConfig, KernelGroupConfig, KernelMetaConfig, KernelMixConfig from .option import RegexpOption, OptionDescription from .todict import TiramisuDict @@ -84,68 +84,83 @@ class CommonTiramisu(TiramisuHelp): _allow_optiondescription = True _validate_properties = True - def _get_option(self) -> Any: - config_bag = self._option_bag.config_bag - if not self._subconfig: - try: - subconfig, name = config_bag.context.get_home_by_path(self._option_bag.path, - config_bag, - validate_properties=self._validate_properties, + def _get_options_bag(self) -> OptionBag: + try: + options_bag = self._config_bag.context.get_sub_option_bag(self._config_bag, + self._path, + self._index, + self._validate_properties, ) - except AssertionError as err: - raise APIError(str(err)) - except Exception as err: - raise err - self._subconfig = subconfig - self._name = name - option = self._option_bag.option - if option is None: - option = self._subconfig.get_description().get_child(self._name, - config_bag, - self._subconfig.get_path(), - ) - self._option_bag.option = option - # Calculate option's properties - - settings = config_bag.context.get_settings() - self._option_bag.properties = settings.getproperties(self._option_bag) - if self._validate_properties: - settings.validate_properties(self._option_bag) - index = self._option_bag.index - if index is not None: - if option.impl_is_optiondescription() or not option.impl_is_follower(): - self._option_bag.option = None - raise APIError('index must be set only with a follower option') - self._length = self._subconfig.get_length_leadership(self._option_bag) - if index >= self._length: - self._option_bag.option = None - raise LeadershipError(_('index "{}" is greater than the leadership length "{}" ' - 'for option "{}"').format(index, - self._length, - option.impl_get_display_name())) - if not self._allow_optiondescription and option.impl_is_optiondescription(): - self._option_bag.option = None - raise APIError(_('option must not be an optiondescription')) - return option + except AssertionError as err: + raise APIError(str(err)) + except Exception as err: + raise err + return options_bag def load_option(func): def wrapped(self, *args, **kwargs): - self._get_option() - return func(self, *args, **kwargs) + options_bag = self._get_options_bag() + return func(self, options_bag, *args, **kwargs) wrapped.func = func return wrapped +def option_type(typ): + if not isinstance(typ, list): + types = [typ] + else: + types = typ + + def wrapper(func): + @wraps(func) + def wrapped(*args, **kwargs): + config_bag = args[0]._config_bag + if args[0]._config_bag.context.impl_type == 'group' and 'group' in types: + options_bag = [OptionBag(None, + None, + args[0]._config_bag, + path=args[0]._path, + )] + kwargs['is_group'] = True + return func(args[0], options_bag, *args[1:], **kwargs) + options_bag = args[0]._get_options_bag() + option = options_bag[-1].option + if option.impl_is_optiondescription() and 'optiondescription' 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 \ + option.get_type() == 'choice' and 'choice' in types)): + if not option.impl_is_optiondescription() and not option.impl_is_symlinkoption() and option.impl_is_follower(): + if 'with_index' in types and args[0]._index is not None: + raise APIError(_(f'please do not specify index ({args[0].__class__.__name__}.{func.__name__})')) + if 'with_index' not in types and args[0]._index is None: + raise APIError(_(f'please specify index with a follower option ({args[0].__class__.__name__}.{func.__name__})')) + elif args[0]._index is not None: + raise APIError(_(f'please specify an index only for follower option ({args[0].__class__.__name__}.{func.__name__})')) + return func(args[0], options_bag, *args[1:], **kwargs) + raise APIError(_(f'please specify a valid sub function ({args[0].__class__.__name__}.{func.__name__})')) + wrapped.func = func + return wrapped + return wrapper + + class CommonTiramisuOption(CommonTiramisu): _allow_optiondescription = False _follower_need_index = True _validate_properties = False def __init__(self, - option_bag: OptionBag) -> None: - self._option_bag = option_bag - self._subconfig = None + path: str, + index: Optional[int], + config_bag: ConfigBag, + ) -> None: + self._path = path + self._index = index + self._config_bag = config_bag def __getattr__(self, subfunc): raise APIError(_('please specify a valid sub function ({})').format(subfunc)) @@ -161,12 +176,6 @@ class _TiramisuOptionWalk: None, config_bag, ) - if opt.impl_is_optiondescription(): - config_bag.context.get_settings().validate_properties(option_bag) - return subconfig.get_subconfig(option_bag) - subconfig.getattr(opt.impl_getname(), - option_bag, - ) def _walk(self, option, @@ -179,9 +188,11 @@ class _TiramisuOptionWalk: options = [] for opt in option.get_children(config_bag): try: + #FIXME trop compliqué devrait faire avec get_sub_option_bag ou get_children ne devrait pas lister les variables disables subsubconfig = self._filter(opt, subconfig, - config_bag) + config_bag, + ) except PropertiesOptionError: continue if opt.impl_is_optiondescription(): @@ -203,6 +214,37 @@ class _TiramisuOptionWalk: )) return options + def _list2(self, + root_option_bag, + type, + group_type, + recursive, + ): + assert type in ('all', 'option', 'optiondescription'), _('unknown list type {}').format(type) + assert group_type is None or isinstance(group_type, groups.GroupType), \ + _("unknown group_type: {0}").format(group_type) + options = [] + types = {'option': ['option'], + 'optiondescription': ['optiondescription'], + 'all': ['option', 'optiondescription']}[type] + for option_bag in self._config_bag.context.walk(root_option_bag, + recursive=recursive, + types=types, + group_type=group_type, + ): + if isinstance(option_bag, dict): + for opt_bag in option_bag.values(): + options.append(TiramisuOption(opt_bag.path, + opt_bag.index, + self._config_bag, + )) + else: + options.append(TiramisuOption(option_bag.path, + option_bag.index, + self._config_bag, + )) + return options + def _list(self, type, group_type, @@ -223,7 +265,8 @@ class _TiramisuOptionWalk: type, group_type, config_bag, - subconfig): + subconfig, + ): options.append(opt) return options @@ -234,147 +277,173 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption): _follower_need_index = False _validate_properties = False - def __init__(self, - option_bag: OptionBag): - super().__init__(option_bag) - self._config = option_bag.config_bag.context - @load_option - def get(self): + def get(self, options_bag: List[OptionBag]): """Get Tiramisu option""" - return self._option_bag.option + option_bag = options_bag[-1] + return option_bag.option @load_option - def isleadership(self): + def isleadership(self, options_bag: List[OptionBag]): """Test if option is a leader or a follower""" - return self._option_bag.option.impl_is_leadership() + option_bag = options_bag[-1] + return option_bag.option.impl_is_leadership() @load_option - def doc(self): + def doc(self, options_bag: List[OptionBag]): """Get option document""" - return self._option_bag.option.impl_get_display_name() + option_bag = options_bag[-1] + return option_bag.option.impl_get_display_name() @load_option - def description(self): + def description(self, options_bag: List[OptionBag]): """Get option description""" - return self._option_bag.option.impl_get_information('doc', None) + option_bag = options_bag[-1] + return option_bag.option.impl_get_information('doc', None) @load_option def name(self, - follow_symlink: bool=False) -> str: + options_bag: List[OptionBag], + follow_symlink: bool=False, + ) -> str: """Get option name""" + option_bag = options_bag[-1] if not follow_symlink or \ - self._option_bag.option.impl_is_optiondescription() or \ - not self._option_bag.option.impl_is_symlinkoption(): - return self._option_bag.option.impl_getname() - else: - return self._option_bag.option.impl_getopt().impl_getname() + option_bag.option.impl_is_optiondescription() or \ + not option_bag.option.impl_is_symlinkoption(): + return option_bag.option.impl_getname() + return option_bag.option.impl_getopt().impl_getname() @load_option - def path(self) -> str: + def path(self, options_bag: List[OptionBag]) -> str: """Get option path""" - return self._option_bag.path + option_bag = options_bag[-1] + return option_bag.path @load_option - def has_dependency(self, self_is_dep=True): + def has_dependency(self, + options_bag: List[OptionBag], + self_is_dep=True, + ) -> bool: """Test if option has dependency""" - return self._option_bag.option.impl_has_dependency(self_is_dep) + option_bag = options_bag[-1] + return option_bag.option.impl_has_dependency(self_is_dep) @load_option - def dependencies(self): + def dependencies(self, options_bag: List[OptionBag]): """Get dependencies from this option""" + option_bag = options_bag[-1] options = [] - for option in self._option_bag.option._get_dependencies(self._option_bag.config_bag.context): + for option in option_bag.option._get_dependencies(self._config_bag.context): options.append(TiramisuOption(option().impl_getpath(), None, - self._option_bag.config_bag, + self._config_bag, )) return options @load_option - def isoptiondescription(self): + def isoptiondescription(self, options_bag: List[OptionBag]): """Test if option is an optiondescription""" - return self._option_bag.option.impl_is_optiondescription() + option_bag = options_bag[-1] + return option_bag.option.impl_is_optiondescription() @load_option def properties(self, + options_bag: List[OptionBag], only_raises=False, - uncalculated=False): + uncalculated=False, + ): """Get properties for an option""" - settings = self._option_bag.config_bag.context.get_settings() + option_bag = options_bag[-1] + settings = self._config_bag.context.get_settings() if uncalculated: - return settings.getproperties(self._option_bag, - uncalculated=True) + return settings.getproperties(option_bag, + uncalculated=True, + ) if not only_raises: - return settings.getproperties(self._option_bag, - apply_requires=False) + return settings.getproperties(option_bag, + apply_requires=False, + ) # do not check cache properties/permissives which are not save (unrestraint, ...) - return settings.calc_raises_properties(self._option_bag, + return settings.calc_raises_properties(option_bag, apply_requires=False, - uncalculated=uncalculated) + uncalculated=uncalculated, + ) def __call__(self, name: str, - index: Optional[int]=None) -> 'TiramisuOption': + index: Optional[int]=None, + ) -> 'TiramisuOption': """Select an option by path""" - path = self._option_bag.path + '.' + name - return TiramisuOption(path, + return TiramisuOption(self._path + '.' + name, index, - self._option_bag.config_bag) + self._config_bag, + ) class TiramisuOptionOption(_TiramisuOptionOptionDescription): """Manage option""" @load_option - def ismulti(self): + def ismulti(self, options_bag: List[OptionBag]): """Test if option could have multi value""" - return self._option_bag.option.impl_is_multi() + option_bag = options_bag[-1] + return option_bag.option.impl_is_multi() @load_option - def issubmulti(self): + def issubmulti(self, options_bag: List[OptionBag]): """Test if option could have submulti value""" - return self._option_bag.option.impl_is_submulti() + option_bag = options_bag[-1] + return option_bag.option.impl_is_submulti() @load_option - def isleader(self): + def isleader(self, options_bag: List[OptionBag]): """Test if option is a leader""" - return self._option_bag.option.impl_is_leader() + option_bag = options_bag[-1] + return option_bag.option.impl_is_leader() @load_option - def isfollower(self): + def isfollower(self, options_bag: List[OptionBag]): """Test if option is a follower""" - return self._option_bag.option.impl_is_follower() + option_bag = options_bag[-1] + return option_bag.option.impl_is_follower() @load_option - def isdynamic(self): + def isdynamic(self, options_bag: List[OptionBag]): """Test if option is a dynamic optiondescription""" - return self._option_bag.option.impl_is_dynsymlinkoption() + option_bag = options_bag[-1] + return option_bag.option.impl_is_dynsymlinkoption() @load_option - def issymlinkoption(self) -> bool: - return self._option_bag.option.impl_is_symlinkoption() + def issymlinkoption(self, options_bag: List[OptionBag]) -> bool: + """Test if option is a symlink option""" + option_bag = options_bag[-1] + return option_bag.option.impl_is_symlinkoption() @load_option - def default(self): + def default(self, options_bag: List[OptionBag]): """Get default value for an option (not for optiondescription)""" - return self._option_bag.option.impl_getdefault() + option_bag = options_bag[-1] + return option_bag.option.impl_getdefault() @load_option - def defaultmulti(self): + def defaultmulti(self, options_bag: List[OptionBag]): """Get default value when added a value for a multi option (not for optiondescription)""" - option = self._option_bag.option - ret = option.impl_getdefault_multi() - return ret + option_bag = options_bag[-1] + return option_bag.option.impl_getdefault_multi() @load_option - def type(self): - if self._option_bag.option.impl_is_optiondescription(): + def type(self, options_bag: List[OptionBag]): + """Get de option type""" + option_bag = options_bag[-1] + if option_bag.option.impl_is_optiondescription(): return 'optiondescription' - return self._option_bag.option.get_type() + return option_bag.option.get_type() @load_option - def pattern(self) -> str: - option = self._option_bag.option + def pattern(self, options_bag: List[OptionBag]) -> str: + """Get the option pattern""" + option_bag = options_bag[-1] + option = option_bag.option type = option.get_type() if isinstance(option, RegexpOption): return option._regexp.pattern @@ -388,57 +457,56 @@ class TiramisuOptionOption(_TiramisuOptionOptionDescription): 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]?)$' @load_option - def leader(self): - return TiramisuOption(self._option_bag.option.impl_get_leadership().get_leader().impl_getpath(), + def leader(self, options_bag: List[OptionBag]): + """Get the leader option for a follower option""" + option_bag = options_bag[-1] + return TiramisuOption(option_bag.option.impl_get_leadership().get_leader().impl_getpath(), None, - self._option_bag.config_bag) + self._config_bag) + + @load_option + def index(self, options_bag: List[OptionBag]): + """Get then index of option""" + return options_bag[-1].index class TiramisuOptionOwner(CommonTiramisuOption): #FIXME optiondescription must not have Owner! """Manage option's owner""" - def __init__(self, - option_bag: OptionBag) -> None: - - super().__init__(option_bag) - if option_bag is not None: - # for help() - self._values = self._option_bag.config_bag.context.get_values() - - @load_option - def get(self): + @option_type(['symlink', 'option']) + def get(self, options_bag: List[OptionBag]): """Get owner for a specified option""" - if self._option_bag.option.impl_is_follower() and self._option_bag.index is None: - if self._option_bag.option.impl_is_symlinkoption(): - length = self._subconfig.get_length_leadership(self._option_bag) - value = [] - for index in range(length): - soption_bag = self._option_bag.copy() - soption_bag.index = index - value.append(self._values.getowner(soption_bag, - self._name, - ) - ) - return value - raise APIError('index must be set with a follower option') - return self._values.getowner(self._option_bag) + option_bag = options_bag[-1] + if len(options_bag) > 1: + parent_option_bag = options_bag[-2] + else: + parent_option_bag = None + return self._config_bag.context.get_owner(option_bag, + parent_option_bag, + ) - @load_option - def isdefault(self): + @option_type(['symlink', 'option']) + def isdefault(self, options_bag: List[OptionBag]): """Is option has defaut value""" - return self._values.is_default_owner(self._option_bag) + option_bag = options_bag[-1] + return self._config_bag.context.get_values().is_default_owner(option_bag) - @load_option - def set(self, owner): + @option_type('option') + def set(self, + options_bag: List[OptionBag], + owner: str, + ) -> None: """Get owner for a specified option""" + option_bag = options_bag[-1] try: obj_owner = getattr(owners, owner) except AttributeError: owners.addowner(owner) obj_owner = getattr(owners, owner) - self._values.setowner(obj_owner, - self._option_bag) + self._config_bag.context.get_values().set_owner(option_bag, + obj_owner, + ) class TiramisuOptionProperty(CommonTiramisuOption): @@ -447,56 +515,58 @@ class TiramisuOptionProperty(CommonTiramisuOption): _follower_need_index = False _validate_properties = False - def __init__(self, - option_bag: OptionBag) -> None: - super().__init__(option_bag) - if option_bag and option_bag.config_bag: - self._settings = option_bag.config_bag.context.get_settings() - @load_option def get(self, - only_raises=False, - uncalculated=False): + options_bag: List[OptionBag], + only_raises=False, + uncalculated=False, + ): """Get properties for an option""" + option_bag = options_bag[-1] if not only_raises: - return self._option_bag.properties + return option_bag.properties # do not check cache properties/permissives which are not save (unrestraint, ...) - ret = self._settings.calc_raises_properties(self._option_bag, - uncalculated=uncalculated) + settings = self._config_bag.context.get_settings() + ret = settings.calc_raises_properties(option_bag, + uncalculated=uncalculated, + ) return ret @load_option - def add(self, prop): + def add(self, + options_bag: List[OptionBag], + prop,): """Add new property for an option""" + option_bag = options_bag[-1] if prop in FORBIDDEN_SET_PROPERTIES: raise ConfigError(_('cannot add this property: "{0}"').format( ' '.join(prop))) - props = self._settings._getproperties(self._option_bag.path, - self._option_bag.index, - self._option_bag.option.impl_getproperties(), - ) - self._settings.setproperties(self._option_bag.path, - props | {prop}, - self._option_bag, - self._option_bag.config_bag.context) + settings = self._config_bag.context.get_settings() + props = settings._getproperties(option_bag.path, + option_bag.index, + option_bag.option.impl_getproperties(), + ) + settings.setproperties(option_bag, + props | {prop}, + ) @load_option - def remove(self, prop): + def remove(self, + options_bag: List[OptionBag], + prop, + ): """Remove new property for an option""" - props = self._settings._getproperties(self._option_bag.path, - self._option_bag.index, - self._option_bag.option.impl_getproperties(), - ) - self._settings.setproperties(self._option_bag.path, - props - {prop}, - self._option_bag, - self._option_bag.config_bag.context) + option_bag = options_bag[-1] + props = option_bag.properties + self._config_bag.context.get_settings().setproperties(option_bag, + props - {prop}, + ) @load_option - def reset(self): + def reset(self, options_bag: List[OptionBag]): """Reset all personalised properties""" - self._settings.reset(self._option_bag, - self._option_bag.config_bag) + option_bag = options_bag[-1] + self._config_bag.context.get_settings().reset(option_bag) class TiramisuOptionPermissive(CommonTiramisuOption): @@ -504,30 +574,28 @@ class TiramisuOptionPermissive(CommonTiramisuOption): _allow_optiondescription = True _follower_need_index = False - def __init__(self, - option_bag: OptionBag) -> None: - super().__init__(option_bag) - if option_bag and option_bag.config_bag: - self._settings = option_bag.config_bag.context.get_settings() - @load_option - def get(self): + def get(self, options_bag: List[OptionBag]): """Get permissives value""" - return self._settings.getpermissives(self._option_bag) + option_bag = options_bag[-1] + return self._config_bag.context.get_settings().getpermissives(option_bag) @load_option - def set(self, permissives): + def set(self, + options_bag: List[OptionBag], + permissives, + ): """Set permissives value""" - self._settings.setpermissives(self._option_bag, - permissives=permissives, - ) + option_bag = options_bag[-1] + self._config_bag.context.get_settings().setpermissives(option_bag, + permissives=permissives, + ) @load_option - def reset(self): + def reset(self, options_bag: List[OptionBag]): """Reset all personalised permissive""" - self._settings.reset_permissives(self._option_bag, - self._option_bag.config_bag, - ) + option_bag = options_bag[-1] + self._config_bag.context.get_settings().reset_permissives(option_bag) class TiramisuOptionInformation(CommonTiramisuOption): @@ -535,100 +603,56 @@ class TiramisuOptionInformation(CommonTiramisuOption): _allow_optiondescription = True _follower_need_index = False - def __init__(self, - option_bag: OptionBag) -> None: - super().__init__(option_bag) - @load_option - def get(self, key, default=undefined): + def get(self, + options_bag: List[OptionBag], + key: str, + default=undefined, + ) -> Any: """Get information""" - values = self._option_bag.config_bag.context.get_values() + option_bag = options_bag[-1] try: - return values.get_information(self._option_bag.config_bag, - self._option_bag, - key, - undefined, - ) + return self._config_bag.context.get_values().get_information(self._config_bag, + option_bag, + key, + undefined, + ) except ValueError: - return self._option_bag.option.impl_get_information(key, default) + return option_bag.option.impl_get_information(key, default) @load_option - def set(self, key, value): + def set(self, + options_bag: List[OptionBag], + key: str, + value: Any) -> None: """Set information""" - path = self._option_bag.path - values = self._option_bag.config_bag.context.get_values() - values.set_information(self._option_bag.config_bag, - self._option_bag, - key, - value, - ) + option_bag = options_bag[-1] + self._config_bag.context.get_values().set_information(self._config_bag, + option_bag, + key, + value, + ) @load_option def reset(self, - key: str, - ) -> None: + options_bag: List[OptionBag], + key: str, + ) -> None: """Remove information""" - path = self._option_bag.path - values = self._option_bag.config_bag.context.get_values() - values.del_information(key, - path=path, - ) + option_bag = options_bag[-1] + self._config_bag.context.get_values().del_information(key, + path=option_bag.path, + ) @load_option - def list(self): + def list(self, + options_bag: List[OptionBag], + ) -> list: """List information's keys""" - path = self._option_bag.path - values = self._option_bag.config_bag.context.get_values() - lst1 = set(self._option_bag.option.impl_list_information()) - lst2 = set(values.list_information(path, - )) + option_bag = options_bag[-1] + lst1 = set(option_bag.option.impl_list_information()) + lst2 = set(self._config_bag.context.get_values().list_information(option_bag.path)) return lst1 | lst2 -# -# def len(self): -# """Length of leadership""" -# option = self._get_option() -# # for example if index is None -# if '_length' not in vars(self): -# self._length = self._subconfig.get_length() -# return self._length - - -def option_type(typ): - if not isinstance(typ, list): - types = [typ] - else: - types = typ - - def wrapper(func): - @wraps(func) - def wrapped(*args, **kwargs): - config_bag = args[0]._option_bag.config_bag - for typ in types: - if typ == 'group': - if args[0]._option_bag.config_bag.context.impl_type == 'group': - ret = func(*args, **kwargs, is_group=True) - return ret - else: - option = args[0]._get_option() - if typ == 'option': - if option.impl_is_optiondescription(): - raise APIError(_('please specify a valid sub function ({})').format(func.__name__)) - elif typ == 'optiondescription': - if not option.impl_is_optiondescription(): - raise APIError(_('please specify a valid sub function ({})').format(func.__name__)) - elif typ == 'leader': - if not option.impl_is_leader(): - raise APIError(_('please specify a valid sub function ({})').format(func.__name__)) - elif typ == 'follower': - if not option.impl_is_follower() and not option.impl_is_leader(): - raise APIError(_('please specify a valid sub function ({})').format(func.__name__)) - elif typ == 'choice': - if not option.get_type() == 'choice': - raise APIError(_('please specify a valid sub function ({})').format(func.__name__)) - return func(*args, **kwargs) - wrapped.func = func - return wrapped - return wrapper class TiramisuOptionValue(CommonTiramisuOption): @@ -638,100 +662,94 @@ class TiramisuOptionValue(CommonTiramisuOption): _validate_properties = True @option_type('optiondescription') - def dict(self, - flatten=False, - withwarning: bool=False, - fullpath=False, - leader_to_list=False, - ): + def dict(self, options_bag: List[OptionBag]): """Dict with path as key and value""" - name = self._option_bag.option.impl_getname() - subconfig = self._subconfig.get_subconfig(self._option_bag) - config_bag = self._option_bag.config_bag - if not withwarning and config_bag.properties and 'warnings' in config_bag.properties: - config_bag = config_bag.copy() - config_bag.remove_warnings() - return subconfig.make_dict(config_bag=config_bag, - flatten=flatten, - fullpath=fullpath, - leader_to_list=leader_to_list) +#FIXME : .nowarnings comme .forcepermissive if not withwarning and self._config_bag.properties and 'warnings' in self._config_bag.properties: +# option_bag.config_bag = self._config_bag.copy() +# option_bag.config_bag.remove_warnings() + return self._config_bag.context.make_dict(options_bag[-1]) - @option_type('option') - def get(self): + @option_type(['option', 'symlink']) + def get(self, + options_bag: List[OptionBag], + ): + return self._get(options_bag) + + def _get(self, + options_bag: OptionBag, + ): """Get option's value""" - if self._option_bag.option.impl_is_follower() and self._option_bag.index is None: - # if it's a follower included in a symlinkoption, this should consider as a list - if self._option_bag.option.impl_is_symlinkoption(): - value = [] - for index in range(self._len()): - soption_bag = self._option_bag.copy() - soption_bag.index = index - value.append(self._subconfig.getattr(self._name, - soption_bag, - ) - ) - return value - raise APIError('index must be set with a follower option') - return self._subconfig.getattr(self._name, - self._option_bag, - ) + option_bag = options_bag[-1] + if len(options_bag) > 1: + parent_option_bag = options_bag[-2] + else: + parent_option_bag = None + return self._config_bag.context.get_value(option_bag, + parent_option_bag, + ) @option_type('option') - def set(self, value): + def set(self, + options_bag: List[OptionBag], + value, + ): """Change option's value""" - if self._option_bag.option.impl_is_follower() and \ - self._option_bag.index is None: - raise APIError('index must be set with a follower option') - values = self._option_bag.config_bag.context.get_values() + option_bag = options_bag[-1] + values = option_bag.config_bag.context.get_values() if isinstance(value, list): while undefined in value: idx = value.index(undefined) - soption_bag = self._option_bag.copy() + soption_bag = option_bag.copy() soption_bag.index = idx value[idx] = values.getdefaultvalue(soption_bag) elif value == undefined: - value = values.getdefaultvalue(self._option_bag) - self._subconfig.setattr(value, - self._option_bag) + value = values.getdefaultvalue(option_bag) + if option_bag.option.impl_is_leader() and len(value) < self._config_bag.context.get_length_leadership(options_bag[-2]): + raise LeadershipError(_('cannot reduce length of the leader "{}"' + '').format(option_bag.option.impl_get_display_name())) + return option_bag.config_bag.context.set_value(option_bag, + value, + ) @option_type(['group', 'option']) def reset(self, + options_bag: List[OptionBag], is_group: bool=False, ) -> None: """Reset value for an option""" + option_bag = options_bag[-1] if is_group: - self._option_bag.config_bag.context.reset(self._option_bag.path) + self._config_bag.context.reset(option_bag.path, + self._config_bag, + ) else: - if self._option_bag.option.impl_is_follower() and self._option_bag.index is None: - raise APIError('index must be set with a follower option') - self._subconfig.delattr(self._option_bag) + self._config_bag.context.delattr(option_bag) @option_type('option') - def default(self): + def default(self, options_bag: List[OptionBag]): """Get default value (default of option or calculated value)""" - option = self._option_bag.option - values = self._option_bag.config_bag.context.get_values() - if option.impl_is_follower() and self._option_bag.index is None: -# IF OU PAS IF ?? if self._option_bag.option.impl_is_symlinkoption(): + option_bag = options_bag[-1] + values = self._config_bag.context.get_values() + if option_bag.option.impl_is_symlinkoption(): value = [] - length = self._subconfig.get_length_leadership(self._option_bag) + length = self._config_bag.context.get_length_leadership(options_bag[-2]) for idx in range(length): - soption_bag = OptionBag(option, + soption_bag = OptionBag(options_bag.option, idx, - self._option_bag.config_bag, + self._config_bag, ) value.append(values.getdefaultvalue(soption_bag)) return value -# raise APIError('index must be set with a follower option') - else: - return values.getdefaultvalue(self._option_bag) + return values.getdefaultvalue(option_bag) @option_type('option') - def valid(self): + def valid(self, options_bag: List[OptionBag]): + """The if the option's value is valid""" + option_bag = options_bag[-1] try: with catch_warnings(record=True) as warns: simplefilter("always", ValueErrorWarning) - self.get() + self._get(options_bag) for warn in warns: if isinstance(warn.message, ValueErrorWarning): return False @@ -740,31 +758,30 @@ class TiramisuOptionValue(CommonTiramisuOption): return True @option_type('choice') - def list(self): + def list(self, options_bag: List[OptionBag]): """All values available for a ChoiceOption""" - return self._option_bag.option.impl_get_values(self._option_bag) + option_bag = options_bag[-1] + return option_bag.option.impl_get_values(option_bag) @option_type('leader') - def pop(self, index): + def pop(self, + options_bag: List[OptionBag], + index: int): """Pop a value""" - option_bag = self._option_bag - if option_bag.option.impl_is_symlinkoption(): - raise APIError(_("can't delete a SymLinkOption")) - option_bag.config_bag.context.get_values().reset_leadership(index, - option_bag, - self._subconfig, - ) + option_bag = options_bag[-1] + if len(options_bag) > 1: + leadership_option_bag = options_bag[-2] + else: + leadership_option_bag = None + self._config_bag.context.pop_leader(option_bag, + leadership_option_bag, + index, + ) - @option_type('follower') - def len(self): - return self._len() - - def _len(self): - """Length of follower option""" - # for example if index is None - if '_length' not in vars(self): - self._length = self._subconfig.get_length_leadership(self._option_bag) - return self._length + @option_type(['leader', 'follower', 'with_index']) + def len(self, options_bag: List[OptionBag]): + """Length for a follower option""" + return self._config_bag.context.get_length_leadership(options_bag[-2]) def _registers(_registers: Dict[str, type], @@ -782,7 +799,8 @@ def _registers(_registers: Dict[str, type], class TiramisuConfig(TiramisuHelp, _TiramisuOptionWalk): def __init__(self, config_bag: ConfigBag, - orig_config_bags: Optional[List[OptionBag]]) -> None: + orig_config_bags: Optional[List[OptionBag]], + ) -> None: self._config_bag = config_bag self._orig_config_bags = orig_config_bags @@ -820,70 +838,66 @@ class TiramisuOption(CommonTiramisu, TiramisuConfig): def __init__(self, path: Optional[str]=None, index: Optional[int]=None, - config_bag: Optional[ConfigBag]=None) -> None: - self._option_bag = OptionBag(None, - index, - config_bag, - path=path, - ) - self._subconfig = None + config_bag: Optional[ConfigBag]=None, + ) -> None: + self._path = path + self._index = index + self._config_bag = config_bag self._tiramisu_dict = None if not self._registers: _registers(self._registers, 'TiramisuOption') def __getattr__(self, subfunc: str) -> Any: if subfunc in self._registers: - return self._registers[subfunc](self._option_bag) + return self._registers[subfunc](self._path, + self._index, + self._config_bag, + ) raise APIError(_('please specify a valid sub function ({})').format(subfunc)) @option_type('optiondescription') def find(self, + options_bag: List[OptionBag], name: str, value=undefined, type=None, first: bool=False): """Find an option by name (only for optiondescription)""" + option_bag = options_bag[-1] if not first: ret = [] - option = self._option_bag.option - config_bag = self._option_bag.config_bag - oname = option.impl_getname() - option_bag = OptionBag(option, - None, - config_bag, - ) - subconfig = self._subconfig.get_subconfig(option_bag) - for path in subconfig.find(byname=name, - byvalue=value, - bytype=type, - _subpath=option_bag.path, - config_bag=config_bag): + for path in self._config_bag.context.find(option_bag=option_bag, + byname=name, + byvalue=value, + bytype=type, + ): t_option = TiramisuOption(path, None, # index for a follower ? - config_bag) + self._config_bag, + ) if first: return t_option ret.append(t_option) return ret @option_type('optiondescription') - def group_type(self): + def group_type(self, options_bag: List[OptionBag]): """Get type for an optiondescription (only for optiondescription)""" - return self._option_bag.option.impl_get_group_type() + return options_bag[-1].option.impl_get_group_type() @option_type('optiondescription') def list(self, + options_bag: List[OptionBag], type='option', recursive=False, - group_type=None): + group_type=None, + ): """List options (by default list only option)""" - return self._list(type, - group_type, - recursive, - self._option_bag.option, - self._subconfig.get_subconfig(self._option_bag), - self._option_bag.config_bag, - ) + return self._list2(options_bag[-1], + type, + group_type, + recursive, + ) def _load_dict(self, clearable: str="all", @@ -898,10 +912,12 @@ class TiramisuOption(CommonTiramisu, TiramisuConfig): @option_type('optiondescription') def dict(self, + options_bag: List[OptionBag], clearable: str="all", remotable: str="minimum", form: List=[], - force: bool=False) -> Dict: + force: bool=False, + ) -> Dict: """Convert config and option to tiramisu format""" if force or self._tiramisu_dict is None: self._load_dict(clearable, remotable) @@ -909,7 +925,9 @@ class TiramisuOption(CommonTiramisu, TiramisuConfig): @option_type('optiondescription') def updates(self, - body: List) -> Dict: + options_bag: List[OptionBag], + body: List, + ) -> Dict: """Updates value with tiramisu format""" if self._tiramisu_dict is None: # pragma: no cover self._load_dict() @@ -968,9 +986,22 @@ class TiramisuContextValue(TiramisuConfig): """Manage config value""" def mandatory(self): """Return path of options with mandatory property without any value""" + config_bag = self._config_bag.copy() + config_bag.properties -= {'mandatory', 'empty', 'warnings'} + config_bag.set_permissive() + root_option_bag = OptionBag(self._config_bag.context.get_description(), + None, + config_bag, + ) options = [] - for option in self._config_bag.context.get_values().mandatory_warnings(self._config_bag): - options.append(option) + for option_bag in self._config_bag.context.walk(root_option_bag, + recursive=True, + types=['mandatory'], + ): + options.append(TiramisuOption(option_bag.path, + option_bag.index, + self._config_bag, + )) return options # FIXME should be only for group/meta @@ -992,9 +1023,13 @@ class TiramisuContextValue(TiramisuConfig): kwargs['force_default_if_same'] = force_default_if_same if force_dont_change_value is not undefined: kwargs['force_dont_change_value'] = force_dont_change_value - return self._config_bag.context.set_value(path, + option_bag = OptionBag(None, + None, + self._config_bag, + path=path, + ) + return self._config_bag.context.set_value(option_bag, value, - self._config_bag, **kwargs, ) @@ -1008,22 +1043,13 @@ class TiramisuContextValue(TiramisuConfig): self._config_bag, ) - def dict(self, - flatten=False, - withwarning: bool=False, - fullpath=False, - leader_to_list=False, - ): + def dict(self): """Dict with path as key and value""" - config_bag = self._config_bag - if not withwarning and 'warnings' in config_bag.properties: - config_bag = config_bag.copy() - config_bag.remove_warnings() - return config_bag.context.make_dict(config_bag, - flatten=flatten, - fullpath=fullpath, - leader_to_list=leader_to_list, - ) + option_bag = OptionBag(self._config_bag.context.get_description(), + None, + self._config_bag, + ) + return self._config_bag.context.make_dict(option_bag) def exportation(self, with_default_owner: bool=False, @@ -1129,9 +1155,7 @@ class TiramisuContextProperty(TiramisuConfig): def reset(self): """Remove config properties""" context = self._config_bag.context - context.get_settings().reset(None, - self._config_bag, - ) + context.get_settings().reset(self._config_bag) self._reset_config_properties() def exportation(self): @@ -1236,8 +1260,7 @@ class TiramisuContextPermissive(TiramisuConfig): """Remove config permissives""" context = self._config_bag.context settings = context.get_settings() - settings.reset_permissives(None, - self._config_bag) + settings.reset_permissives(self._config_bag) self._reset_config_properties() def add(self, prop): @@ -1268,11 +1291,15 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk): first=False): """Find an or a list of options""" options = [] - context = self._config_bag.context - for path in context.find(byname=name, - byvalue=value, - bytype=type, - config_bag=self._config_bag): + 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) @@ -1287,13 +1314,15 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk): recursive=False, ): """List options (by default list only option)""" - return self._list(type, - group_type, - recursive, - self._config_bag.context.get_description(), - self._config_bag.context, - self._config_bag, - ) + root_option_bag = OptionBag(self._config_bag.context.get_description(), + None, + self._config_bag, + ) + return self._list2(root_option_bag, + type, + group_type, + recursive, + ) def _load_dict(self, clearable="all", @@ -1305,10 +1334,11 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk): ) def dict(self, - clearable="all", - remotable="minimum", - form=[], - force=False): + clearable="all", + remotable="minimum", + form=[], + force=False, + ): """Convert config and option to tiramisu format""" if force or self._tiramisu_dict is None: self._load_dict(clearable, remotable) @@ -1384,12 +1414,14 @@ class _TiramisuContextGroupConfig(TiramisuConfig): return ret def find(self, - name: str, - value=undefined): + name: str, + value=undefined, + ): """Find an or a list of config with finding option""" return GroupConfig(self._config_bag.context.find_group(byname=name, byvalue=value, - config_bag=self._config_bag)) + config_bag=self._config_bag, + )) def __call__(self, path: Optional[str]): @@ -1564,7 +1596,7 @@ class Config(TiramisuAPI): class MetaConfig(TiramisuAPI): - """MetaConfig object that enables us to handle the sub configuration's options""" + """MetaConfig object that enables us to handle the sub configuration's options with common root optiondescription""" def __init__(self, children: 'Config'=[], name=None, @@ -1596,7 +1628,7 @@ class MetaConfig(TiramisuAPI): class MixConfig(TiramisuAPI): - """MetaConfig object that enables us to handle the sub configuration's options""" + """MixConfig object that enables us to handle the sub configuration's options with differents root optiondescription""" def __init__(self, optiondescription: OptionDescription, children: List[Config], @@ -1628,7 +1660,7 @@ class MixConfig(TiramisuAPI): class GroupConfig(TiramisuAPI): - """GroupConfig that enables us to access the Config""" + """GroupConfig that enables us to access the sub configuration's options""" def __init__(self, children, name=None, diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 19f8656..8d6af7d 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -243,7 +243,12 @@ def manager_callback(callbk: Param, return index return None - def calc_self(callbk, option, index, value, config_bag): + def calc_self(callbk, + option, + index, + value, + config_bag, + ): # index must be apply only if follower is_follower = option.impl_is_follower() apply_index = calc_index(callbk, index, is_follower) @@ -251,12 +256,40 @@ def manager_callback(callbk: Param, if config_bag is undefined: return undefined path = option.impl_getpath() - option_bag = get_option_bag(config_bag, - option, - apply_index, - True, - ) - new_value = get_value(callbk, option_bag, path) + option_bag = OptionBag(option, + None, + config_bag, + properties=None, + ) + properties = config_bag.context.get_settings().getproperties(option_bag, + uncalculated=True, + ) + parent_option_bag, option_bag = get_option_bag(config_bag, + option, + callbk, + apply_index, + True, + properties=properties, + ) + if option.impl_is_follower() and apply_index is None: + new_value = [] + for idx in range(config_bag.context.get_length_leadership(parent_option_bag)): + parent_option_bag, option_bag = get_option_bag(config_bag, + option, + callbk, + idx, + True, + properties=properties, + ) + new_value.append(get_value(callbk, + option_bag, + path, + )) + else: + new_value = get_value(callbk, + option_bag, + path, + ) if apply_index is None and is_follower: new_value[index] = value value = new_value @@ -270,9 +303,7 @@ def manager_callback(callbk: Param, ): try: # get value - value = config_bag.context.getattr(path, - option_bag, - ) + value = config_bag.context.get_value(option_bag) except PropertiesOptionError as err: # raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation if callbk.notraisepropertyerror or callbk.raisepropertyerror: @@ -292,9 +323,12 @@ def manager_callback(callbk: Param, return value def get_option_bag(config_bag, - opt, - index_, - self_calc): + opt, + callbk, + index_, + self_calc, + properties=undefined, + ): # don't validate if option is option that we tried to validate config_bag = config_bag.copy() if for_settings: @@ -305,12 +339,41 @@ def manager_callback(callbk: Param, if self_calc: config_bag.unrestraint() config_bag.remove_validation() - option_bag = OptionBag(opt, - index_, - config_bag, - apply_requires=not self_calc, # if we are in properties calculation, cannot calculated properties - ) - return option_bag + root_option_bag = OptionBag(config_bag.context.get_description(), + None, + config_bag, + ) + try: + options_bag = config_bag.context.get_sub_option_bag(root_option_bag, + opt.impl_getpath(), + index_, + validate_properties=not self_calc, + properties=properties, + ) + except PropertiesOptionError as err: + # raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation + if callbk.notraisepropertyerror or callbk.raisepropertyerror: + raise err from err + raise ConfigError(_('unable to carry out a calculation for "{}"' + ', {}').format(option.impl_get_display_name(), err), 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 + except AttributeError as err: + if isinstance(callbk, ParamDynOption) and callbk.optional: + # cannot acces, simulate a propertyerror + raise PropertiesOptionError(options_bag[-1], + ['configerror'], + config_bag.context.get_settings(), + ) + raise ConfigError(_(f'unable to get value for calculating "{option.impl_get_display_name()}", {err}')) from err + if self_calc: + if len(options_bag) > 1: + parent_option_bag = options_bag[-2] + else: + parent_option_bag = None + return parent_option_bag, options_bag[-1] + else: + return options_bag[-1] if isinstance(callbk, ParamValue): return callbk.value @@ -345,11 +408,17 @@ def manager_callback(callbk: Param, if isinstance(callbk, ParamSelfOption): if leadership_must_have_index and option.impl_is_follower() and index is None: raise Break() - value = calc_self(callbk, option, index, orig_value, config_bag) + value = calc_self(callbk, + option, + index, + orig_value, + config_bag, + ) if not callbk.todict: return value return {'name': option.impl_get_display_name(), - 'value': value} + 'value': value, + } if isinstance(callbk, ParamOption): callbk_option = callbk.option @@ -362,7 +431,8 @@ def manager_callback(callbk: Param, suffix = callbk.suffix callbk_option = callbk_option.to_dynoption(rootpath, suffix, - subdyn) + subdyn, + ) found = True elif option.impl_is_dynsymlinkoption(): rootpath = option.rootpath @@ -416,6 +486,7 @@ def manager_callback(callbk: Param, path = callbk_option.impl_getpath() option_bag = get_option_bag(config_bag, callbk_option, + callbk, index_, False, ) diff --git a/tiramisu/cacheobj.py b/tiramisu/cacheobj.py index 54cedee..2c8cfac 100644 --- a/tiramisu/cacheobj.py +++ b/tiramisu/cacheobj.py @@ -52,7 +52,8 @@ class Cache: index, props, self_props, - type_): + type_, + ): no_cache = False, None, False if 'cache' in props or type_ == 'context_props': values = self._cache.get(path) diff --git a/tiramisu/config.py b/tiramisu/config.py index f28f5e5..4d49598 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -21,19 +21,20 @@ "options handler global entry point" import weakref from copy import copy, deepcopy +from typing import Optional, List, Any, Union from .error import PropertiesOptionError, ConfigError, ConflictError, \ - LeadershipError + LeadershipError, APIError from .option import SynDynOptionDescription, DynOptionDescription, Leadership, Option from .option.baseoption import BaseOption from .setting import OptionBag, ConfigBag, Settings, undefined, groups -from .value import Values +from .value import Values, owners from .i18n import _ from .cacheobj import Cache -class SubConfig: +class _SubConfig: """Sub configuration management entry. Tree if OptionDescription's responsability. SubConfig are generated on-demand. A Config is also a SubConfig. @@ -42,7 +43,7 @@ class SubConfig: __slots__ = ('_impl_context', '_impl_descr', '_impl_path', - '_impl_length') + ) def __init__(self, descr, @@ -67,37 +68,29 @@ class SubConfig: self._impl_descr = descr self._impl_context = context self._impl_path = subpath - if not descr.impl_is_leadership(): - return - leader = descr.get_leader() - leader_name = leader.impl_getname() - cconfig_bag = config_bag.copy() - cconfig_bag.remove_validation() - option_bag = OptionBag(leader, - None, - cconfig_bag, - ) - value = self.getattr(leader_name, - option_bag, - ) - self._impl_length = len(value) def get_length_leadership(self, option_bag, ): """Get the length of leader option (useful to know follower's length) """ - if not option_bag.option.impl_is_symlinkoption(): - return self._impl_length - true_path = option_bag.option.impl_getopt().impl_getpath() - subconfig, _ = self.get_context().get_home_by_path(true_path, - option_bag.config_bag, - ) - moption_bag = OptionBag(subconfig.get_description(), - None, - option_bag.config_bag, - ) - return subconfig.get_length_leadership(moption_bag) + if option_bag.option.impl_is_symlinkoption(): + root_option_bag = OptionBag(option_bag.config_bag.context.get_description(), + None, + config_bag, + ) + option_bag = self.get_sub_option_bag(root_option_bag, + option_bag.option.impl_getopt().impl_getpath(), + option_bag.index, + True, + )[-1] + cconfig_bag = option_bag.config_bag.copy() + cconfig_bag.remove_validation() + option_bag = OptionBag(option_bag.option.get_leader(), + None, + cconfig_bag, + ) + return len(self.get_value(option_bag)) def get_path(self): return self._impl_path @@ -116,18 +109,6 @@ class SubConfig: def get_values(self): return self.get_context()._impl_values - def get_subconfig(self, - option_bag: OptionBag, - validate_properties: bool=True, - ) -> 'SubConfig': - if validate_properties: - self.get_settings().validate_properties(option_bag) - return SubConfig(option_bag.option, - self._impl_context, - option_bag.config_bag, - option_bag.path, - ) - # ============================================================================= # CACHE def reset_cache(self, @@ -159,27 +140,25 @@ class SubConfig: if option_bag.path in resetted_opts: return resetted_opts.append(option_bag.path) - for woption in option_bag.option._get_dependencies(self.get_description()): + for woption in option_bag.option._get_dependencies(option_bag.option): option = woption() + soption_bag = OptionBag(option, + option_bag.index, + option_bag.config_bag, + properties=None, + ) if option.impl_is_dynoptiondescription(): - self._reset_cache_dyn_optiondescription(option, - option_bag, + self._reset_cache_dyn_optiondescription(soption_bag, resetted_opts, ) elif option.issubdyn(): # it's an option in dynoptiondescription, remove cache for all generated option - self._reset_cache_dyn_option(option, - option_bag, + self._reset_cache_dyn_option(soption_bag, resetted_opts, ) else: - doption_bag = OptionBag(option, - option_bag.index, - option_bag.config_bag, - properties=None - ) self.reset_one_option_cache(resetted_opts, - doption_bag, + soption_bag, ) del option option_bag.option.reset_cache(option_bag.path, @@ -188,37 +167,48 @@ class SubConfig: ) def _reset_cache_dyn_optiondescription(self, - dynoption, option_bag, resetted_opts, ): # reset cache for all chidren - for coption in self.get_description().get_children_recursively(None, - None, - option_bag.config_bag, - ): - subconfig, name = self.get_home_by_path(coption.impl_getpath(), - option_bag.config_bag, - validate_properties=False, - ) - coption_bag = OptionBag(coption, + path = option_bag.option.impl_getpath() + if '.' in path: + subpath = path.rsplit('.', 1)[0] + else: + subpath = '' + + for suffix in option_bag.option.get_suffixes(option_bag.config_bag): + path_suffix = option_bag.option.convert_suffix_to_path(suffix) + doption = option_bag.option.to_dynoption(subpath, + suffix, + option_bag.option, + ) + doption_bag = OptionBag(doption, option_bag.index, option_bag.config_bag, properties=None, ) - subconfig.reset_one_option_cache(resetted_opts, - coption_bag, - ) - self._reset_cache_dyn_option(dynoption, - option_bag, + for coption in doption.get_children_recursively(None, + None, + option_bag.config_bag, + ): + coption_bag = self.get_sub_option_bag(doption_bag, + coption.impl_getpath(), + None, + False, + )[-1] + self.reset_one_option_cache(resetted_opts, + coption_bag, + ) + self._reset_cache_dyn_option(option_bag, resetted_opts, ) def _reset_cache_dyn_option(self, - option, option_bag, resetted_opts, ): + option = option_bag.option if isinstance(option, (Option, Leadership)): dynoption = option.getsubdyn() if isinstance(option, Option): @@ -252,49 +242,16 @@ class SubConfig: # ============================================================================= # WALK - def get_home_by_path(self, - path: str, - config_bag: ConfigBag, - validate_properties=True, - ) -> ('Subconfig', str): - """Get the suboption for path and the name of the option - :returns: tuple (config, name)""" - if self._impl_path is None: - path = path.split('.') - else: - if not path.startswith(self._impl_path + '.'): - raise ConfigError(_('cannot use get_home_by_path with external option')) - path = path[len(self._impl_path) + 1:].split('.') - for step in path[:-1]: - option = self.get_description().get_child(step, - config_bag, - self.get_path(), - ) - if validate_properties: - properties = undefined - else: - properties = None - option_bag = OptionBag(option, - None, - config_bag, - properties=properties, - ) - self = self.get_subconfig(option_bag, - validate_properties, - ) - assert isinstance(self, SubConfig), _('unknown option {}').format(path[-1]) - return self, path[-1] - def find(self, + option_bag, bytype, byname, byvalue, - config_bag, - _subpath=None, raise_if_not_found=True, only_path=undefined, only_option=undefined, - with_option=False): + with_option=False, + ): """ convenience method for finding an option that lives only in the subtree @@ -303,8 +260,7 @@ class SubConfig: """ def _filter_by_value(soption_bag): try: - value = context.getattr(path, - soption_bag) + value = soption_bag.config_bag.context.get_value(soption_bag) except PropertiesOptionError: return False if isinstance(value, list): @@ -318,33 +274,26 @@ class SubConfig: yield only_option options = _fake_iter() else: - options = self.get_description().get_children_recursively(bytype, - byname, - config_bag) - context = self.get_context() + options = option_bag.option.get_children_recursively(bytype, + byname, + option_bag.config_bag, + ) for option in options: path = option.impl_getpath() - option_bag = OptionBag(option, - None, - config_bag, - ) - if byvalue is not undefined and not _filter_by_value(option_bag): + soption_bag = OptionBag(option, + None, + option_bag.config_bag, + ) + if byvalue is not undefined and not _filter_by_value(soption_bag): continue - elif config_bag.properties: + elif option_bag.config_bag.properties: #remove option with propertyerror, ... try: - if '.' in path: - subconfig, subpath = self.get_home_by_path(path, - config_bag, - ) - else: - subconfig = self - subpath = path - subconfig.get_description().get_child(subpath, - config_bag, - subconfig.get_path(), - ) - self.get_settings().validate_properties(option_bag) + self.get_sub_option_bag(option_bag, + path, + None, + True, + )[-1] except PropertiesOptionError: continue found = True @@ -353,7 +302,8 @@ class SubConfig: else: yield path, option self._find_return_results(found, - raise_if_not_found) + raise_if_not_found, + ) def _find_return_results(self, found, @@ -362,166 +312,157 @@ class SubConfig: raise AttributeError(_("no option found in config" " with these criteria")) - def make_dict(self, - config_bag, - flatten=False, - fullpath=False, - leader_to_list=False): + def _walk_valid_value(self, + option_bag, + types, + value=undefined, + ): + if value is undefined: + value = self.get_value(option_bag, + need_help=False, + ) + l_option_bag = option_bag.copy() + l_option_bag.config_bag = option_bag.config_bag.copy() + if 'mandatory' in types: + l_option_bag.config_bag.properties |= {'mandatory', 'empty'} + self.get_settings().validate_mandatory(value, + l_option_bag, + ) + return value + + def walk(self, + option_bag, + types=['option'], + group_type=None, + recursive=True, + walked=False, + ): + if option_bag.option.impl_is_optiondescription(): + # do not return root option + if walked: + if 'optiondescription' in types and (group_type is None or + option_bag.option.impl_get_group_type() == group_type): + yield option_bag + if not recursive: + # it's not recursive, so stop to walk + return + if not option_bag.option.impl_is_leadership(): + for opt in option_bag.option.get_children(option_bag.config_bag): + try: + yield from self.walk(self.get_sub_option_bag(option_bag, + opt.impl_getpath(), + None, + True, + )[-1], + types=types, + recursive=recursive, + group_type=group_type, + walked=True, + ) + except PropertiesOptionError as err: + if err.proptype in (['mandatory'], ['empty']): + raise err + elif 'option' in types or 'mandatory' in types: + # it's a leadership so walk to leader and followers + # followers has specific length + leader, *followers = option_bag.option.get_children(option_bag.config_bag) + leader_option_bag = self.get_sub_option_bag(option_bag, + leader.impl_getpath(), + None, + True, + )[-1] + followers_dict = {'leader': leader_option_bag} + values = self.get_value(leader_option_bag, + need_help=False, + ) + leadership_length = len(values) + try: + self._walk_valid_value(leader_option_bag, + types, + value=values, + ) + except PropertiesOptionError as err: + if err.proptype in (['mandatory'], ['empty']): + if 'mandatory' in types: + yield leader_option_bag + else: + raise err + for idx in range(leadership_length): + followers_dict[idx] = [] + for follower in followers: + follower_path = follower.impl_getpath() + try: + for f_follower_bag in self.walk(self.get_sub_option_bag(option_bag, + follower_path, + idx, + True, + leadership_length=leadership_length, + )[-1], + types=types, + recursive=recursive, + group_type=group_type, + walked=True, + ): + if 'mandatory' in types: + yield f_follower_bag + followers_dict[idx].append(f_follower_bag) + except PropertiesOptionError as err: + continue + if 'option' in types: + yield followers_dict +# pass + else: + if 'mandatory' in types and not option_bag.option.impl_is_symlinkoption(): + try: + self._walk_valid_value(option_bag, + types, + ) + except PropertiesOptionError as err: + if err.proptype in (['mandatory'], ['empty']): + yield option_bag + if 'option' in types: + yield option_bag + + def make_dict(self, option_bag): """exports the whole config into a `dict` :returns: dict of Option's name (or path) and values """ - pathsvalues = {} - self._make_dict(config_bag, - [], - flatten, - fullpath, - pathsvalues, - leader_to_list, - ) - return pathsvalues - - def _make_dict(self, - config_bag, - _currpath, - flatten, - fullpath, - pathsvalues, - leader_to_list): - for opt in self.get_description().get_children(config_bag): - if leader_to_list and opt.impl_is_optiondescription() and opt.impl_is_leadership(): - self._make_dict_leader(opt, - config_bag, - flatten, - fullpath, - leader_to_list, - pathsvalues, - _currpath, - ) + ret = {} + for data in self.walk(option_bag): + if isinstance(data, OptionBag): + option_bag = data + ret[option_bag.path] = self.get_value(option_bag, + need_help=False, + ) else: - soption_bag = OptionBag(opt, - None, - config_bag, - ) - try: - self._make_sub_dict(pathsvalues, - _currpath, - soption_bag, - flatten, - fullpath, - leader_to_list) - except PropertiesOptionError as err: - if err.proptype in (['mandatory'], ['empty']): - raise err - continue + leader_ret = [] + leader_path = data['leader'].path + for idx, value in enumerate(self.get_value(data['leader'], + need_help=False, + )): + leader_dict = {leader_path: value} + for follower in data.get(idx, []): + leader_dict[follower.path] = self.get_value(follower, + need_help=False, + ) + leader_ret.append(leader_dict) + ret[leader_path] = leader_ret - def _make_sub_dict(self, - pathsvalues, - _currpath, - option_bag, - flatten, - fullpath, - leader_to_list): - option = option_bag.option - name = option.impl_getname() - if option.impl_is_optiondescription(): - self.get_settings().validate_properties(option_bag, - need_help=False) - subconfig = SubConfig(option_bag.option, - self._impl_context, - option_bag.config_bag, - option_bag.path) - subconfig._make_dict(option_bag.config_bag, - _currpath + [name], - flatten, - fullpath, - pathsvalues, - leader_to_list) - else: - ret = self.getattr(name, - option_bag, - need_help=False) - if flatten: - name_ = option.impl_getname() - elif fullpath: - name_ = option.impl_getpath() - else: - name_ = '.'.join(_currpath + [name]) - pathsvalues[name_] = ret - - def _make_dict_leader(self, - opt, - config_bag, - flatten, - fullpath, - leader_to_list, - pathsvalues, - _currpath, - ): - # leader - try: - loption_bag = OptionBag(opt, - None, - config_bag, - ) - self.get_settings().validate_properties(loption_bag, - need_help=False, - ) - except PropertiesOptionError as err: - return - children = opt.get_children(config_bag) - leader = children[0] - loption_bag = OptionBag(leader, - None, - config_bag, - ) - leader_pathsvalues = {} - leader_currpath = _currpath + [opt.impl_getname()] - self._make_sub_dict(leader_pathsvalues, - leader_currpath, - loption_bag, - flatten, - fullpath, - leader_to_list) - if not leader_pathsvalues: # pragma: no cover - return - leader_name = list(leader_pathsvalues.keys())[0] - pathsvalues[leader_name] = [] - subconfig = SubConfig(opt, - self._impl_context, - config_bag, - opt.impl_getpath()) - for idx, value in enumerate(leader_pathsvalues[leader_name]): - leadership_pathsvalues = {leader_name: value} - for follower_opt in children[1:]: - foption_bag = OptionBag(follower_opt, - idx, - config_bag, - ) - try: - subconfig._make_sub_dict(leadership_pathsvalues, - leader_currpath, - foption_bag, - flatten, - fullpath, - leader_to_list) - except PropertiesOptionError as err: - continue - pathsvalues[leader_name].append(leadership_pathsvalues) + return ret # ============================================================================= # Manage value - def setattr(self, - value, - option_bag): + def set_value(self, + option_bag: OptionBag, + value: Any, + ): if option_bag.option.impl_is_symlinkoption(): raise ConfigError(_("can't set value to a SymLinkOption")) context = option_bag.config_bag.context context.get_settings().validate_properties(option_bag) - if option_bag.option.impl_is_leader() and len(value) < self._impl_length: - raise LeadershipError(_('cannot reduce length of the leader "{}"' - '').format(option_bag.option.impl_get_display_name())) - return context.get_values().setvalue(value, - option_bag) + return context.get_values().set_value(option_bag, + value, + ) def delattr(self, option_bag): @@ -534,23 +475,42 @@ class SubConfig: else: values.reset(option_bag) - def getattr(self, - name, - option_bag, - from_follower=False, - needs_re_verify_follower_properties=False, - need_help=True, - ): + def get_value(self, + option_bag, + parent_option_bag=None, + need_help=True, + ): """ :return: option's value if name is an option name, OptionDescription otherwise """ - config_bag = option_bag.config_bag - if '.' in name: - self, name = self.get_home_by_path(name, - config_bag, - ) + option_bag = self._get(option_bag, parent_option_bag, need_help) + if isinstance(option_bag, list): + value = [] + for opt_bag in option_bag: + value.append(self.get_value(opt_bag, + need_help=need_help, + )) + else: + value = self.get_values().get_cached_value(option_bag) + if parent_option_bag and option_bag.option.impl_is_follower() : + length = self.get_length_leadership(parent_option_bag) + follower_len = self.get_values().get_max_length(option_bag.path) + if follower_len > length: + option_name = option_bag.option.impl_get_display_name() + raise LeadershipError(_(f'the follower option "{option_name}" ' + f'has greater length ({follower_len}) than the leader ' + f'length ({length})')) + self.get_settings().validate_mandatory(value, + option_bag, + ) + return value + def _get(self, + option_bag, + parent_option_bag, + need_help, + ): option = option_bag.option if option.impl_is_symlinkoption(): suboption = option.impl_getopt() @@ -571,61 +531,65 @@ class SubConfig: option_bag.config_bag, ori_option=option ) - context = self.get_context() - ret.append(context.getattr(doption_bag.path, - doption_bag, - )), + ret.append(doption_bag) return ret + if suboption.impl_is_follower(): + options_bag = self.get_sub_option_bag(option_bag.config_bag, + suboption.impl_getpath(), + None, + True, + ) + leadership_length = self.get_length_leadership(options_bag[-2]) + ret = [] + for idx in range(leadership_length): + f_option_bag = OptionBag(suboption, + idx, + option_bag.config_bag, + ) + ret.append(f_option_bag) + return ret + soption_bag = OptionBag(suboption, option_bag.index, - config_bag, + option_bag.config_bag, ori_option=option, ) - context = self.get_context() - return context.getattr(soption_bag.path, - soption_bag, - ) + return self._get(soption_bag, None, need_help) + return option_bag - needs = needs_re_verify_follower_properties - if option.impl_is_follower() and not from_follower: - needs = self.get_settings().has_properties_index(option_bag) - if not option.impl_is_follower() or \ - (needs and option_bag.index is not None) or \ - (not needs and (not from_follower or option_bag.index is None)): - self.get_settings().validate_properties(option_bag, - need_help=need_help) - - if option.impl_is_follower() and not from_follower: - length = self.get_length_leadership(option_bag) - follower_len = self.get_values().get_max_length(option_bag.path) - if follower_len > length: - raise LeadershipError(_(f'the follower option "{option.impl_get_display_name()}" ' - 'has greater length ({follower_len}) than the leader ' - 'length ({length})')) - - if option.impl_is_follower() and option_bag.index is None: - value = [] - for idx in range(length): - try: - soption_bag = OptionBag(option, - idx, - config_bag, - ) - value.append(self.getattr(name, - soption_bag, - from_follower=True, - needs_re_verify_follower_properties=needs, - )) - except PropertiesOptionError as err: - value.append(err) + def get_owner(self, + option_bag: OptionBag, + parent_option_bag=None, + ): + options_bag = self._get(option_bag, parent_option_bag, need_help=True) + if isinstance(options_bag, list): + if not option_bag.option.impl_is_symlinkoption(): + owner = [] + for opt_bag in options_bag: + owner.append(self.get_owner(opt_bag)) + else: + for opt_bag in options_bag: + owner = self.get_owner(opt_bag) + if owner != owners.default: + break + else: + owner = owners.default else: - value = self.get_values().get_cached_value(option_bag) - self.get_settings().validate_mandatory(value, - option_bag) - return value + owner = self.get_values().getowner(options_bag) + return owner + + def pop_leader(self, + option_bag: OptionBag, + leadership_option_bag: OptionBag, + index: int, + ): + self.get_values().reset_leadership(option_bag, + leadership_option_bag, + index, + ) -class _CommonConfig(SubConfig): +class _CommonConfig(_SubConfig): "abstract base class for the Config, KernelGroupConfig and the KernelMetaConfig" __slots__ = ('_impl_values', '_impl_values_cache', @@ -781,6 +745,75 @@ class _CommonConfig(SubConfig): path = parent().get_config_path() + '.' + path return path + def get_sub_option_bag(self, + bag: Union[OptionBag, ConfigBag], + path: str, + index: Optional[int], + validate_properties: bool, + leadership_length: int=None, + properties=undefined, + ) -> List[OptionBag]: + """Get the suboption for path and the name of the option + :returns: tuple (config, name)""" + if isinstance(bag, ConfigBag): + option_bag = OptionBag(self.get_description(), + None, + bag, + ) + else: + option_bag = bag + if option_bag.option != option_bag.config_bag.context.get_description(): + if not path.startswith(option_bag.path + '.'): + raise ConfigError('cannot get sub option if not a parent') + path = path[len(option_bag.path) + 1:] + path = path.split('.') + last_idx = len(path) - 1 + suboption = option_bag.option + options_bag = [] + sub_option_bag = option_bag + for idx, step in enumerate(path): + if not suboption.impl_is_optiondescription(): + raise TypeError(f'{suboption.impl_getpath()} is not an optiondescription') + + if not idx and option_bag.option == self.get_description(): + subpath = None + else: + subpath = suboption.impl_getpath() + option = suboption.get_child(step, + option_bag.config_bag, + subpath, + ) + if idx == last_idx: + option_index = index + else: + option_index = None + if idx == last_idx: + if option_index is not None: + if option.impl_is_optiondescription() or option.impl_is_symlinkoption() or not option.impl_is_follower(): + raise APIError('index must be set only with a follower option') + if leadership_length is not None: + length = leadership_length + else: + length = self.get_length_leadership(sub_option_bag) + if index >= length: + raise LeadershipError(_('index "{}" is greater than the leadership length "{}" ' + 'for option "{}"').format(index, + length, + option.impl_get_display_name())) + option_properties = properties + else: + option_properties = undefined + sub_option_bag = OptionBag(option, + option_index, + option_bag.config_bag, + properties=option_properties, + ) + if validate_properties: + self.get_settings().validate_properties(sub_option_bag) + suboption = option + options_bag.append(sub_option_bag) + return options_bag + def impl_getname(self): return self._impl_name @@ -908,22 +941,21 @@ class KernelGroupConfig(_CommonConfig): ) def set_value(self, - path, + option_bag, value, - config_bag, only_config=False, ): """Setattr not in current KernelGroupConfig, but in each children """ ret = [] for child in self._impl_children: - cconfig_bag = config_bag.copy() + cconfig_bag = option_bag.config_bag.copy() cconfig_bag.context = child if isinstance(child, KernelGroupConfig): - ret.extend(child.set_value(path, + ret.extend(child.set_value(option_bag, value, - cconfig_bag, - only_config=only_config)) + only_config=only_config, + )) else: settings = child.get_settings() properties = settings.get_context_properties(child.properties_cache) @@ -931,20 +963,14 @@ class KernelGroupConfig(_CommonConfig): cconfig_bag.properties = properties cconfig_bag.permissives = permissives try: - subconfig, name = child.get_home_by_path(path, - cconfig_bag, - ) - option = subconfig.get_description().get_child(name, - cconfig_bag, - child.get_path(), - ) - option_bag = OptionBag(option, - None, - cconfig_bag, - ) - child.setattr(value, - option_bag, - ) + coption_bag = child.get_sub_option_bag(cconfig_bag, + option_bag.path, + option_bag.index, + False, + )[-1] + child.set_value(coption_bag, + value, + ) except PropertiesOptionError as err: ret.append(PropertiesOptionError(err._option_bag, err.proptype, @@ -964,18 +990,22 @@ class KernelGroupConfig(_CommonConfig): byoption=undefined, byvalue=undefined, raise_if_not_found=True, - _sub=False): + _sub=False, + ): """Find first not in current KernelGroupConfig, but in each children """ # if KernelMetaConfig, all children have same OptionDescription in # context so search only one time the option for all children if bypath is undefined and byname is not None and \ - isinstance(self, - KernelMixConfig): - for bypath, byoption in self.find(bytype=None, + self.impl_type == 'meta': + root_option_bag = OptionBag(self.get_description(), + None, + config_bag, + ) + for bypath, byoption in self.find(root_option_bag, + bytype=None, byname=byname, byvalue=undefined, - config_bag=config_bag, raise_if_not_found=raise_if_not_found, with_option=True, ): @@ -995,18 +1025,24 @@ class KernelGroupConfig(_CommonConfig): else: cconfig_bag = config_bag.copy() cconfig_bag.context = child - settings = child.get_settings() - properties = settings.get_context_properties(child.properties_cache) - permissives = settings.get_context_permissives() - cconfig_bag.properties = properties - cconfig_bag.permissives = permissives - for path in child.find(None, + if cconfig_bag.properties is None: + settings = child.get_settings() + properties = settings.get_context_properties(child.properties_cache) + permissives = settings.get_context_permissives() + cconfig_bag.properties = properties + cconfig_bag.permissives = permissives + root_option_bag = OptionBag(child.get_description(), + None, + cconfig_bag, + ) + for path in child.find(root_option_bag, + None, byname, byvalue, - config_bag=cconfig_bag, raise_if_not_found=False, only_path=bypath, - only_option=byoption): + only_option=byoption, + ): ret.append(child) break if not _sub: @@ -1015,28 +1051,24 @@ class KernelGroupConfig(_CommonConfig): return ret def reset(self, - path, + path: str, + config_bag: ConfigBag, ): for child in self._impl_children: + settings = child.get_settings() + cconfig_bag = config_bag.copy() + cconfig_bag.context = child settings = child.get_settings() properties = settings.get_context_properties(child.properties_cache) permissives = settings.get_context_permissives() - config_bag = ConfigBag(child, - properties=properties, - permissives=permissives) - config_bag.remove_validation() - subconfig, name = child.get_home_by_path(path, - config_bag, - ) - option = subconfig.get_description().get_child(name, - config_bag, - subconfig.get_path(), - ) - config_bag.context = child - option_bag = OptionBag(option, - None, - config_bag, - ) + cconfig_bag.properties = properties + cconfig_bag.permissives = permissives + cconfig_bag.remove_validation() + option_bag = child.get_sub_option_bag(cconfig_bag, + path, + None, + False, + )[-1] child.get_values().reset(option_bag) def getconfig(self, @@ -1082,9 +1114,8 @@ class KernelMixConfig(KernelGroupConfig): ) def set_value(self, - path, + option_bag, value, - config_bag, only_config=False, force_default=False, force_dont_change_value=False, @@ -1093,92 +1124,75 @@ class KernelMixConfig(KernelGroupConfig): """only_config: could be set if you want modify value in all Config included in this KernelMetaConfig """ + ret = [] if only_config: if force_default or force_default_if_same or force_dont_change_value: raise ValueError(_('force_default, force_default_if_same or ' 'force_dont_change_value cannot be set with' ' only_config')) - return super().set_value(path, - value, - config_bag, - only_config=only_config) - ret = [] - subconfig, name = self.get_home_by_path(path, - config_bag, - ) - option = subconfig.get_description().get_child(name, - config_bag, - self.get_path()) - option_bag = OptionBag(option, - None, - config_bag, - ) - if force_default or force_default_if_same or force_dont_change_value: - if force_default and force_dont_change_value: - raise ValueError(_('force_default and force_dont_change_value' - ' cannot be set together')) - for child in self._impl_children: - cconfig_bag = config_bag.copy() - cconfig_bag.context = child - settings = child.get_settings() - properties = settings.get_context_properties(child.properties_cache) - cconfig_bag.properties = properties - cconfig_bag.permissives = settings.get_context_permissives() - try: - subconfig2, name = child.get_home_by_path(path, - cconfig_bag, - ) - if self.impl_type == 'meta': - moption_bag = option_bag.copy() - del moption_bag.permissives - moption_bag.config_bag = cconfig_bag - moption_bag.properties = settings.getproperties(moption_bag) - else: - option = subconfig2.get_description().get_child(name, - cconfig_bag, - None, - ) - moption_bag = OptionBag(option, - None, - cconfig_bag, - ) - if force_default_if_same: - if not child.get_values().hasvalue(path): - child_value = undefined + else: + if force_default or force_default_if_same or force_dont_change_value: + if force_default and force_dont_change_value: + raise ValueError(_('force_default and force_dont_change_value' + ' cannot be set together')) + for child in self._impl_children: + cconfig_bag = option_bag.config_bag.copy() + cconfig_bag.context = child + settings = child.get_settings() + properties = settings.get_context_properties(child.properties_cache) + cconfig_bag.properties = properties + cconfig_bag.permissives = settings.get_context_permissives() + try: + if self.impl_type == 'meta': + obj = self else: - child_value = subconfig2.getattr(name, - moption_bag, - ) - if force_default or (force_default_if_same and value == child_value): - child.get_values().reset(moption_bag) - continue - if force_dont_change_value: - child_value = child.getattr(name, - moption_bag) - if value != child_value: - subconfig2.setattr(child_value, - moption_bag) - except PropertiesOptionError as err: - ret.append(PropertiesOptionError(err._option_bag, - err.proptype, - err._settings, - err._opt_type, - err._name, - err._orig_opt)) - except (ValueError, LeadershipError, AttributeError) as err: - ret.append(err) + obj = child + moption_bag = obj.get_sub_option_bag(cconfig_bag, + option_bag.path, + option_bag.index, + not force_default and not force_default_if_same, + )[-1] + if force_default_if_same: + if not child.get_values().hasvalue(option_bag.path): + child_value = undefined + else: + child_value = child.get_value(moption_bag) + if force_default or (force_default_if_same and value == child_value): + child.get_values().reset(moption_bag) + continue + if force_dont_change_value: + child_value = child.get_value(moption_bag) + if value != child_value: + child.set_value(moption_bag, + child_value, + ) + except PropertiesOptionError as err: + ret.append(PropertiesOptionError(err._option_bag, + err.proptype, + err._settings, + err._opt_type, + err._name, + err._orig_opt, + )) + except (ValueError, LeadershipError, AttributeError) as err: + ret.append(err) try: - if self.impl_type == 'meta': - moption_bag = option_bag.copy() - moption_bag.config_bag = config_bag - properties = config_bag.context.get_settings().getproperties(moption_bag) - moption_bag.properties = properties + moption_bag = self.get_sub_option_bag(option_bag.config_bag, + option_bag.path, + option_bag.index, + not only_config, + )[-1] + if only_config: + ret = super().set_value(moption_bag, + value, + only_config=only_config, + ) else: - moption_bag = option_bag - subconfig.setattr(value, - moption_bag, - ) + _CommonConfig.set_value(self, + moption_bag, + value, + ) except (PropertiesOptionError, ValueError, LeadershipError) as err: ret.append(err) return ret @@ -1191,30 +1205,18 @@ class KernelMixConfig(KernelGroupConfig): rconfig_bag = config_bag.copy() rconfig_bag.remove_validation() if self.impl_type == 'meta': - subconfig, name = self.get_home_by_path(path, - config_bag, - ) - option = subconfig.get_description().get_child(name, - config_bag, - subconfig.get_path(), - ) - option_bag = OptionBag(option, - None, - rconfig_bag, - ) + option_bag = self.get_sub_option_bag(config_bag, + path, + None, + True, + )[-1] elif not only_children: try: - subconfig, name = self.get_home_by_path(path, - config_bag, - ) - option = subconfig.get_description().get_child(name, - config_bag, - subconfig.get_path(), - ) - option_bag = OptionBag(option, - None, - rconfig_bag, - ) + option_bag = self.get_sub_option_bag(rconfig_bag, + path, + None, + True, + )[-1] except AttributeError: only_children = True for child in self._impl_children: @@ -1224,17 +1226,11 @@ class KernelMixConfig(KernelGroupConfig): moption_bag = option_bag moption_bag.config_bag = rconfig_bag else: - subconfig, name = child.get_home_by_path(path, - rconfig_bag, - ) - option = subconfig.get_description().get_child(name, - rconfig_bag, - child.get_path(), - ) - moption_bag = OptionBag(option, - None, - rconfig_bag, - ) + moption_bag = child.get_sub_option_bag(rconfig_bag, + path, + None, + True, + )[-1] child.get_values().reset(moption_bag) except AttributeError: pass diff --git a/tiramisu/option/leadership.py b/tiramisu/option/leadership.py index b576775..0364985 100644 --- a/tiramisu/option/leadership.py +++ b/tiramisu/option/leadership.py @@ -166,10 +166,11 @@ class Leadership(OptionDescription): ) def pop(self, - values: Values, - index: int, - option_bag: OptionBag, - followers: Optional[List[Option]]=undefined) -> None: + values: Values, + index: int, + option_bag: OptionBag, + followers: Optional[List[Option]]=undefined, + ) -> None: if followers is undefined: # followers are not undefined only in SynDynLeadership followers = self.get_followers() @@ -202,19 +203,22 @@ class Leadership(OptionDescription): def reset_cache(self, path: str, config_bag: 'ConfigBag', - resetted_opts: List[Option]) -> None: + resetted_opts: List[Option], + ) -> None: self._reset_cache(path, self.get_leader(), self.get_followers(), config_bag, - resetted_opts) + resetted_opts, + ) def _reset_cache(self, path: str, leader: Option, followers: List[Option], config_bag: 'ConfigBag', - resetted_opts: List[Option]) -> None: + resetted_opts: List[Option], + ) -> None: super().reset_cache(path, config_bag, resetted_opts) diff --git a/tiramisu/option/syndynoption.py b/tiramisu/option/syndynoption.py index 37d4e94..8f1fbc2 100644 --- a/tiramisu/option/syndynoption.py +++ b/tiramisu/option/syndynoption.py @@ -46,7 +46,8 @@ class SynDynOption: def __getattr__(self, name: str) -> Any: return getattr(self.opt, - name) + name, + ) def __eq__(self, left: BaseOption) -> bool: @@ -68,7 +69,10 @@ class SynDynOption: return self.suffix def impl_getpath(self) -> str: - return self.rootpath + '.' + self.impl_getname() + path = self.impl_getname() + if self.rootpath: + path = f'{self.rootpath}.{path}' + return path def impl_is_dynsymlinkoption(self) -> bool: return True diff --git a/tiramisu/option/syndynoptiondescription.py b/tiramisu/option/syndynoptiondescription.py index 839585e..f7cd316 100644 --- a/tiramisu/option/syndynoptiondescription.py +++ b/tiramisu/option/syndynoptiondescription.py @@ -40,9 +40,6 @@ class SynDynOptionDescription: suffix: str, ori_dyn) -> None: self.opt = opt - if rootpath is None: - rootpath = '' - assert isinstance(rootpath, str), 'rootpath must be a string, not {}'.format(type(rootpath)) self.rootpath = rootpath self._suffix = suffix # For a Leadership inside a DynOptionDescription @@ -60,9 +57,10 @@ class SynDynOptionDescription: return self.opt def get_child(self, - name: str, - config_bag: ConfigBag, - subpath: str) -> BaseOption: + name: str, + config_bag: ConfigBag, + subpath: str, + ) -> BaseOption: suffix = self.ori_dyn.convert_suffix_to_path(self._suffix) if name.endswith(suffix): oname = name[:-len(suffix)] @@ -86,9 +84,9 @@ class SynDynOptionDescription: return True def get_children(self, - config_bag: ConfigBag, - dyn: bool=True, - ): + config_bag: ConfigBag, + dyn: bool=True, + ): subpath = self.impl_getpath() children = [] for child in self.opt.get_children(config_bag): @@ -102,21 +100,23 @@ class SynDynOptionDescription: return True def get_children_recursively(self, - bytype: Optional[BaseOption], - byname: Optional[str], - config_bag: ConfigBag, - self_opt: BaseOption=None) -> BaseOption: + bytype: Optional[BaseOption], + byname: Optional[str], + config_bag: ConfigBag, + self_opt: BaseOption=None, + ) -> BaseOption: for option in self.opt.get_children_recursively(bytype, - byname, - config_bag, - self): + byname, + config_bag, + self, + ): yield option def impl_getpath(self) -> str: - rootpath = self.rootpath - if rootpath != '': - rootpath += '.' - return rootpath + self.impl_getname() + path = self.impl_getname() + if self.rootpath: + path = f'{self.rootpath}.{path}' + return path def impl_get_display_name(self) -> str: return self.opt.impl_get_display_name() + str(self._suffix) @@ -126,44 +126,52 @@ class SynDynLeadership(SynDynOptionDescription): def get_leader(self) -> SynDynOption: return self.opt.get_leader().to_dynoption(self.impl_getpath(), self._suffix, - self.ori_dyn) + self.ori_dyn, + ) def get_followers(self) -> Iterator[SynDynOption]: subpath = self.impl_getpath() for follower in self.opt.get_followers(): yield follower.to_dynoption(subpath, self._suffix, - self.ori_dyn) + self.ori_dyn, + ) def reset_cache(self, path: str, config_bag: 'ConfigBag', - resetted_opts: List[str]) -> None: + resetted_opts: List[str], + ) -> None: leader = self.get_leader() followers = self.get_followers() self._reset_cache(path, leader, followers, config_bag, - resetted_opts) + resetted_opts, + ) def pop(self, - *args, - **kwargs) -> None: + *args, + **kwargs, + ) -> None: self.opt.pop(*args, - followers=self.get_followers(), - **kwargs) + followers=self.get_followers(), + **kwargs, + ) def follower_force_store_value(self, - values, - value, - option_bag, - owner) -> None: + values, + value, + option_bag, + owner, + ) -> None: self.opt.follower_force_store_value(values, - value, - option_bag, - owner, - dyn=self) + value, + option_bag, + owner, + dyn=self, + ) def impl_getsuffix(self) -> str: return self._suffix diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 868ad0c..e5fd0f1 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # ____________________________________________________________ +from typing import Union from itertools import chain from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list from .i18n import _ @@ -186,7 +187,9 @@ class OptionBag: self.path = path elif option: self.path = option.impl_getpath() - if properties is undefined: + if '.' not in self.path and option == config_bag.context.get_description(): + self.properties = None + elif properties is undefined: self.properties = config_bag.context.get_settings().getproperties(self, apply_requires=apply_requires) if properties is not undefined: self.properties = properties @@ -196,7 +199,7 @@ class OptionBag: return self.option elif key == 'apply_requires': return True - raise KeyError('unknown key "{}" for OptionBag'.format(key)) # pragma: no cover + return undefined def __delattr__(self, key): if key in ['properties', 'permissives']: @@ -208,10 +211,14 @@ class OptionBag: raise KeyError(_('cannot delete key "{}" for OptionBag').format(key)) # pragma: no cover def copy(self): - option_bag = OptionBag(None, None, None) + option_bag = OptionBag(None, + None, + None, + ) for key in self.__slots__: - if hasattr(self, key): - setattr(option_bag, key, getattr(self, key)) + if not hasattr(self, key): + continue + setattr(option_bag, key, getattr(self, key)) return option_bag @@ -573,10 +580,8 @@ class Settings(object): context.reset_cache(None) def setproperties(self, - path, - properties, option_bag, - context, + properties, ): """save properties for specified path (never save properties if same has option properties) @@ -597,9 +602,9 @@ class Settings(object): raise LeadershipError(_('a leader ({0}) cannot have ' '"force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"' '').format(opt.impl_get_display_name())) - self._properties.setdefault(path, {})[option_bag.index] = properties + self._properties.setdefault(option_bag.path, {})[option_bag.index] = properties # values too because of follower values could have a PropertiesOptionError has value - context.reset_cache(option_bag) + option_bag.config_bag.context.reset_cache(option_bag) option_bag.properties = properties def set_context_permissives(self, @@ -644,40 +649,44 @@ class Settings(object): #____________________________________________________________ # reset methods - - def reset(self, - option_bag, - config_bag, - ): - if option_bag is None: - opt = None + def _get_path_index_config_option(self, + bag: Union[OptionBag, ConfigBag], + msg: str, + ): + if isinstance(bag, ConfigBag): path = None index = None + config_bag = bag + option_bag = None else: - opt = option_bag.option - assert not opt.impl_is_symlinkoption(), _("can't reset properties to " - "the symlinkoption \"{}\"" - "").format(opt.impl_get_display_name()) - path = option_bag.path - index = option_bag.index + assert not bag.option.impl_is_symlinkoption(), \ + _(msg).format(bag.option.impl_get_display_name()) + path = bag.path + index = bag.index + config_bag = bag.config_bag + option_bag = bag + return path, index, config_bag, option_bag + + def reset(self, + bag: Union[OptionBag, ConfigBag], + ): + path, index, config_bag, option_bag = \ + self._get_path_index_config_option(bag, + "can't reset properties to " + "the symlinkoption \"{}\"", + ) if path in self._properties and index in self._properties[path]: del(self._properties[path][index]) config_bag.context.reset_cache(option_bag) def reset_permissives(self, - option_bag, - config_bag): - if option_bag is None: - opt = None - path = None - index = None - else: - opt = option_bag.option - assert not opt.impl_is_symlinkoption(), _("can't reset permissives to " - "the symlinkoption \"{}\"" - "").format(opt.impl_get_display_name()) - index = option_bag.index - path = option_bag.path + bag: Union[OptionBag, ConfigBag], + ): + path, index, config_bag, option_bag = \ + self._get_path_index_config_option(bag, + "can't reset permissives to " + "the symlinkoption \"{}\"", + ) if path in self._permissives and index in self._permissives[path]: del(self._permissives[path][index]) config_bag.context.reset_cache(option_bag) @@ -742,7 +751,8 @@ class Settings(object): def validate_mandatory(self, value, - option_bag): + option_bag, + ): if 'mandatory' in option_bag.config_bag.properties: values = option_bag.config_bag.context.get_values() if option_bag.option.impl_is_follower(): @@ -758,14 +768,17 @@ class Settings(object): ): raise PropertiesOptionError(option_bag, ['mandatory'], - self) + self, + ) if 'empty' in option_bag.properties and values.isempty(option_bag.option, value, force_allow_empty_list=True, - index=option_bag.index): + index=option_bag.index, + ): raise PropertiesOptionError(option_bag, ['empty'], - self) + self, + ) def validate_frozen(self, option_bag): diff --git a/tiramisu/todict.py b/tiramisu/todict.py index 198dec6..1dcebf3 100644 --- a/tiramisu/todict.py +++ b/tiramisu/todict.py @@ -152,10 +152,11 @@ class Requires(object): self.tiramisu_web.set_remotable(leader.option.path(), form, leader) def manage_requires(self, - childapi, - path, - form, - current_action): + childapi, + path, + form, + current_action, + ): for requires in childapi.option.properties(uncalculated=True): if not isinstance(requires, str): option = requires.params.kwargs['condition'].option @@ -365,14 +366,15 @@ class TiramisuDict: form.setdefault(leader.option.path(), {})['remote'] = True def walk(self, - root, - subchildapi, - schema, - model, - form, - order, - updates_status, - init=False): + root, + subchildapi, + schema, + model, + form, + order, + updates_status, + init=False, + ): error = None if init: if form is not None: @@ -398,22 +400,26 @@ class TiramisuDict: props_no_requires = set(childapi.option.properties()) if form is not None: self.requires.add(path, - childapi, - form) + childapi, + form, + ) self.consistencies.add(path, - childapi, - form) + childapi, + form, + ) self.callbacks.add(path, - childapi, - schema, - 'force_store_value' in props_no_requires) + childapi, + schema, + 'force_store_value' in props_no_requires, + ) childapi_option = childapi.option if model is not None and childapi.option.isoptiondescription() or not childapi_option.issymlinkoption(): self.gen_model(model, - childapi, - path, - leader_len, - updates_status) + childapi, + path, + leader_len, + updates_status, + ) if order is not None: order.append(path) if childapi.option.isoptiondescription(): @@ -429,12 +435,13 @@ class TiramisuDict: else: subschema = schema self.walk(path, - childapi, - subschema, - model, - form, - order, - updates_status) + childapi, + subschema, + model, + form, + order, + updates_status, + ) else: child = childapi_option.get() childtype = child.__class__.__name__ @@ -461,22 +468,24 @@ class TiramisuDict: if schema is not None: self.gen_schema(schema, - childapi, - childapi_option, - path, - props_no_requires, - value, - defaultmulti, - is_multi, - web_type, - form) + childapi, + childapi_option, + path, + props_no_requires, + value, + defaultmulti, + is_multi, + web_type, + form, + ) if form is not None: self.gen_form(form, - web_type, - path, - child, - childapi_option, - childtype) + web_type, + path, + child, + childapi_option, + childtype, + ) if schema is not None: if web_type != 'symlink': schema[path]['title'] = childapi_option.description() @@ -502,16 +511,17 @@ class TiramisuDict: def gen_schema(self, - schema, - childapi, - childapi_option, - path, - props_no_requires, - value, - defaultmulti, - is_multi, - web_type, - form): + schema, + childapi, + childapi_option, + path, + props_no_requires, + value, + defaultmulti, + is_multi, + web_type, + form, + ): schema[path] = {'type': web_type} if childapi_option.issymlinkoption(): sym_option = childapi_option.get() @@ -545,10 +555,11 @@ class TiramisuDict: def get_enum(self, - childapi, - is_multi, - path, - props_no_requires): + childapi, + is_multi, + path, + props_no_requires, + ): values = childapi.value.list() empty_is_required = not childapi.option.isfollower() and is_multi if '' not in values and ((empty_is_required and not 'empty' in props_no_requires) or \ @@ -557,12 +568,13 @@ class TiramisuDict: return values def gen_form(self, - form, - web_type, - path, - child, - childapi_option, - childtype): + form, + web_type, + path, + child, + childapi_option, + childtype, + ): obj_form = {} if path in form: obj_form.update(form[path]) @@ -601,13 +613,14 @@ class TiramisuDict: form[path] = obj_form def calc_raises_properties(self, - obj, - childapi): - old_properties = childapi._option_bag.config_bag.properties - config = childapi._option_bag.config_bag.context + obj, + childapi, + ): + old_properties = childapi._config_bag.properties + config = childapi._config_bag.context settings = config.get_settings() - childapi._option_bag.config_bag.properties = self.config.property.get(default=True) # settings.get_context_properties(config._impl_properties_cache) - childapi._option_bag.config_bag.properties -= {'permissive'} + childapi._config_bag.properties = self.config.property.get(default=True) # settings.get_context_properties(config._impl_properties_cache) + childapi._config_bag.properties -= {'permissive'} properties = childapi.property.get(only_raises=True, uncalculated=True) properties -= childapi.permissive.get() @@ -618,12 +631,13 @@ class TiramisuDict: properties -= self.config.permissive.get() if properties: obj['hidden'] = True - childapi._option_bag.config_bag.properties = old_properties + childapi._config_bag.properties = old_properties def _gen_model_properties(self, - childapi, - path, - index): + childapi, + path, + index, + ): isfollower = childapi.option.isfollower() props = set(childapi.property.get()) obj = self.gen_properties(props, @@ -667,11 +681,12 @@ class TiramisuDict: return obj def gen_model(self, - model, - childapi, - path, - leader_len, - updates_status): + model, + childapi, + path, + leader_len, + updates_status, + ): if childapi.option.isoptiondescription(): props = set(childapi.property.get()) obj = {} @@ -686,27 +701,31 @@ class TiramisuDict: pass else: obj = self._gen_model_properties(childapi, - path, - None) + path, + None, + ) if childapi.option.isfollower(): for index in range(leader_len): follower_childapi = self.config.unrestraint.option(path, index) sobj = self._gen_model_properties(follower_childapi, - path, - index) + path, + index, + ) self._get_model_value(follower_childapi, - path, - sobj, - index, - updates_status) + path, + sobj, + index, + updates_status, + ) if sobj: model.setdefault(path, {})[str(index)] = sobj else: self._get_model_value(childapi, - path, - obj, - None, - updates_status) + path, + obj, + None, + updates_status, + ) if obj: if not childapi.option.isoptiondescription() and childapi.option.isfollower(): model.setdefault(path, {})['null'] = obj @@ -714,11 +733,12 @@ class TiramisuDict: model[path] = obj def _get_model_value(self, - childapi, - path, - obj, - index, - updates_status): + childapi, + path, + obj, + index, + updates_status, + ): if path in updates_status and index in updates_status[path]: value = childapi.value.get() self._get_value_with_exception(obj, @@ -835,9 +855,10 @@ class TiramisuDict: childapi.value.set(multi) def apply_updates(self, - oripath, - updates, - model_ori): + oripath, + updates, + model_ori, + ): updates_status = {} for update in updates: path = update['name'] @@ -852,13 +873,15 @@ class TiramisuDict: try: if update['action'] == 'modify': self.mod_value(childapi, - path, - index, - update.get('value', undefined)) + path, + index, + update.get('value', undefined), + ) elif update['action'] == 'delete': self.del_value(childapi, - path, - index) + path, + index, + ) elif update['action'] == 'add': if childapi_option.ismulti(): self.add_value(childapi, path, update['value']) @@ -873,19 +896,22 @@ class TiramisuDict: return updates_status def set_updates(self, - body): + body, + ): root_path = self.root updates = body.get('updates', []) updates_status = self.apply_updates(root_path, - updates, - body.get('model')) + updates, + body.get('model'), + ) if 'model' in body: order = [] old_model = body['model'] new_model = self.todict(order=order, - build_schema=False, - build_form=False, - updates_status=updates_status) + build_schema=False, + build_form=False, + updates_status=updates_status, + ) values = {'updates': list_keys(old_model, new_model['model'], order, updates_status), 'model': new_model['model']} else: @@ -893,12 +919,13 @@ class TiramisuDict: return values def todict(self, - custom_form=[], - build_schema=True, - build_model=True, - build_form=True, - order=None, - updates_status={}): + custom_form=[], + build_schema=True, + build_model=True, + build_form=True, + order=None, + updates_status={}, + ): rootpath = self.root if build_schema: schema = {} @@ -914,13 +941,14 @@ class TiramisuDict: else: form = None self.walk(rootpath, - None, - schema, - model, - form, - order, - updates_status, - init=True) + None, + schema, + model, + form, + order, + updates_status, + init=True, + ) if build_form: for form_ in custom_form: if 'key' in form_: diff --git a/tiramisu/value.py b/tiramisu/value.py index 0622f70..9a0744e 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -247,10 +247,10 @@ class Values: #______________________________________________________________________ # set value - def setvalue(self, - value, - option_bag, - ): + def set_value(self, + option_bag, + value, + ): context = option_bag.config_bag.context owner = self.get_context_owner() if 'validator' in option_bag.config_bag.properties: @@ -283,23 +283,29 @@ class Values: def setvalue_validation(self, value, - option_bag): + option_bag, + ): settings = option_bag.config_bag.context.get_settings() # First validate properties with this value opt = option_bag.option settings.validate_frozen(option_bag) - val = self.calc_value(option_bag, value, False) + val = self.calc_value(option_bag, + value, + False,) settings.validate_mandatory(val, - option_bag) + option_bag, + ) # Value must be valid for option opt.impl_validate(val, option_bag, - check_error=True) + check_error=True, + ) if 'warnings' in option_bag.config_bag.properties: # No error found so emit warnings opt.impl_validate(value, option_bag, - check_error=False) + check_error=False, + ) def _setvalue(self, option_bag: OptionBag, @@ -398,7 +404,8 @@ class Values: else: doption_bag.properties = ori_properties parent_owner = parent.get_values().getowner(doption_bag, - only_default=True) + only_default=True, + ) if parent_owner != owners.default: return doption_bag @@ -432,7 +439,8 @@ class Values: def getowner(self, option_bag, validate_meta=True, - only_default=False): + only_default=False, + ): """ retrieves the option's owner @@ -466,15 +474,16 @@ class Values: moption_bag = self._get_modified_parent(option_bag) if moption_bag is not None: owner = moption_bag.config_bag.context.get_values().getowner(moption_bag, - only_default=only_default) + only_default=only_default, + ) elif 'force_metaconfig_on_freeze' in option_bag.properties: return owners.default return owner - def setowner(self, - owner, - option_bag, - ): + def set_owner(self, + option_bag, + owner, + ): """ sets a owner to an option @@ -586,9 +595,10 @@ class Values: del self._values[path][index] def reset_leadership(self, - index, - option_bag, - subconfig): + option_bag: OptionBag, + leadership_option_bag: OptionBag, + index: int, + ): current_value = self.get_cached_value(option_bag) length = len(current_value) if index >= length: @@ -597,12 +607,13 @@ class Values: length, option_bag.option.impl_get_display_name())) current_value.pop(index) - subconfig.get_description().pop(self, - index, - option_bag) - self.setvalue(current_value, - option_bag, - ) + leadership_option_bag.option.pop(self, + index, + option_bag, + ) + self.set_value(option_bag, + current_value, + ) #______________________________________________________________________ # information @@ -665,98 +676,6 @@ class Values: ): return list(self._informations.get(path, {}).keys()) - #______________________________________________________________________ - # mandatory warnings - def _mandatory_warnings(self, - context, - config_bag, - description_bag, - currpath, - subconfig, - ): - settings = context.get_settings() - for option in description_bag.option.get_children(config_bag): - name = option.impl_getname() - if option.impl_is_symlinkoption(): - continue - if option.impl_is_optiondescription(): - try: - option_bag = OptionBag(option, - None, - description_bag.config_bag, - ) - - subsubconfig = subconfig.get_subconfig(option_bag) - except PropertiesOptionError as err: - pass - else: - for option in self._mandatory_warnings(context, - config_bag, - option_bag, - currpath + [name], - subsubconfig, - ): - yield option - else: - try: - if not option.impl_is_follower(): - option_bag = OptionBag(option, - None, - config_bag, - ) - if 'mandatory' in option_bag.properties or 'empty' in option_bag.properties: - subconfig.getattr(name, - option_bag) - else: - for index in range(subconfig.get_length_leadership(description_bag)): - option_bag = OptionBag(option, - index, - config_bag, - ) - if 'mandatory' in option_bag.properties or 'empty' in option_bag.properties: - subconfig.getattr(name, - option_bag) - except PropertiesOptionError as err: - if err.proptype in (['mandatory'], ['empty']): - yield option.impl_getpath() - except ConfigError: - pass - - def mandatory_warnings(self, - config_bag, - ): - """convenience function to trace Options that are mandatory and - where no value has been set - - :returns: generator of mandatory Option's path - """ - context = config_bag.context - # copy - od_setting_properties = config_bag.properties - {'mandatory', 'empty'} - setting_properties = set(config_bag.properties) - {'warnings'} - setting_properties.update(['mandatory', 'empty']) - nconfig_bag = ConfigBag(context=config_bag.context, - properties=frozenset(setting_properties), - permissives=config_bag.permissives) - nconfig_bag.set_permissive() - od_config_bag = ConfigBag(context=nconfig_bag.context, - properties=frozenset(od_setting_properties), - permissives=nconfig_bag.permissives) - od_config_bag.set_permissive() - - descr = context.get_description() - option_bag = OptionBag(descr, - None, - od_config_bag, - ) - for option in self._mandatory_warnings(context, - nconfig_bag, - option_bag, - [], - context, - ): - yield option - #____________________________________________________________ # default owner methods def set_context_owner(self, owner):