# -*- coding: utf-8 -*- # Copyright (C) 2012-2018 Team tiramisu (see AUTHORS for all contributors) # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # # The original `Config` design model is unproudly borrowed from # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # the whole pypy projet is under MIT licence # ____________________________________________________________ "options handler global entry point" import weakref from copy import copy from .error import PropertiesOptionError, ConfigError, ConflictError, SlaveError from .option.syndynoptiondescription import SynDynOptionDescription from .option.dynoptiondescription import DynOptionDescription from .option.masterslave import MasterSlaves from .option.baseoption import BaseOption, valid_name from .setting import OptionBag, ConfigBag, groups, Settings, undefined from .storage import get_storages, get_default_values_storages from .value import Values # , Multi from .i18n import _ class SubConfig(object): """Sub configuration management entry. Tree if OptionDescription's responsability. SubConfig are generated on-demand. A Config is also a SubConfig. Root Config is call context below """ __slots__ = ('_impl_context', '_impl_descr', '_impl_path', '_impl_length') def __init__(self, descr, context, config_bag, subpath=None, fromconsistency=None): """ Configuration option management master class :param descr: describes the configuration schema :type descr: an instance of ``option.OptionDescription`` :param context: the current root config :type context: `Config` :type subpath: `str` with the path name """ # main option description error = False if descr is not None and (not isinstance(descr, (BaseOption, SynDynOptionDescription)) or not descr.impl_is_optiondescription()): error = True if error: try: msg = descr.impl_get_displayname() except AttributeError: msg = descr raise TypeError(_('"{0}" must be an optiondescription, not an {1}' ).format(msg, type(descr))) self._impl_descr = descr self._impl_context = context self._impl_path = subpath if descr is not None and \ descr.impl_get_group_type() == groups.master: master = descr.getmaster() masterpath = master.impl_getname() full_masterpath = self._get_subpath(masterpath) cconfig_bag = config_bag.copy() cconfig_bag.validate = False moption_bag = OptionBag() moption_bag.set_option(master, full_masterpath, None, cconfig_bag) if fromconsistency: moption_bag.fromconsistency = fromconsistency value = self.getattr(masterpath, moption_bag) self._impl_length = len(value) def cfgimpl_get_length(self): return self._impl_length def cfgimpl_get_length_slave(self, option_bag): if option_bag.option.impl_is_symlinkoption(): context = self.cfgimpl_get_context() #soption_bag = OptionBag() #soption_bag.set_option(option_bag.option.impl_getopt(), # option_bag.option.impl_getopt().impl_getpath(context), # None, # option_bag.config_bag) path = option_bag.option.impl_getopt().impl_getpath(context) subconfig, _ = context.cfgimpl_get_home_by_path(path, option_bag.config_bag) return subconfig.cfgimpl_get_length() else: return self.cfgimpl_get_length() def reset_one_option_cache(self, desc, values, settings, resetted_opts, option_bag): if option_bag.path in resetted_opts: return resetted_opts.append(option_bag.path) for woption in option_bag.option._get_dependencies(self): option = woption() if option.impl_is_dynoptiondescription(): for doption in option.get_syndynoptiondescriptions(option_bag): doption_path = doption.impl_getpath(self) doption_bag = OptionBag() doption_bag.set_option(doption, doption_path, option_bag.index, option_bag.config_bag) self.reset_one_option_cache(desc, values, settings, resetted_opts, doption_bag) elif option.issubdyn(): doption_bag = OptionBag() doption_path = option.impl_getpath(self) doption_bag.set_option(option, doption_path, option_bag.index, option_bag.config_bag) for doption in desc.build_dynoptions(doption_bag): doption_path = doption.impl_getpath(self) doption_bag = OptionBag() doption_bag.set_option(doption, doption_path, option_bag.index, option_bag.config_bag) self.reset_one_option_cache(desc, values, settings, resetted_opts, doption_bag) else: option_path = option.impl_getpath(self) doption_bag = OptionBag() doption_bag.set_option(option, option_path, option_bag.index, option_bag.config_bag) self.reset_one_option_cache(desc, values, settings, resetted_opts, doption_bag) del option option_bag.option.reset_cache(option_bag.path, values, settings, resetted_opts) def cfgimpl_reset_cache(self, option_bag, resetted_opts=None): """reset all settings in cache """ if resetted_opts is None: resetted_opts = [] context = self.cfgimpl_get_context() desc = context.cfgimpl_get_description() values = context.cfgimpl_get_values() settings = context.cfgimpl_get_settings() if option_bag is not None: self.reset_one_option_cache(desc, values, settings, resetted_opts, option_bag) else: values._p_.reset_all_cache() settings._p_.reset_all_cache() def cfgimpl_get_home_by_path(self, path, config_bag, fromconsistency=None): """:returns: tuple (config, name)""" path = path.split('.') for step in path[:-1]: option_bag = OptionBag() option = self.cfgimpl_get_description().impl_getchild(step, config_bag, self) subpath = self._get_subpath(step) option_bag.set_option(option, subpath, None, config_bag) if fromconsistency is not None: option_bag.fromconsistency = fromconsistency self = self.get_subconfig(step, option_bag) if not isinstance(self, SubConfig): raise AttributeError(_('unknown option {}').format(path[-1])) return self, path[-1] # ______________________________________________________________________ def cfgimpl_get_context(self): """context could be None, we need to test it context is None only if all reference to `Config` object is deleted (for example we delete a `Config` and we manipulate a reference to old `SubConfig`, `Values`, `Multi` or `Settings`) """ context = self._impl_context() if context is None: # pragma: no cover raise ConfigError(_('the context does not exist anymore')) return 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 def cfgimpl_get_settings(self): return self.cfgimpl_get_context()._impl_settings def cfgimpl_get_values(self): return self.cfgimpl_get_context()._impl_values def setattr(self, value, option_bag, _commit=True): if option_bag.option.impl_is_symlinkoption(): raise ConfigError(_("can't assign to a SymLinkOption")) context = option_bag.config_bag.context if option_bag.config_bag.setting_properties: context.cfgimpl_get_settings().validate_properties(option_bag) self.cfgimpl_get_description().impl_validate_value(option_bag.option, value, self) return context.cfgimpl_get_values().setvalue(value, option_bag, _commit) def delattr(self, option_bag): option = option_bag.option if option.impl_is_symlinkoption(): raise TypeError(_("can't delete a SymLinkOption")) values = self.cfgimpl_get_values() if option_bag.index is not None: values.reset_slave(option_bag) else: values.reset(option_bag) def _get_subpath(self, name): if self._impl_path is None: subpath = name else: subpath = self._impl_path + '.' + name return subpath def get_subconfig(self, name, option_bag): if '.' in name: if option_bag.fromconsistency: fromconsistency = option_bag.fromconsistency.copy() else: fromconsistency = None self, name = self.cfgimpl_get_home_by_path(name, option_bag.config_bag, fromconsistency) elif option_bag.fromconsistency: fromconsistency = option_bag.fromconsistency.copy() else: fromconsistency = None if option_bag.config_bag.setting_properties: self.cfgimpl_get_settings().validate_properties(option_bag) return SubConfig(option_bag.option, self._impl_context, option_bag.config_bag, option_bag.path, fromconsistency) def getattr(self, name, option_bag): """ attribute notation mechanism for accessing the value of an option :param name: attribute name :return: option's value if name is an option name, OptionDescription otherwise """ config_bag = option_bag.config_bag if '.' in name: if option_bag.fromconsistency: fromconsistency = option_bag.fromconsistency.copy() else: fromconsistency = None self, name = self.cfgimpl_get_home_by_path(name, config_bag, fromconsistency) option = option_bag.option if option.impl_is_symlinkoption(): soption_bag = OptionBag() soption_bag.set_option(option.impl_getopt(), None, option_bag.index, config_bag) soption_bag.ori_option = option context = self.cfgimpl_get_context() return context.getattr(soption_bag.path, soption_bag) if config_bag.setting_properties: self.cfgimpl_get_settings().validate_properties(option_bag) if option.impl_is_master_slaves('slave'): length = self.cfgimpl_get_length_slave(option_bag) slave_len = self.cfgimpl_get_values()._p_.get_max_length(option_bag.path) if slave_len > length: raise SlaveError(_('slave option "{}" has higher length "{}" than the master ' 'length "{}"').format(option.impl_get_display_name(), slave_len, length, option_bag.index)) if option.impl_is_master_slaves('slave') and option_bag.index is None: value = [] for idx in range(length): soption_bag = OptionBag() soption_bag.set_option(option, option_bag.path, idx, config_bag) soption_bag.fromconsistency = option_bag.fromconsistency.copy() value.append(self.getattr(name, soption_bag)) else: value = self.cfgimpl_get_values().get_cached_value(option_bag) if config_bag.validate_properties: self.cfgimpl_get_settings().validate_mandatory(value, option_bag) return value def find(self, bytype, byname, byvalue, config_bag, _subpath=None, raise_if_not_found=True, only_path=undefined, only_option=undefined): """ convenience method for finding an option that lives only in the subtree :param first: return only one option if True, a list otherwise :return: find list or an exception if nothing has been found """ def _filter_by_value(soption_bag): try: value = self.getattr(path, soption_bag) except PropertiesOptionError: return False if isinstance(value, list): return byvalue in value else: return value == byvalue found = False if only_path is not undefined: options = [(only_path, only_option)] else: options = self.cfgimpl_get_description().impl_get_options_paths(bytype, byname, _subpath, config_bag) for path, option in options: option_bag = OptionBag() option_bag.set_option(option, path, None, config_bag) if byvalue is not undefined and not _filter_by_value(option_bag): continue elif config_bag.validate_properties: #remove option with propertyerror, ... try: if '.' in path: subconfig, subpath = self.cfgimpl_get_home_by_path(path, config_bag) else: subconfig = self subpath = path subconfig.cfgimpl_get_description().impl_getchild(subpath, config_bag, subconfig) self.cfgimpl_get_settings().validate_properties(option_bag) except PropertiesOptionError: continue found = True yield path self._find_return_results(found, raise_if_not_found) def _find_return_results(self, found, raise_if_not_found): if not found and raise_if_not_found: raise AttributeError(_("no option found in config" " with these criteria")) def make_dict(self, config_bag, flatten=False, _currpath=None, withoption=None, withvalue=undefined, fullpath=False): """exports the whole config into a `dict`, for example: >>> print(cfg.make_dict()) {'od2.var4': None, 'od2.var5': None, 'od2.var6': None} :param flatten: returns a dict(name=value) instead of a dict(path=value) :: >>> print(cfg.make_dict(flatten=True)) {'var5': None, 'var4': None, 'var6': None} :param withoption: returns the options that are present in the very same `OptionDescription` than the `withoption` itself:: >>> print(cfg.make_dict(withoption='var1')) {'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value', 'od1.var1': None, 'od1.var3': None, 'od1.var2': None} :param withvalue: returns the options that have the value `withvalue` :: >>> print(c.make_dict(withoption='var1', withvalue=u'value')) {'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value'} :returns: dict of Option's name (or path) and values """ pathsvalues = [] if _currpath is None: _currpath = [] if withoption is None and withvalue is not undefined: raise ValueError(_("make_dict can't filtering with value without " "option")) context = self.cfgimpl_get_context() if withoption is not None: mypath = self.cfgimpl_get_path() for path in context.find(bytype=None, byname=withoption, byvalue=withvalue, _subpath=self.cfgimpl_get_path(False), config_bag=config_bag): path = '.'.join(path.split('.')[:-1]) if '.' in path: subconfig, subpath = context.cfgimpl_get_home_by_path(path, config_bag) else: subconfig = context subpath = path opt = subconfig.cfgimpl_get_description().impl_getchild(subpath, config_bag, subconfig) soption_bag = OptionBag() soption_bag.set_option(opt, path, None, config_bag) if mypath is not None: if mypath == path: withoption = None withvalue = undefined break else: tmypath = mypath + '.' if not path.startswith(tmypath): # pragma: no cover raise AttributeError(_('unexpected path "{0}", ' 'should start with "{1}"' '').format(path, mypath)) path = path[len(tmypath):] self._make_sub_dict(path, pathsvalues, _currpath, flatten, soption_bag, fullpath=fullpath) #withoption can be set to None below ! if withoption is None: for opt in self.cfgimpl_get_description().impl_getchildren(config_bag, context): name = opt.impl_getname() path = self._get_subpath(name) soption_bag = OptionBag() soption_bag.set_option(opt, path, None, config_bag) #path = self._get_subpath(name) self._make_sub_dict(name, pathsvalues, _currpath, flatten, soption_bag, fullpath=fullpath) if _currpath == []: options = dict(pathsvalues) return options return pathsvalues def _make_sub_dict(self, name, pathsvalues, _currpath, flatten, option_bag, fullpath=False): try: option = option_bag.option if not option.impl_is_optiondescription(): if option.impl_is_master_slaves('slave'): ret = [] length = self.cfgimpl_get_length_slave(option_bag) if length: for idx in range(length): soption_bag = OptionBag() soption_bag.set_option(option, option_bag.path, idx, option_bag.config_bag) ret.append(self.getattr(name, soption_bag)) elif option_bag.config_bag.setting_properties: self.cfgimpl_get_settings().validate_properties(option_bag) else: ret = self.getattr(name, option_bag) else: ret = self.get_subconfig(name, option_bag) except PropertiesOptionError: pass else: if option.impl_is_optiondescription(): pathsvalues += ret.make_dict(option_bag.config_bag, flatten=flatten, _currpath=_currpath + [name], fullpath=fullpath) else: if flatten: name = option.impl_getname() elif fullpath: name = self._get_subpath(name) else: name = '.'.join(_currpath + [name]) pathsvalues.append((name, ret)) def cfgimpl_get_path(self, dyn=True): descr = self.cfgimpl_get_description() if not dyn and descr.impl_is_dynoptiondescription(): context_descr = self.cfgimpl_get_context().cfgimpl_get_description() return context_descr.impl_get_path_by_opt(descr.impl_getopt()) return self._impl_path class _CommonConfig(SubConfig): "abstract base class for the Config, GroupConfig and the MetaConfig" __slots__ = ('_impl_values', '_impl_settings', '_impl_meta') def _impl_build_all_caches(self): descr = self.cfgimpl_get_description() if not descr.impl_already_build_caches(): descr._build_cache_option() descr._build_cache(self) descr.impl_build_force_store_values(self) def cfgimpl_get_path(self, dyn=True): return None def cfgimpl_get_meta(self): if self._impl_meta is not None: return self._impl_meta() # information def impl_set_information(self, key, value): """updates the information's attribute :param key: information's key (ex: "help", "doc" :param value: information's value (ex: "the help string") """ self._impl_values.set_information(key, value) def impl_get_information(self, key, default=undefined): """retrieves one information's item :param key: the item string (ex: "help") """ return self._impl_values.get_information(key, default) def impl_del_information(self, key, raises=True): self._impl_values.del_information(key, raises) def __getstate__(self): raise NotImplementedError() def _gen_fake_values(self): fake_config = Config(self._impl_descr, persistent=False, force_values=get_default_values_storages(), force_settings=self.cfgimpl_get_settings()) fake_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation()) return fake_config def duplicate(self, session_id=None, force_values=None, force_settings=None, storage=None): config = Config(self._impl_descr, _duplicate=True, session_id=session_id, force_values=force_values, force_settings=force_settings, storage=storage) config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation()) config.cfgimpl_get_settings()._p_.importation(self.cfgimpl_get_settings( )._p_.exportation()) config.cfgimpl_get_settings()._pp_.importation(self.cfgimpl_get_settings( )._pp_.exportation()) return config # ____________________________________________________________ class Config(_CommonConfig): "main configuration management entry" __slots__ = ('__weakref__', '_impl_name') def __init__(self, descr, session_id=None, persistent=False, force_values=None, force_settings=None, _duplicate=False, storage=None): """ Configuration option management master class :param descr: describes the configuration schema :type descr: an instance of ``option.OptionDescription`` :param context: the current root config :type context: `Config` :param session_id: session ID is import with persistent Config to retrieve good session :type session_id: `str` :param persistent: if persistent, don't delete storage when leaving :type persistent: `boolean` """ self._impl_meta = None if isinstance(descr, MasterSlaves): raise ConfigError(_('cannot set masterslaves object has root optiondescription')) if isinstance(descr, DynOptionDescription): raise ConfigError(_('cannot set dynoptiondescription object has root optiondescription')) if force_settings is not None and force_values is not None: if isinstance(force_settings, tuple): self._impl_settings = Settings(self, force_settings[0], force_settings[1]) else: self._impl_settings = force_settings self._impl_values = Values(self, force_values) else: properties, permissives, values, session_id = get_storages(self, session_id, persistent, storage=storage) if not valid_name(session_id): raise ValueError(_("invalid session ID: {0} for config").format(session_id)) self._impl_settings = Settings(self, properties, permissives) self._impl_values = Values(self, values) super(Config, self).__init__(descr, weakref.ref(self), ConfigBag(self), None) if _duplicate is False and (force_settings is None or force_values is None): self._impl_build_all_caches() self._impl_name = session_id def impl_getname(self): return self._impl_name def impl_getsessionid(self): return self._impl_values._p_._storage.session_id class GroupConfig(_CommonConfig): __slots__ = ('__weakref__', '_impl_children', '_impl_name') def __init__(self, children, session_id=None, persistent=False, _descr=None, storage=None): if not isinstance(children, list): raise ValueError(_("groupconfig's children must be a list")) names = [] for child in children: if not isinstance(child, _CommonConfig): raise ValueError(_("groupconfig's children must be Config, MetaConfig or GroupConfig")) name_ = child._impl_name names.append(name_) if len(names) != len(set(names)): for idx in range(1, len(names) + 1): name = names.pop(0) if name in names: raise ConflictError(_('config name must be uniq in ' 'groupconfig for "{0}"').format(name)) self._impl_children = children properties, permissives, values, session_id = get_storages(self, session_id, persistent, storage=storage) self._impl_settings = Settings(self, properties, permissives) self._impl_values = Values(self, values) self._impl_meta = None super(GroupConfig, self).__init__(_descr, weakref.ref(self), ConfigBag(self), None) #undocumented option used only in test script self._impl_name = session_id def cfgimpl_get_children(self): return self._impl_children def cfgimpl_reset_cache(self, option_bag, resetted_opts=None): if resetted_opts is None: resetted_opts = [] if isinstance(self, MetaConfig): super(GroupConfig, self).cfgimpl_reset_cache(option_bag, resetted_opts=copy(resetted_opts)) for child in self._impl_children: child.cfgimpl_reset_cache(option_bag, resetted_opts=copy(resetted_opts)) def set_value(self, path, index, value, config_bag, only_config=False, _commit=True): """Setattr not in current GroupConfig, but in each children """ ret = [] for child in self._impl_children: cconfig_bag = config_bag.copy() cconfig_bag.context = child try: if isinstance(child, GroupConfig): ret.extend(child.set_value(path, index, value, cconfig_bag, only_config=only_config, _commit=False)) else: subconfig, name = child.cfgimpl_get_home_by_path(path, cconfig_bag) option = subconfig.cfgimpl_get_description().impl_getchild(name, cconfig_bag, child) option_bag = OptionBag() option_bag.set_option(option, path, index, cconfig_bag) child.setattr(value, option_bag, _commit=False) except PropertiesOptionError as err: ret.append(PropertiesOptionError(err._option_bag, err.proptype, err._settings, err._opt_type, err._requires, err._name, err._orig_opt)) except (ValueError, SlaveError) as err: ret.append(err) if _commit: self.cfgimpl_get_values()._p_.commit() return ret def find_firsts(self, config_bag, byname=None, bypath=undefined, byoption=undefined, byvalue=undefined, raise_if_not_found=True, _sub=False): """Find first not in current GroupConfig, but in each children """ #if MetaConfig, 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, MetaConfig): bypath = next(self.find(bytype=None, byvalue=undefined, byname=byname, config_bag=config_bag, raise_if_not_found=raise_if_not_found)) byname = None byoption = self.cfgimpl_get_description().impl_get_opt_by_path(bypath) ret = [] for child in self._impl_children: if isinstance(child, GroupConfig): ret.extend(child.find_firsts(byname=byname, bypath=bypath, byoption=byoption, byvalue=byvalue, config_bag=config_bag, raise_if_not_found=False, _sub=True)) else: try: next(child.find(None, byname, byvalue, config_bag=config_bag, raise_if_not_found=False, only_path=bypath, only_option=byoption)) ret.append(child) except StopIteration: pass if _sub: return ret else: self._find_return_results(ret != [], raise_if_not_found) return GroupConfig(ret) def impl_getname(self): return self._impl_name def getconfig(self, name): for child in self._impl_children: if name == child.impl_getname(): return child raise ConfigError(_('unknown config "{}"').format(name)) class MetaConfig(GroupConfig): __slots__ = tuple() def __init__(self, children, session_id=None, persistent=False, optiondescription=None): descr = None if optiondescription is not None: new_children = [] for child_session_id in children: new_children.append(Config(optiondescription, persistent=persistent, session_id=child_session_id)) children = new_children for child in children: if not isinstance(child, _CommonConfig): raise TypeError(_("metaconfig's children " "should be config, not {0}" ).format(type(child))) if child.cfgimpl_get_meta() is not None: raise ValueError(_("child has already a metaconfig's")) if descr is None: descr = child.cfgimpl_get_description() elif not descr is child.cfgimpl_get_description(): raise ValueError(_('all config in metaconfig must ' 'have the same optiondescription')) child._impl_meta = weakref.ref(self) super(MetaConfig, self).__init__(children, session_id, persistent, descr) def set_value(self, path, index, value, config_bag, force_default=False, force_dont_change_value=False, force_default_if_same=False, only_config=False, _commit=True): """only_config: could be set if you want modify value in all Config included in this MetaConfig """ 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(MetaConfig, self).set_value(path, index, value, config_bag, only_config=only_config, _commit=_commit) ret = [] 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')) opt = self.cfgimpl_get_description().impl_get_opt_by_path(path) for child in self._impl_children: cconfig_bag = config_bag.copy() cconfig_bag.context = child subconfig, name = child.cfgimpl_get_home_by_path(path, cconfig_bag) option = subconfig.cfgimpl_get_description().impl_getchild(name, cconfig_bag, child) option_bag = OptionBag() option_bag.set_option(option, path, index, cconfig_bag) if force_default_if_same: if not child.cfgimpl_get_values()._p_.hasvalue(path): child_value = undefined else: child_value = child.getattr(name, option_bag) if force_default or (force_default_if_same and value == child_value): child.cfgimpl_get_values().reset(option_bag, _commit=False) continue if force_dont_change_value: try: child_value = child.getattr(name, option_bag) if value != child_value: child.setattr(child_value, option_bag, _commit=False) except (PropertiesOptionError, ValueError, SlaveError) as err: ret.append(err) try: subconfig, name = self.cfgimpl_get_home_by_path(path, config_bag) option = subconfig.cfgimpl_get_description().impl_getchild(name, config_bag, self) option_bag = OptionBag() option_bag.set_option(option, path, index, config_bag) self.setattr(value, option_bag, _commit=False) except (PropertiesOptionError, ValueError, SlaveError) as err: ret.append(err) return ret def reset(self, path, config_bag): rconfig_bag = config_bag.copy() rconfig_bag.validate = False subconfig, name = self.cfgimpl_get_home_by_path(path, config_bag) option = subconfig.cfgimpl_get_description().impl_getchild(name, config_bag, self) option_bag = OptionBag() option_bag.set_option(option, path, option, rconfig_bag) for child in self._impl_children: child.cfgimpl_get_values().reset(option_bag, _commit=False) self.cfgimpl_get_values().reset(option_bag) def new_config(self, session_id, persistent=False): config = Config(self._impl_descr, session_id=session_id, persistent=persistent) if config._impl_name in [child._impl_name for child in self._impl_children]: # pragma: no cover raise ConflictError(_('config name must be uniq in ' 'groupconfig for {0}').format(config._impl_name)) config._impl_meta = weakref.ref(self) self._impl_children.append(config) return config