diff --git a/ChangeLog b/ChangeLog index f506e56..bb21118 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ -Sun Mar 24 20:24:34 2019 +Fri Apr 5 20:57:05 2019 +0200 Emmanuel Garette + * add/remove config in mixconfig or metaconfig (fixes #6) + +Sun Mar 24 20:24:34 2019 +0200 Emmanuel Garette * version 3.0 rc3 * corrections in debug logger * requirement can have callback diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index 4a1ae52..acd09e2 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -246,14 +246,55 @@ def test_meta_new_metaconfig(): def test_meta_pop_config(): od = make_description() meta = MetaConfig(['name1', 'name2'], optiondescription=od) + meta.option('od1.i1').value.set(2) + # assert len(list(meta.config.list())) == 2 meta.config.new('newconf1') + assert meta.config('newconf1').value.dict() == {'od1.i1': 2, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + # assert len(list(meta.config.list())) == 3 - meta.config.pop('newconf1') + newconf1 = meta.config.pop('newconf1') + try: + assert meta.config('newconf1').value.dict() + except ConfigError: + pass + else: + raise Exception('must raise') + assert newconf1.value.dict() == {'od1.i1': None, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + # assert len(list(meta.config.list())) == 2 raises(ConfigError, "meta.config.pop('newconf1')") +def test_meta_add_config(): + od = make_description() + od2 = make_description() + meta = MetaConfig(['name1', 'name2'], optiondescription=od) + meta.option('od1.i1').value.set(2) + # + assert len(list(meta.config.list())) == 2 + config = Config(od, session_id='new') + assert config.value.dict() == {'od1.i1': None, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + meta.config.add(config) + # + assert len(list(meta.config.list())) == 3 + assert config.value.dict() == {'od1.i1': 2, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + # + raises(ConflictError, "meta.config.add(config)") + raises(ValueError, "meta.config.add(Config(od2))") + + +def test_meta_add_config_readd(): + od = make_description() + meta = MetaConfig([], optiondescription=od) + meta2 = MetaConfig([], optiondescription=od) + config = Config(od, session_id='new') + # + meta.config.add(config) + # + raises(ConflictError, "meta2.config.add(config)") + + def test_meta_new_config_wrong_name(): od = make_description() meta = MetaConfig(['name1', 'name2'], optiondescription=od) diff --git a/test/test_mixconfig.py b/test/test_mixconfig.py index d4162a3..9fe1059 100644 --- a/test/test_mixconfig.py +++ b/test/test_mixconfig.py @@ -1072,3 +1072,53 @@ def test_mix_different_default_reset(): assert mix.config('submix2.submix1').value.dict() == {'ip_admin_eth1': ['192.168.1.3']} assert mix.config('submix2.submix1.conf2').value.dict() == {'ip_admin_eth1': ['192.168.1.2']} assert mix.config('submix2.submix1.conf1').value.dict() == {'ip_admin_eth0': ['192.168.1.1']} + + +def test_mix_pop_config(): + od = make_description() + config1 = Config(od, session_id='config1') + config2 = Config(od, session_id='config2') + mix = MixConfig(od, [config1, config2]) + mix.option('od1.i1').value.set(2) + # + assert len(list(mix.config.list())) == 2 + assert mix.config('config1').value.dict() == {'od1.i1': 2, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + newconf1 = mix.config.pop('config1') + try: + assert mix.config('config1').value.dict() + except ConfigError: + pass + else: + raise Exception('must raise') + assert newconf1.value.dict() == {'od1.i1': None, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + # + assert len(list(mix.config.list())) == 1 + raises(ConfigError, "mix.config.pop('newconf1')") + + +def test_mix_add_config(): + od = make_description() + config1 = Config(od, session_id='config1') + config2 = Config(od, session_id='config2') + mix = MixConfig(od, [config1, config2]) + mix.option('od1.i1').value.set(2) + # + assert len(list(mix.config.list())) == 2 + config = Config(od, session_id='new') + assert config.value.dict() == {'od1.i1': None, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + mix.config.add(config) + # + assert len(list(mix.config.list())) == 3 + assert config.value.dict() == {'od1.i1': 2, 'od1.i2': 1, 'od1.i3': None, 'od1.i4': 2, 'od1.i5': [2], 'od1.i6': None} + # + raises(ConflictError, "mix.config.add(config)") + + +def test_mix_add_config_readd(): + od = make_description() + mix = MixConfig(od, []) + mix2 = MixConfig(od, []) + # + config = Config(od, session_id='new') + mix.config.add(config) + raises(ConflictError, "mix2.config.add(config)") diff --git a/tiramisu/api.py b/tiramisu/api.py index b91f39a..1399f1d 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -1248,10 +1248,18 @@ class _TiramisuContextGroupConfig(TiramisuContext): class _TiramisuContextMixConfig(_TiramisuContextGroupConfig, _TiramisuContextConfigReset): """Actions to MixConfig""" - pass + def pop(self, + session_id): + """Remove config from MetaConfig""" + return Config(self._config_bag.context.pop_config(session_id=session_id)) + + def add(self, + config): + """Add config from MetaConfig""" + return Config(self._config_bag.context.add_config(config)) -class _TiramisuContextMetaConfig(_TiramisuContextGroupConfig, _TiramisuContextConfigReset): +class _TiramisuContextMetaConfig(_TiramisuContextMixConfig): """Actions to MetaConfig""" def new(self, session_id, @@ -1262,11 +1270,6 @@ class _TiramisuContextMetaConfig(_TiramisuContextGroupConfig, _TiramisuContextCo persistent=persistent, type_=type)) - def pop(self, - session_id): - """Remove config from MetaConfig""" - return Config(self._config_bag.context.pop_config(session_id=session_id)) - class TiramisuContextCache(TiramisuContext): def reset(self): diff --git a/tiramisu/config.py b/tiramisu/config.py index 4ecfc6f..95129d1 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -1169,6 +1169,28 @@ class KernelMixConfig(KernelGroupConfig): if commit: self.cfgimpl_get_values()._p_.commit() + def add_config(self, + apiconfig): + config = apiconfig._config_bag.context + if config._impl_meta is not None: + raise ConflictError(_('config is already in a metaconfig')) + if config.impl_getname() in [child.impl_getname() for child in self._impl_children]: + raise ConflictError(_('config name must be uniq in ' + 'groupconfig for {0}').format(config.impl_getname())) + + config._impl_meta = weakref.ref(self) + self._impl_children.append(config) + config.cfgimpl_reset_cache(None, None) + + def pop_config(self, + session_id): + for idx, child in enumerate(self._impl_children): + if session_id == child.impl_getname(): + child._impl_meta = None + child.cfgimpl_reset_cache(None, None) + return self._impl_children.pop(idx) + raise ConfigError(_('cannot find the config {}').format(session_id)) + class KernelMetaConfig(KernelMixConfig): __slots__ = tuple() @@ -1221,7 +1243,7 @@ class KernelMetaConfig(KernelMixConfig): session_id, type_='config', persistent=False): - if session_id in [child._impl_name for child in self._impl_children]: + if session_id in [child.impl_getname() for child in self._impl_children]: raise ConflictError(_('config name must be uniq in ' 'groupconfig for {0}').format(session_id)) assert type_ in ('config', 'metaconfig'), _('unknown type {}').format(type_) @@ -1242,9 +1264,9 @@ class KernelMetaConfig(KernelMixConfig): self._impl_children.append(config) return config - def pop_config(self, - session_id): - for idx, child in enumerate(self._impl_children): - if session_id == child._impl_name: - return self._impl_children.pop(idx) - raise ConfigError(_('cannot find the config {}').format(session_id)) + def add_config(self, + apiconfig): + if self._impl_descr is not apiconfig._config_bag.context.cfgimpl_get_description(): + raise ValueError(_('metaconfig must ' + 'have the same optiondescription')) + super().add_config(apiconfig)