tiramisu/tiramisu/config.py

1069 lines
46 KiB
Python

# -*- 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 <http://www.gnu.org/licenses/>.
#
# 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 = ConfigBag(config=config_bag.config,
_setting_properties=config_bag._setting_properties,
force_permissive=config_bag.force_permissive,
force_unrestraint=config_bag.force_unrestraint,
_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):
#self, name = self.cfgimpl_get_home_by_path(option_bag.path,
# option_bag.config_bag)
#if config_bag.option is None:
# config_bag.option = self.cfgimpl_get_description().impl_getchild(name,
# config_bag,
# self)
if option_bag.option.impl_is_symlinkoption():
raise ConfigError(_("can't assign to a SymLinkOption"))
else:
context = self.cfgimpl_get_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:
try:
if isinstance(child, GroupConfig):
ret.extend(child.set_value(path,
index,
value,
config_bag,
only_config=only_config,
_commit=False))
else:
subconfig, name = child.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().impl_getchild(name,
config_bag,
child)
option_bag = OptionBag()
option_bag.set_option(option,
path,
index,
config_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:
subconfig, name = child.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().impl_getchild(name,
config_bag,
child)
option_bag = OptionBag()
option_bag.set_option(option,
path,
index,
config_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 = ConfigBag(config=config_bag.config,
_setting_properties=config_bag._setting_properties,
force_permissive=config_bag.force_permissive,
force_unrestraint=config_bag.force_unrestraint,
_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