diff --git a/test/test_config.py b/test/test_config.py index b9117df..72908b2 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -195,7 +195,9 @@ def test_get_modified_values(): assert not config.option('od.g5').option.issubmulti() config.option('od.g5').value.set('yes') assert to_tuple(config.value.exportation()) == (('od.g5',), (None,), ('yes',), ('user',)) - config.option('od.g4').value.set(True) + config.option('od.g4').value.set(False) + assert to_tuple(config.value.exportation()) == (('od.g5', 'od.g4'), (None, None), ('yes', False), ('user', 'user')) + config.option('od.g4').value.set(undefined) assert to_tuple(config.value.exportation()) == (('od.g5', 'od.g4'), (None, None), ('yes', True), ('user', 'user')) config.option('od.g4').value.reset() assert to_tuple(config.value.exportation()) == (('od.g5',), (None,), ('yes',), ('user',)) diff --git a/test/test_masterslaves.py b/test/test_masterslaves.py index 213c4f2..7877f3c 100644 --- a/test/test_masterslaves.py +++ b/test/test_masterslaves.py @@ -118,6 +118,12 @@ def test_iter_on_groups(): group_type=groups.family): #test StopIteration break + result = api.option('creole').list('option', + group_type=groups.family) + assert list(result) == [] + result = api.option('creole.general').list('optiondescription', + group_type=groups.family) + assert list(result) == [] def test_list_recursive(): descr = make_description() @@ -130,6 +136,9 @@ def test_list_recursive(): result = list(api.option.list(recursive=True)) group_names = [res.option.name() for res in result] assert group_names == ['numero_etab', 'nom_machine', 'nombre_interfaces', 'activer_proxy_client', 'mode_conteneur_actif', 'serveur_ntp', 'time_zone', 'ip_admin_eth0', 'netmask_admin_eth0'] + result = list(api.option.list(recursive=True, type='optiondescription')) + group_names = [res.option.name() for res in result] + assert group_names == ['general', 'ip_admin_eth0', 'interface1', 'creole'] def test_iter_on_groups_force_permissive(): diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index 42b7e2f..9822734 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -7,7 +7,7 @@ from tiramisu.setting import groups, owners from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, \ OptionDescription, MasterSlaves, Config, GroupConfig, MetaConfig, \ Params, ParamOption, ParamValue -from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, SlaveError +from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, SlaveError, APIError owners.addowner('meta1') owners.addowner('meta2') @@ -286,12 +286,14 @@ def test_not_meta(): #raises(ConflictError, "GroupConfig([conf2, conf4], session_id='conf2')") raises(ConflictError, "GroupConfig([conf2, conf2], session_id='conf8')") grp = GroupConfig([conf1, conf2]) - raises(ConfigError, "grp.option('od1.i1').value.get()") + raises(APIError, "grp.option('od1.i1').value.get()") conf1, conf2 = grp.config.list() errors = grp.value.set('od1.i1', 7) assert len(errors) == 0 assert grp.config('conf1').option('od1.i1').value.get() == grp.config('conf2').option('od1.i1').value.get() == 7 assert grp.config('conf1').option('od1.i1').owner.get() is grp.config('conf2').option('od1.i1').owner.get() is owners.user + grp.option('od1.i1').value.reset() + assert grp.config('conf1').option('od1.i1').owner.get() is grp.config('conf2').option('od1.i1').owner.get() is owners.default def test_group_find_firsts(): diff --git a/tiramisu/api.py b/tiramisu/api.py index 78034ae..ae47d91 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -145,7 +145,7 @@ class CommonTiramisuOption(CommonTiramisu): self._name = name self.subconfig = subconfig # for help() - if option_bag is not None: + if option_bag is not None and self.option_bag.config_bag.context.impl_type != 'group': self._get_option() if option_bag.config_bag is not None and self.slave_need_index: self._test_slave_index() @@ -436,8 +436,7 @@ class TiramisuOptionValue(CommonTiramisuOption): def _m_pop(self, index): """pop value for a master option (only for master option)""" - if self.option_bag.option.impl_is_symlinkoption(): - raise TypeError(_("can't delete a SymLinkOption")) + assert not self.option_bag.option.impl_is_symlinkoption(), _("can't delete a SymLinkOption") self.option_bag.config_bag.context.cfgimpl_get_values().reset_master(index, self.option_bag, self.subconfig) @@ -447,28 +446,21 @@ class TiramisuOptionValue(CommonTiramisuOption): self._test_slave_index() self.subconfig.delattr(self.option_bag) - def _g_reset(self, - itself=None, - children=None): - """reset value for a GroupConfig or a MetaConfig""" - config_bag = self.option_bag.config_bag - if isinstance(config_bag.context, KernelMetaConfig): - if children is None: - children = False - if itself is None: - itself = True - else: - if children is None: - children = True - if itself is True: - raise APIError(_('cannot remove value in a GroupConfig')) - itself = False + def _m_reset(self, + itself: bool=True, + children: bool=False): + """reset value for a MetaConfig""" if children: + config_bag = self.option_bag.config_bag config_bag.context.reset(self.option_bag.path, config_bag) if itself: self._o_reset() + def _g_reset(self): + """reset value for a GroupConfig""" + self.option_bag.config_bag.context.reset(self.option_bag.path) + def _m_len_master(self): """length of master option (only for slave option)""" option = self.option_bag.option @@ -526,9 +518,14 @@ class TiramisuOptionValue(CommonTiramisuOption): return self._m_len_master elif name == 'dict' and option.impl_is_optiondescription(): return self._od_dict - elif not option.impl_is_optiondescription(): - if name == 'reset' and isinstance(self.option_bag.config_bag.context, KernelGroupConfig): + elif name == 'reset': + if self.option_bag.config_bag.context.impl_type == 'group': return getattr(self, '_g_' + name) + elif not option.impl_is_optiondescription(): + if self.option_bag.config_bag.context.impl_type == 'meta': + return getattr(self, '_m_' + name) + return getattr(self, '_o_' + name) + elif option and not option.impl_is_optiondescription(): return getattr(self, '_o_' + name) raise APIError(_('{} is unknown').format(name)) @@ -1049,11 +1046,11 @@ class TiramisuContextConfig(TiramisuContext): name: str) -> Callable: if not name.startswith('_'): try: - if isinstance(self.config_bag.context, KernelMetaConfig): + if self.config_bag.context.impl_type == 'meta': return getattr(self, '_m_' + name) - elif isinstance(self.config_bag.context, KernelGroupConfig): + elif self.config_bag.context.impl_type == 'group': return getattr(self, '_g_' + name) - elif isinstance(self.config_bag.context, KernelConfig): + elif self.config_bag.context.impl_type == 'config': return getattr(self, '_c_' + name) except APIError: # pragma: no cover raise APIError(_('{} is unknown').format(name)) @@ -1112,8 +1109,12 @@ class TiramisuDispatcherOption(TiramisuDispatcher, TiramisuContextOption): path: str, index: Optional[int]=None) -> TiramisuOption: """select a option (index only for slave option)""" - subconfig, name = self.config_bag.context.cfgimpl_get_home_by_path(path, - self.config_bag) + if self.config_bag.context.impl_type == 'group': + subpath, name = path.rsplit('.', 1) + subconfig = None + else: + subconfig, name = self.config_bag.context.cfgimpl_get_home_by_path(path, + self.config_bag) return TiramisuOption(name, path, index, diff --git a/tiramisu/config.py b/tiramisu/config.py index a14a3ef..2567287 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -217,11 +217,9 @@ class SubConfig(object): return self._impl_context() def cfgimpl_get_description(self): - if self._impl_descr is None: - raise ConfigError(_('there is no option description for this config' - ' (may be GroupConfig)')) - else: - return self._impl_descr + assert self._impl_descr is not None, _('there is no option description for this config' + ' (may be GroupConfig)') + return self._impl_descr def cfgimpl_get_settings(self): return self.cfgimpl_get_context()._impl_settings @@ -612,7 +610,8 @@ class _CommonConfig(SubConfig): "abstract base class for the Config, KernelGroupConfig and the KernelMetaConfig" __slots__ = ('_impl_values', '_impl_settings', - '_impl_meta') + '_impl_meta', + 'impl_type') def _impl_build_all_caches(self): descr = self.cfgimpl_get_description() @@ -709,7 +708,9 @@ class _CommonConfig(SubConfig): # ____________________________________________________________ class KernelConfig(_CommonConfig): "main configuration management entry" - __slots__ = ('__weakref__', '_impl_name') + __slots__ = ('__weakref__', + '_impl_name') + impl_type = 'config' def __init__(self, descr, @@ -769,6 +770,7 @@ class KernelGroupConfig(_CommonConfig): __slots__ = ('__weakref__', '_impl_children', '_impl_name') + impl_type = 'group' def __init__(self, children, @@ -822,6 +824,11 @@ class KernelGroupConfig(_CommonConfig): """Setattr not in current KernelGroupConfig, but in each children """ ret = [] + if isinstance(self, KernelGroupConfig): + commit = True + else: + #Commit only one time + commit = False for child in self._impl_children: cconfig_bag = config_bag.copy() cconfig_bag.context = child @@ -832,7 +839,7 @@ class KernelGroupConfig(_CommonConfig): value, cconfig_bag, only_config=only_config, - _commit=_commit)) + _commit=commit)) else: subconfig, name = child.cfgimpl_get_home_by_path(path, cconfig_bag) @@ -846,7 +853,7 @@ class KernelGroupConfig(_CommonConfig): cconfig_bag) child.setattr(value, option_bag, - _commit=_commit) + _commit=commit) except PropertiesOptionError as err: ret.append(PropertiesOptionError(err._option_bag, err.proptype, @@ -857,9 +864,8 @@ class KernelGroupConfig(_CommonConfig): err._orig_opt)) except (ValueError, SlaveError) as err: ret.append(err) - #FIXME should commit only here - #if _commit: - # self._impl_children[0].cfgimpl_get_values()._p_.commit() + if _commit and not isinstance(self, KernelGroupConfig): + self.cfgimpl_get_values()._p_.commit() return ret @@ -921,6 +927,25 @@ class KernelGroupConfig(_CommonConfig): def impl_getname(self): return self._impl_name + def reset(self, + path): + for child in self._impl_children: + config_bag = ConfigBag(child) + config_bag.remove_validation() + subconfig, name = child.cfgimpl_get_home_by_path(path, + config_bag) + option = subconfig.cfgimpl_get_description().impl_getchild(name, + config_bag, + subconfig.cfgimpl_get_path()) + option_bag = OptionBag() + option_bag.set_option(option, + path, + option, + config_bag) + option_bag.config_bag.context = child + child.cfgimpl_get_values().reset(option_bag, + _commit=True) + def getconfig(self, name): for child in self._impl_children: @@ -931,6 +956,7 @@ class KernelGroupConfig(_CommonConfig): class KernelMetaConfig(KernelGroupConfig): __slots__ = tuple() + impl_type = 'meta' def __init__(self, children, @@ -1073,7 +1099,7 @@ class KernelMetaConfig(KernelGroupConfig): config_bag) option = subconfig.cfgimpl_get_description().impl_getchild(name, config_bag, - self.cfgimpl_get_path()) + subconfig.cfgimpl_get_path()) option_bag = OptionBag() option_bag.set_option(option, path, @@ -1081,8 +1107,7 @@ class KernelMetaConfig(KernelGroupConfig): rconfig_bag) for child in self._impl_children: option_bag.config_bag.context = child - child.cfgimpl_get_values().reset(option_bag, - _commit=False) + child.cfgimpl_get_values().reset(option_bag) def new_config(self, session_id, diff --git a/tiramisu/storage/__init__.py b/tiramisu/storage/__init__.py index 3a7bb86..5866f3e 100644 --- a/tiramisu/storage/__init__.py +++ b/tiramisu/storage/__init__.py @@ -21,8 +21,6 @@ The storage is the system Tiramisu uses to communicate with various DB. You can specified a persistent storage. Storage is basic components used to set Config informations in DB. -The primary "entry point" class is the StorageType and it's public -configurator ``set_storage()``. """ @@ -84,18 +82,6 @@ memory_storage = StorageType() memory_storage.set(MEMORY_STORAGE) -def set_storage(type_, name): # pragma: optional cover - """Change storage's configuration - - :params name: is the storage name. If storage is already set, cannot - reset storage name - - Other attributes are differents according to the selected storage's name - """ - storage_type.set(name) - setting = storage_type.get().setting - - def gen_storage_id(session_id, config): if session_id is not None: @@ -152,4 +138,4 @@ def delete_session(session_id): # pragma: optional cover del(session) -__all__ = ('set_storage', 'list_sessions', 'delete_session') +__all__ = ('list_sessions', 'delete_session')