ConfigBag optimisation

This commit is contained in:
Emmanuel Garette 2018-08-01 08:37:58 +02:00
parent acdddcfe9c
commit 41c17004d2
19 changed files with 1163 additions and 1160 deletions

View file

@ -246,7 +246,7 @@ def test_reset_cache():
api.option('u1').value.get() api.option('u1').value.get()
assert 'u1' in values._p_.get_cached() assert 'u1' in values._p_.get_cached()
assert 'u1' in settings._p_.get_cached() assert 'u1' in settings._p_.get_cached()
c.cfgimpl_reset_cache(None, None, None) c.cfgimpl_reset_cache(None, None)
assert 'u1' not in values._p_.get_cached() assert 'u1' not in values._p_.get_cached()
assert 'u1' not in settings._p_.get_cached() assert 'u1' not in settings._p_.get_cached()
api.option('u1').value.get() api.option('u1').value.get()
@ -258,7 +258,7 @@ def test_reset_cache():
assert 'u1' in settings._p_.get_cached() assert 'u1' in settings._p_.get_cached()
assert 'u2' in values._p_.get_cached() assert 'u2' in values._p_.get_cached()
assert 'u2' in settings._p_.get_cached() assert 'u2' in settings._p_.get_cached()
c.cfgimpl_reset_cache(None, None, None) c.cfgimpl_reset_cache(None, None)
assert 'u1' not in values._p_.get_cached() assert 'u1' not in values._p_.get_cached()
assert 'u1' not in settings._p_.get_cached() assert 'u1' not in settings._p_.get_cached()
assert 'u2' not in values._p_.get_cached() assert 'u2' not in values._p_.get_cached()
@ -273,7 +273,7 @@ def test_reset_cache():
# values = c.cfgimpl_get_values() # values = c.cfgimpl_get_values()
# api.option('od1.u1').value.get() # api.option('od1.u1').value.get()
# assert 'od1.u1' in values._p_.get_cached() # assert 'od1.u1' in values._p_.get_cached()
# c.od1.cfgimpl_reset_cache(None, None, None) # c.od1.cfgimpl_reset_cache(None, None)
# assert 'od1.u1' not in values._p_.get_cached() # assert 'od1.u1' not in values._p_.get_cached()

View file

@ -429,10 +429,10 @@ def test_invalid_option():
raises(ValueError, "DomainnameOption('a', '', multi=True, default_multi=1)") raises(ValueError, "DomainnameOption('a', '', multi=True, default_multi=1)")
def test_help(): #def test_help():
stro = StrOption('s', '', multi=True) # stro = StrOption('s', '', multi=True)
od1 = OptionDescription('o', '', [stro]) # od1 = OptionDescription('o', '', [stro])
od2 = OptionDescription('o', '', [od1]) # od2 = OptionDescription('o', '', [od1])
cfg = Config(od2) # cfg = Config(od2)
api = getapi(cfg) # api = getapi(cfg)
api.help(_display=False, _valid=True) # api.help(_display=False, _valid=True)

View file

@ -110,8 +110,8 @@ def test_iter_on_groups():
descr = make_description() descr = make_description()
api = getapi(Config(descr)) api = getapi(Config(descr))
api.property.read_write() api.property.read_write()
result = list(api.option('creole').list('optiondescription', group_type=groups.family)) result = api.option('creole').list('optiondescription', group_type=groups.family)
group_names = [res[0] for res in result] group_names = [res.option.name() for res in result]
assert group_names == ['general', 'interface1'] assert group_names == ['general', 'interface1']
for i in api.option('creole').list('optiondescription', group_type=groups.family): for i in api.option('creole').list('optiondescription', group_type=groups.family):
#test StopIteration #test StopIteration
@ -123,13 +123,15 @@ def test_iter_on_groups_force_permissive():
api = getapi(Config(descr)) api = getapi(Config(descr))
api.property.read_write() api.property.read_write()
api.permissive.set(frozenset(['hidden'])) api.permissive.set(frozenset(['hidden']))
#result = list(config.creole.general.__iter__(force_permissive=True)) result = api.forcepermissive.option('creole.general').list()
group_names = list(api.forcepermissive.option('creole.general').list()) group_names = [res.option.name() for res in result]
ass = ['numero_etab', 'nom_machine', 'nombre_interfaces', ass = ['numero_etab', 'nom_machine', 'nombre_interfaces',
'activer_proxy_client', 'mode_conteneur_actif', 'activer_proxy_client', 'mode_conteneur_actif',
'mode_conteneur_actif2', 'serveur_ntp', 'time_zone'] 'mode_conteneur_actif2', 'serveur_ntp', 'time_zone']
assert group_names == ass assert group_names == ass
group_names = list(api.option('creole.general').list()) # mode_conteneur_actif2 is not visible is not forcepermissive
result = api.option('creole.general').list()
group_names = [res.option.name() for res in result]
ass.remove('mode_conteneur_actif2') ass.remove('mode_conteneur_actif2')
assert group_names == ass assert group_names == ass
@ -139,8 +141,8 @@ def test_iter_group_on_groups_force_permissive():
api = getapi(Config(descr)) api = getapi(Config(descr))
api.property.read_write() api.property.read_write()
api.permissive.set(frozenset(['hidden'])) api.permissive.set(frozenset(['hidden']))
result = list(api.forcepermissive.option('creole').list(type='optiondescription', group_type=groups.family)) result = api.forcepermissive.option('creole').list(type='optiondescription', group_type=groups.family)
group_names = [res[0] for res in result] group_names = [res.option.name() for res in result]
assert group_names == ['general', 'interface1', 'new'] assert group_names == ['general', 'interface1', 'new']
@ -149,8 +151,8 @@ def test_iter_on_groups_props():
api = getapi(Config(descr)) api = getapi(Config(descr))
api.property.read_write() api.property.read_write()
api.option('creole.interface1').property.add('disabled') api.option('creole.interface1').property.add('disabled')
result = list(api.option('creole').list(type='optiondescription', group_type=groups.family)) result = api.option('creole').list(type='optiondescription', group_type=groups.family)
group_names = [res[0] for res in result] group_names = [res.option.name() for res in result]
assert group_names == ['general'] assert group_names == ['general']

View file

@ -796,33 +796,32 @@ def test_callback_master_and_slaves_slave_cal():
val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val3))) val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params=Params(ParamOption(val3)))
val2 = StrOption('val2', "", multi=True, callback=return_val) val2 = StrOption('val2', "", multi=True, callback=return_val)
interface1 = MasterSlaves('val1', '', [val1, val2]) interface1 = MasterSlaves('val1', '', [val1, val2])
#interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, val3]) maconfig = OptionDescription('rootconfig', '', [interface1, val3])
api = getapi(Config(maconfig)) api = getapi(Config(maconfig))
api.property.read_write() api.property.read_write()
#
assert api.option('val3').value.get() == [] assert api.option('val3').value.get() == []
assert api.option('val1.val1').value.get() == [] assert api.option('val1.val1').value.get() == []
#
api.option('val1.val1').value.set(['val1']) api.option('val1.val1').value.set(['val1'])
api.option('val3').value.set(['val1']) api.option('val3').value.set(['val1'])
assert api.option('val1.val1').value.get() == ['val1'] assert api.option('val1.val1').value.get() == ['val1']
assert api.option('val1.val2', 0).value.get() == 'val' assert api.option('val1.val2', 0).value.get() == 'val'
#
api.option('val1.val1').value.reset() api.option('val1.val1').value.reset()
api.option('val1.val2', 0).value.set('val') api.option('val1.val2', 0).value.set('val')
#
api.option('val3').value.set(['val1', 'val2']) api.option('val3').value.set(['val1', 'val2'])
assert api.option('val1.val2', 0).value.get() == 'val' assert api.option('val1.val2', 0).value.get() == 'val'
assert api.option('val1.val2', 1).value.get() == 'val' assert api.option('val1.val2', 1).value.get() == 'val'
assert api.option('val1.val1').value.get() == ['val1', 'val2'] assert api.option('val1.val1').value.get() == ['val1', 'val2']
# len of slave is higher than master's one
api.option('val1.val2', 0).value.set('val1') api.option('val1.val2', 0).value.set('val1')
api.option('val1.val2', 1).value.set('val2') api.option('val1.val2', 1).value.set('val2')
api.option('val3').value.set(['val1']) api.option('val3').value.set(['val1'])
# cannot remove slave's value because master is calculated assert api.option('val1.val1').value.get() == ['val1']
# so raise raises(SlaveError, "api.option('val1.val2', 0).value.get()")
if TIRAMISU_VERSION == 2: #
raises(SlaveError, "api.option('val1.val1').value.get()")
raises(SlaveError, "api.option('val1.val2', 0).value.get()")
else:
assert api.option('val1.val1').value.get() == ['val1']
raises(SlaveError, "api.option('val1.val2', 0).value.get()")
api.option('val3').value.set(['val1', 'val2', 'val3']) api.option('val3').value.set(['val1', 'val2', 'val3'])
assert api.option('val1.val2', 0).value.get() == 'val1' assert api.option('val1.val2', 0).value.get() == 'val1'
assert api.option('val1.val2', 1).value.get() == 'val2' assert api.option('val1.val2', 1).value.get() == 'val2'
@ -1020,6 +1019,7 @@ def test_callback_hidden():
api = getapi(Config(maconfig)) api = getapi(Config(maconfig))
api.property.read_write() api.property.read_write()
raises(PropertiesOptionError, "api.option('od1.opt1').value.get()") raises(PropertiesOptionError, "api.option('od1.opt1').value.get()")
# do not raise, forcepermissive
api.option('od2.opt2').value.get() api.option('od2.opt2').value.get()

View file

@ -5,7 +5,7 @@ do_autopath()
from py.test import raises from py.test import raises
try: try:
from tiramisu.setting import ConfigBag from tiramisu.setting import OptionBag, ConfigBag
tiramisu_version = 3 tiramisu_version = 3
except: except:
tiramisu_version = 2 tiramisu_version = 2
@ -151,10 +151,12 @@ def test_slots_config():
c = Config(od2) c = Config(od2)
raises(AttributeError, "c.x = 1") raises(AttributeError, "c.x = 1")
raises(AttributeError, "c.cfgimpl_x = 1") raises(AttributeError, "c.cfgimpl_x = 1")
if tiramisu_version == 2: option_bag = OptionBag()
sc = c.getattr('a') option_bag.set_option(od2,
else: 'a',
sc = c.getattr('a', None, ConfigBag(c)) None,
ConfigBag(c))
sc = c.getattr('a', option_bag)
assert isinstance(sc, SubConfig) assert isinstance(sc, SubConfig)
raises(AttributeError, "sc.x = 1") raises(AttributeError, "sc.x = 1")
raises(AttributeError, "sc.cfgimpl_x = 1") raises(AttributeError, "sc.cfgimpl_x = 1")

View file

@ -22,7 +22,7 @@ from typing import List, Any, Optional, Callable, Union, Dict
from .error import APIError, ConfigError, SlaveError, PropertiesOptionError from .error import APIError, ConfigError, SlaveError, PropertiesOptionError
from .i18n import _ from .i18n import _
from .setting import ConfigBag, owners, Undefined, undefined, FORBIDDEN_SET_PROPERTIES from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, FORBIDDEN_SET_PROPERTIES
from .config import Config, SubConfig, GroupConfig, MetaConfig from .config import Config, SubConfig, GroupConfig, MetaConfig
from .option import ChoiceOption from .option import ChoiceOption
@ -102,35 +102,36 @@ class TiramisuHelp:
options.append(self.tmpl_help.format(space, self.icon, root + 'unrestraint', _('access to option without property restriction'))) options.append(self.tmpl_help.format(space, self.icon, root + 'unrestraint', _('access to option without property restriction')))
options.append(self.tmpl_help.format(space, self.icon, root + 'forcepermissive', _('access to option without verifying permissive property'))) options.append(self.tmpl_help.format(space, self.icon, root + 'forcepermissive', _('access to option without verifying permissive property')))
root = '[unrestraint.|forcepermissive.]' root = '[unrestraint.|forcepermissive.]'
modules = list(self.registers.keys()) if 'registers' in dir(self):
modules.sort() modules = list(self.registers.keys())
for module_name in modules: modules.sort()
module = self.registers[module_name] for module_name in modules:
instance_module = module(None) module = self.registers[module_name]
if isinstance(instance_module, TiramisuDispatcher): instance_module = module(None)
if _valid and not getdoc(module.__call__): # pragma: no cover if isinstance(instance_module, TiramisuDispatcher):
raise Exception('unknown doc for {}'.format('__call__')) if _valid and not getdoc(module.__call__): # pragma: no cover
module_doc = _(getdoc(module.__call__)) raise Exception('unknown doc for {}'.format('__call__'))
module_signature = signature(module.__call__) module_doc = _(getdoc(module.__call__))
module_args = [str(module_signature.parameters[key]) for key in list(module_signature.parameters.keys())[1:]] module_signature = signature(module.__call__)
module_args = '(' + ', '.join(module_args) + ')' module_args = [str(module_signature.parameters[key]) for key in list(module_signature.parameters.keys())[1:]]
options.append(self.tmpl_help.format(space, self.icon, root + module_name + module_args, module_doc)) module_args = '(' + ', '.join(module_args) + ')'
if hasattr(module, 'subhelp'): options.append(self.tmpl_help.format(space, self.icon, root + module_name + module_args, module_doc))
instance_submodule = module.subhelp(None, None, None, None, None) if hasattr(module, 'subhelp'):
options.extend(instance_submodule.help(init=False, space=space + ' ', root=root + module_name + module_args + '.')) instance_submodule = module.subhelp(None, None, None, None, None)
else: options.extend(instance_submodule.help(init=False, space=space + ' ', root=root + module_name + module_args + '.'))
root = root + '[config(path).]' else:
if isinstance(instance_module, CommonTiramisuOption): root = root + '[config(path).]'
if _valid and not getdoc(module): # pragma: no cover if isinstance(instance_module, CommonTiramisuOption):
raise Exception('unknown doc for {}'.format(module.__class__.__name__)) if _valid and not getdoc(module): # pragma: no cover
module_doc = _(getdoc(module)) raise Exception('unknown doc for {}'.format(module.__class__.__name__))
options.append(self.tmpl_help.format(space, self.icon, root + module_name, module_doc)) module_doc = _(getdoc(module))
if isinstance(instance_module, TiramisuContext): options.append(self.tmpl_help.format(space, self.icon, root + module_name, module_doc))
if _valid and not getdoc(module): # pragma: no cover if isinstance(instance_module, TiramisuContext):
raise Exception('unknown doc for {}'.format(module.__class__.__name__)) if _valid and not getdoc(module): # pragma: no cover
module_doc = _(getdoc(module)) raise Exception('unknown doc for {}'.format(module.__class__.__name__))
options.append(self.tmpl_help.format(space, self.icon, root + module_name, module_doc)) module_doc = _(getdoc(module))
options.extend(instance_module.help(init=False, space=space + ' ', root=root + '{}.'.format(module_name))) options.append(self.tmpl_help.format(space, self.icon, root + module_name, module_doc))
options.extend(instance_module.help(init=False, space=space + ' ', root=root + '{}.'.format(module_name)))
funcs = dir(self) funcs = dir(self)
funcs.sort() funcs.sort()
@ -159,20 +160,21 @@ class CommonTiramisu(TiramisuHelp):
registers = {} registers = {}
def _get_option(self) -> Any: def _get_option(self) -> Any:
option = self.config_bag.option option = self.option_bag.option
if option is None: if option is None:
option = self.subconfig.cfgimpl_get_description().impl_getchild(self._name, option = self.subconfig.cfgimpl_get_description().impl_getchild(self._name,
self.config_bag, self.config_bag,
self.subconfig) self.subconfig)
self.config_bag.option = option self.option_bag.set_option(option,
self._path,
self.index,
self.config_bag)
if self.config_bag.setting_properties: if self.config_bag.setting_properties:
self.config_bag.config.cfgimpl_get_settings().validate_properties(self._path, self.config_bag.config.cfgimpl_get_settings().validate_properties(self.option_bag)
self.index,
self.config_bag)
if self.index is not None: if self.index is not None:
if option.impl_is_optiondescription() or not option.impl_is_master_slaves('slave'): if option.impl_is_optiondescription() or not option.impl_is_master_slaves('slave'):
raise APIError('index must be set only with a slave option') raise APIError('index must be set only with a slave option')
self._length = self.subconfig.cfgimpl_get_length_slave(option, self.config_bag) self._length = self.subconfig.cfgimpl_get_length_slave(self.option_bag)
if self.index >= self._length: if self.index >= self._length:
raise SlaveError(_('index "{}" is higher than the master length "{}" ' raise SlaveError(_('index "{}" is higher than the master length "{}" '
'for option "{}"').format(self.index, 'for option "{}"').format(self.index,
@ -188,14 +190,16 @@ class CommonTiramisuOption(CommonTiramisu):
slave_need_index = True slave_need_index = True
def __init__(self, def __init__(self,
name: Optional[str], name: str,
path: Optional[str]=None, path: str,
index: Optional[int]=None, index: int,
subconfig: Any=None, subconfig: Union[Config, SubConfig],
config_bag: Optional[ConfigBag]=None) -> None: config_bag: ConfigBag,
option_bag: OptionBag) -> None:
self._path = path self._path = path
self.index = index self.index = index
self.config_bag = config_bag self.config_bag = config_bag
self.option_bag = option_bag
self._name = name self._name = name
self.subconfig = subconfig self.subconfig = subconfig
if config_bag is not None and self.slave_need_index: if config_bag is not None and self.slave_need_index:
@ -310,7 +314,8 @@ class TiramisuOptionOption(CommonTiramisuOption):
return option.impl_getrequires() return option.impl_getrequires()
def __getattr__(self, name: str) -> Callable: def __getattr__(self, name: str) -> Callable:
if not self._get_option().impl_is_optiondescription() and name != 'get_option': #if not self._get_option().impl_is_optiondescription() and name != 'get_option':
if not self._get_option().impl_is_optiondescription():
subkey = '_' + name subkey = '_' + name
if subkey in dir(self): if subkey in dir(self):
func = getattr(self, subkey) func = getattr(self, subkey)
@ -327,17 +332,19 @@ class TiramisuOptionOwner(CommonTiramisuOption):
"""manager option's owner""" """manager option's owner"""
def __init__(self, def __init__(self,
name: Optional[str], name: str,
path: Optional[str]=None, path: str,
index: Optional[int]=None, index: int,
subconfig: Union[None, Config, SubConfig]=None, subconfig: Union[Config, SubConfig],
config_bag: Optional[ConfigBag]=None) -> None: config_bag: ConfigBag,
option_bag: OptionBag) -> None:
super().__init__(name, super().__init__(name,
path, path,
index, index,
subconfig, subconfig,
config_bag) config_bag,
option_bag)
if config_bag: if config_bag:
self.values = self.config_bag.config.cfgimpl_get_values() self.values = self.config_bag.config.cfgimpl_get_values()
@ -345,17 +352,13 @@ class TiramisuOptionOwner(CommonTiramisuOption):
def get(self): def get(self):
"""get owner for a specified option""" """get owner for a specified option"""
option = self._get_option() option = self._get_option()
return self.values.getowner(self._path, return self.values.getowner(self.option_bag)
self.index,
self.config_bag)
@count @count
def isdefault(self): def isdefault(self):
"""is option has defaut value""" """is option has defaut value"""
self._get_option() self._get_option()
return self.values.is_default_owner(self._path, return self.values.is_default_owner(self.option_bag)
self.index,
self.config_bag)
@count @count
def set(self, owner): def set(self, owner):
@ -369,10 +372,8 @@ class TiramisuOptionOwner(CommonTiramisuOption):
except AttributeError: except AttributeError:
owners.addowner(owner) owners.addowner(owner)
obj_owner = getattr(owners, owner) obj_owner = getattr(owners, owner)
self.values.setowner(self._path, self.values.setowner(obj_owner,
self.index, self.option_bag)
obj_owner,
self.config_bag)
class TiramisuOptionProperty(CommonTiramisuOption): class TiramisuOptionProperty(CommonTiramisuOption):
@ -381,16 +382,18 @@ class TiramisuOptionProperty(CommonTiramisuOption):
slave_need_index = False slave_need_index = False
def __init__(self, def __init__(self,
name: Optional[str], name: str,
path: Optional[str]=None, path: str,
index: Optional[int]=None, index: int,
subconfig: Union[None, Config, SubConfig]=None, subconfig: Union[Config, SubConfig],
config_bag: Optional[ConfigBag]=None) -> None: config_bag: ConfigBag,
option_bag: OptionBag) -> None:
super().__init__(name, super().__init__(name,
path, path,
index, index,
subconfig, subconfig,
config_bag) config_bag,
option_bag)
if config_bag: if config_bag:
self.settings = config_bag.config.cfgimpl_get_settings() self.settings = config_bag.config.cfgimpl_get_settings()
@ -400,12 +403,9 @@ class TiramisuOptionProperty(CommonTiramisuOption):
self._get_option() self._get_option()
if apply_requires: if apply_requires:
self._test_slave_index() self._test_slave_index()
properties = self.settings.getproperties(self._path, else:
self.index, self.option_bag.apply_requires = False
self.config_bag, properties = self.option_bag.properties
apply_requires)
if TIRAMISU_VERSION == 2:
properties = properties.get()
return set(properties) return set(properties)
@count @count
@ -415,33 +415,27 @@ class TiramisuOptionProperty(CommonTiramisuOption):
if prop in FORBIDDEN_SET_PROPERTIES: if prop in FORBIDDEN_SET_PROPERTIES:
raise ConfigError(_('cannot add this property: "{0}"').format( raise ConfigError(_('cannot add this property: "{0}"').format(
' '.join(prop))) ' '.join(prop)))
props = self.settings.getproperties(self._path, props = self.settings.getproperties(self.option_bag,
None,
self.config_bag,
apply_requires=False) apply_requires=False)
self.settings.setproperties(self._path, self.settings.setproperties(self._path,
props | {prop}, props | {prop},
self.config_bag) self.option_bag)
@count @count
def pop(self, prop): def pop(self, prop):
"""remove new property for an option""" """remove new property for an option"""
self._get_option() self._get_option()
props = self.settings.getproperties(self._path, props = self.settings.getproperties(self.option_bag,
self.index,
self.config_bag,
apply_requires=False) apply_requires=False)
self.settings.setproperties(self._path, self.settings.setproperties(self._path,
props - {prop}, props - {prop},
self.config_bag) self.option_bag)
@count @count
def reset(self): def reset(self):
"""reset all personalised properties""" """reset all personalised properties"""
self._get_option() self._get_option()
self.settings.reset(self.config_bag.option, self.settings.reset(self.option_bag)
self._path,
self.config_bag)
class TiramisuOptionPermissive(CommonTiramisuOption): class TiramisuOptionPermissive(CommonTiramisuOption):
@ -450,16 +444,18 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
slave_need_index = False slave_need_index = False
def __init__(self, def __init__(self,
name: Optional[str], name: str,
path: Optional[str]=None, path: str,
index: Optional[int]=None, index: int,
subconfig: Union[None, Config, SubConfig]=None, subconfig: Union[Config, SubConfig],
config_bag: Optional[ConfigBag]=None) -> None: config_bag: ConfigBag,
option_bag: OptionBag) -> None:
super().__init__(name, super().__init__(name,
path, path,
index, index,
subconfig, subconfig,
config_bag) config_bag,
option_bag)
if config_bag: if config_bag:
self.settings = config_bag.config.cfgimpl_get_settings() self.settings = config_bag.config.cfgimpl_get_settings()
@ -475,21 +471,9 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
@count @count
def set(self, permissives): def set(self, permissives):
"""set permissives value""" """set permissives value"""
if TIRAMISU_VERSION == 2: self._get_option()
permissives = tuple(permissives) self.settings.setpermissive(self.option_bag,
path = self._path permissives=permissives)
opt = self._opt
self.settings.setpermissive(opt=opt,
path=path,
config_bag=self.config_bag,
permissive=permissives)
else:
path = self._path
opt = self._get_option()
self.settings.setpermissive(opt=opt,
path=path,
config_bag=self.config_bag,
permissives=permissives)
@count @count
def reset(self): def reset(self):
@ -526,12 +510,10 @@ class TiramisuOptionValue(CommonTiramisuOption):
@count @count
def get(self): def get(self):
"""get option's value""" """get option's value"""
self._get_option()
self._test_slave_index() self._test_slave_index()
settings = self.config_bag.config.cfgimpl_get_settings() settings = self.config_bag.config.cfgimpl_get_settings()
value = self.subconfig.getattr(self._name, value = self.subconfig.getattr(self._name,
self.index, self.option_bag)
self.config_bag)
#if isinstance(value, Multi): #if isinstance(value, Multi):
# value = list(value) # value = list(value)
return value return value
@ -545,35 +527,35 @@ class TiramisuOptionValue(CommonTiramisuOption):
if isinstance(value, list): if isinstance(value, list):
while undefined in value: while undefined in value:
idx = value.index(undefined) idx = value.index(undefined)
value[idx] = values.getdefaultvalue(self._path, option_bag = OptionBag()
idx, option_bag.set_option(self.option_bag.option,
self.config_bag) self.option_bag.path,
idx,
self.config_bag)
value[idx] = values.getdefaultvalue(option_bag)
else: else:
if value == undefined: if value == undefined:
value = values.getdefaultvalue(self._path, value = values.getdefaultvalue(self.option_bag)
self.index, self.subconfig.setattr(value,
self.config_bag) self.option_bag)
self.subconfig.setattr(self._name,
self.index,
value,
self.config_bag)
@count @count
def _pop(self, index): def _pop(self, index):
"""pop value for a master option (only for master option)""" """pop value for a master option (only for master option)"""
self._get_option() self._get_option()
self.config_bag.config.delattr(self._path, if self.option_bag.option.impl_is_symlinkoption():
index, raise TypeError(_("can't delete a SymLinkOption"))
self.config_bag) self.config_bag.config.cfgimpl_get_values().reset_master(index,
self.option_bag,
self.subconfig)
@count @count
def reset(self): def reset(self):
"""reset value for a value""" """reset value for a value"""
self._get_option() self._get_option()
self._test_slave_index() self._test_slave_index()
self.config_bag.config.delattr(self._path, #self.config_bag.config.delattr(self.option_bag)
self.index, self.subconfig.delattr(self.option_bag)
self.config_bag)
@count @count
def _len_master(self): def _len_master(self):
@ -590,7 +572,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
option = self._get_option() option = self._get_option()
# for example if index is None # for example if index is None
if '_length' not in vars(self): if '_length' not in vars(self):
self._length = self.subconfig.cfgimpl_get_length_slave(option, self.config_bag) self._length = self.subconfig.cfgimpl_get_length_slave(self.option_bag)
return self._length return self._length
def __getattr__(self, name: str) -> Callable: def __getattr__(self, name: str) -> Callable:
@ -608,7 +590,8 @@ class TiramisuOptionValue(CommonTiramisuOption):
@count @count
def _list(self): def _list(self):
"""all values available for an option (only for choiceoption)""" """all values available for an option (only for choiceoption)"""
return self.config_bag.option.impl_get_values(self.config_bag) self._get_option()
return self._get_option().impl_get_values(self.option_bag)
def registers(registers: Dict[str, type], prefix: str) -> None: def registers(registers: Dict[str, type], prefix: str) -> None:
@ -620,19 +603,27 @@ def registers(registers: Dict[str, type], prefix: str) -> None:
class TiramisuOption(CommonTiramisu): class TiramisuOption(CommonTiramisu):
registers = {}
def __init__(self, def __init__(self,
name: Optional[str], name: Optional[str],
path: Optional[str]=None, path: Optional[str]=None,
index: Optional[int]=None, index: Optional[int]=None,
subconfig: Union[None, Config, SubConfig]=None, subconfig: Union[None, Config, SubConfig]=None,
config_bag: Optional[ConfigBag]=None) -> None: config_bag: Optional[ConfigBag]=None,
option_bag: Optional[OptionBag]=None) -> None:
self._name = name self._name = name
self.subconfig = subconfig self.subconfig = subconfig
if subconfig == None:
raise Exception()
self._path = path self._path = path
self.index = index self.index = index
self.config_bag = config_bag self.config_bag = config_bag
self.registers = {} if option_bag:
registers(self.registers, self.__class__.__name__) self.option_bag = option_bag
else:
self.option_bag = OptionBag()
if not self.registers:
registers(self.registers, self.__class__.__name__)
def __getattr__(self, subfunc: str) -> Any: def __getattr__(self, subfunc: str) -> Any:
if subfunc in self.registers: if subfunc in self.registers:
@ -640,11 +631,14 @@ class TiramisuOption(CommonTiramisu):
self._path, self._path,
self.index, self.index,
self.subconfig, self.subconfig,
self.config_bag) self.config_bag,
self.option_bag)
elif subfunc == 'make_dict' and self._get_option().impl_is_optiondescription(): elif subfunc == 'make_dict' and self._get_option().impl_is_optiondescription():
return self._make_dict return self._make_dict
elif subfunc == 'find' and self._get_option().impl_is_optiondescription(): elif subfunc == 'find' and self._get_option().impl_is_optiondescription():
return self._find return self._find
elif subfunc == 'get' and self._get_option().impl_is_optiondescription():
return self._get
elif subfunc == 'list' and self._get_option().impl_is_optiondescription(): elif subfunc == 'list' and self._get_option().impl_is_optiondescription():
return self._list return self._list
elif subfunc == 'group_type' and self._get_option().impl_is_optiondescription(): elif subfunc == 'group_type' and self._get_option().impl_is_optiondescription():
@ -659,9 +653,9 @@ class TiramisuOption(CommonTiramisu):
withoption=None, withoption=None,
fullpath=False): fullpath=False):
"""return dict with path as key and value for an optiondescription (only for optiondescription)""" """return dict with path as key and value for an optiondescription (only for optiondescription)"""
self._get_option()
return self.config_bag.config.getattr(self._path, return self.config_bag.config.getattr(self._path,
None, self.option_bag).make_dict(config_bag=self.config_bag,
self.config_bag).make_dict(config_bag=self.config_bag,
flatten=flatten, flatten=flatten,
fullpath=fullpath, fullpath=fullpath,
withoption=withoption, withoption=withoption,
@ -680,19 +674,42 @@ class TiramisuOption(CommonTiramisu):
bytype=type, bytype=type,
_subpath=self._path, _subpath=self._path,
config_bag=self.config_bag): config_bag=self.config_bag):
config_bag = self.config_bag.copy('nooption') subconfig, name = self.config_bag.config.cfgimpl_get_home_by_path(path,
subconfig, name = config_bag.config.cfgimpl_get_home_by_path(path, self.config_bag)
config_bag)
t_option = TiramisuOption(name, t_option = TiramisuOption(name,
path, path,
None, # index for a slave ? None, # index for a slave ?
subconfig, subconfig,
config_bag) self.config_bag)
if first: if first:
return t_option return t_option
ret.append(t_option) ret.append(t_option)
return ret return ret
@count
def _get(self, name):
self._get_option()
current_option = self.option_bag.option.impl_getchild(name,
self.config_bag,
self.subconfig)
path = self.option_bag.path + '.' + name
option_bag= OptionBag()
option_bag.set_option(current_option,
path,
None,
self.config_bag)
if current_option.impl_is_optiondescription():
subconfig = self.subconfig.getattr(name,
option_bag)
else:
subconfig = self.subconfig
return TiramisuOption(name,
path,
None,
subconfig,
self.config_bag,
option_bag)
@count @count
def _group_type(self): def _group_type(self):
"""get type for an optiondescription (only for optiondescription)""" """get type for an optiondescription (only for optiondescription)"""
@ -703,26 +720,57 @@ class TiramisuOption(CommonTiramisu):
type='all', type='all',
group_type=None): group_type=None):
"""list options in an optiondescription (only for optiondescription)""" """list options in an optiondescription (only for optiondescription)"""
if type == 'optiondescription': if type not in ('all', 'optiondescription'):
return self.config_bag.config.getattr(self._path,
None,
self.config_bag
).iter_groups(self.config_bag, group_type)
elif type == 'all':
return self.config_bag.config.getattr(self._path,
None,
self.config_bag
).cfgimpl_get_children(self.config_bag)
else:
raise APIError(_('unknown list type {}').format(type)) raise APIError(_('unknown list type {}').format(type))
if group_type is not None and not isinstance(group_type,
groups.GroupType):
raise TypeError(_("unknown group_type: {0}").format(group_type))
def _filter(opt):
if not self.config_bag.force_unrestraint:
name = opt.impl_getname()
path = subconfig._get_subpath(name)
option_bag = OptionBag()
option_bag.set_option(opt,
path,
None,
self.config_bag)
self.subconfig.getattr(name,
option_bag)
option = self._get_option()
name = option.impl_getname()
path = self.subconfig._get_subpath(name)
option_bag = OptionBag()
option_bag.set_option(option,
path,
None,
self.config_bag)
subconfig = self.subconfig.getattr(name,
option_bag)
for opt in option.impl_getchildren(self.config_bag):
try:
subsubconfig = _filter(opt)
except PropertiesOptionError:
continue
if opt.impl_is_optiondescription():
if type == 'optiondescription' and \
(group_type and opt.impl_get_group_type() != group_type):
continue
else:
if type == 'optiondescription':
continue
name = opt.impl_getname()
yield TiramisuOption(name,
subconfig._get_subpath(name),
None,
subconfig,
self.config_bag)
class TiramisuContext(TiramisuHelp): class TiramisuContext(TiramisuHelp):
def __init__(self, def __init__(self,
config_bag: Optional[ConfigBag]) -> None: config_bag: Optional[ConfigBag]) -> None:
self.config_bag = config_bag self.config_bag = config_bag
self.registers = {}
registers(self.registers, self.__class__.__name__)
class TiramisuContextInformation(TiramisuContext): class TiramisuContextInformation(TiramisuContext):
@ -778,7 +826,8 @@ class TiramisuContextValue(TiramisuContext):
def reset(self, def reset(self,
path): path):
"""reset value for a GroupConfig or a MetaConfig""" """reset value for a GroupConfig or a MetaConfig"""
self.config_bag.config.reset(path, self.config_bag) self.config_bag.config.reset(path,
self.config_bag)
@count @count
def exportation(self): def exportation(self):
@ -789,7 +838,7 @@ class TiramisuContextValue(TiramisuContext):
def importation(self, values): def importation(self, values):
"""import values""" """import values"""
self.config_bag.config.cfgimpl_get_values()._p_.importation(values) self.config_bag.config.cfgimpl_get_values()._p_.importation(values)
self.config_bag.config.cfgimpl_reset_cache(None, None, None) self.config_bag.config.cfgimpl_reset_cache(None, None)
class TiramisuContextOwner(TiramisuContext): class TiramisuContextOwner(TiramisuContext):
@ -819,7 +868,10 @@ class TiramisuContextProperty(TiramisuContext):
"""set configuration to read only mode""" """set configuration to read only mode"""
settings = self.config_bag.config.cfgimpl_get_settings() settings = self.config_bag.config.cfgimpl_get_settings()
settings.read_only() settings.read_only()
self.config_bag.delete('setting_properties') try:
del self.config_bag.setting_properties
except AttributeError:
pass
@count @count
def read_write(self): def read_write(self):
@ -828,7 +880,10 @@ class TiramisuContextProperty(TiramisuContext):
settings.read_write() settings.read_write()
# #FIXME ? # #FIXME ?
settings.set_context_permissive(frozenset(['hidden'])) settings.set_context_permissive(frozenset(['hidden']))
self.config_bag.delete('setting_properties') try:
del self.config_bag.setting_properties
except AttributeError:
pass
#/FIXME ? #/FIXME ?
@count @count
@ -859,9 +914,7 @@ class TiramisuContextProperty(TiramisuContext):
@count @count
def reset(self): def reset(self):
"""remove configuration properties""" """remove configuration properties"""
self.config_bag.config.cfgimpl_get_settings().reset(None, self.config_bag.config.cfgimpl_get_settings().reset(None)
None,
None)
@count @count
def exportation(self): def exportation(self):
@ -872,7 +925,8 @@ class TiramisuContextProperty(TiramisuContext):
def importation(self, properties): def importation(self, properties):
"""import configuration properties""" """import configuration properties"""
self.config_bag.config.cfgimpl_get_settings()._p_.importation(properties) self.config_bag.config.cfgimpl_get_settings()._p_.importation(properties)
self.config_bag.config.cfgimpl_reset_cache(None, None, None) self.config_bag.config.cfgimpl_reset_cache(None,
None)
class TiramisuContextPermissive(TiramisuContext): class TiramisuContextPermissive(TiramisuContext):
@ -897,7 +951,8 @@ class TiramisuContextPermissive(TiramisuContext):
def importation(self, permissives): def importation(self, permissives):
"""import configuration permissives""" """import configuration permissives"""
self.config_bag.config.cfgimpl_get_settings()._pp_.importation(permissives) self.config_bag.config.cfgimpl_get_settings()._pp_.importation(permissives)
self.config_bag.config.cfgimpl_reset_cache(None, None, None) self.config_bag.config.cfgimpl_reset_cache(None,
None)
@ -918,28 +973,28 @@ class TiramisuContextOption(TiramisuContext):
bytype=type, bytype=type,
#_subpath=self._path, #_subpath=self._path,
config_bag=self.config_bag): config_bag=self.config_bag):
config_bag = self.config_bag.copy('nooption') subconfig, name = self.config_bag.config.cfgimpl_get_home_by_path(path,
subconfig, name = config_bag.config.cfgimpl_get_home_by_path(path, self.config_bag)
config_bag)
t_option = TiramisuOption(name, t_option = TiramisuOption(name,
path, path,
None, # index for a slave ? None, # index for a slave ?
subconfig, subconfig,
config_bag) self.config_bag)
if first: if first:
return t_option return t_option
ret.append(t_option) ret.append(t_option)
return ret return ret
#@count @count
#def get(self, path): def get(self, name):
# """""" option = self.config_bag.config.cfgimpl_get_description().impl_getchild(name,
# config_bag = self.config_bag.copy() self.config_bag,
# config_bag.validate = False self.config_bag.config)
# config_bag.force_unrestraint = True return TiramisuOption(name,
# config_bag.setting_properties = None name,
# return self.config_bag.config.unwrap_from_path(path, None,
# config_bag) self.config_bag.config,
self.config_bag)
@count @count
def make_dict(self, def make_dict(self,
@ -960,11 +1015,24 @@ class TiramisuContextOption(TiramisuContext):
group_type=None, group_type=None,
recursive=False): recursive=False):
"""list content of an optiondescription""" """list content of an optiondescription"""
# FIXME should return TiramisuOption !!!
if group_type is not None and not isinstance(group_type,
groups.GroupType):
raise TypeError(_("unknown group_type: {0}").format(group_type))
if type == 'optiondescription': if type == 'optiondescription':
if recursive: if recursive:
raise APIError(_('not implemented yet')) raise APIError(_('not implemented yet'))
else: else:
return self.config_bag.config.iter_groups(self.config_bag, group_type) if not self.config_bag.force_unrestraint:
option = self.config_bag.config.cfgimpl_get_description()
for opt in option.impl_getchildren(self.config_bag):
if type == 'optiondescription' and not opt.impl_is_optiondescription():
continue
yield opt.impl_getname()
else:
# FIXME itergroups !!!
return self.config_bag.config.iter_groups(self.config_bag, group_type)
elif type == 'all': elif type == 'all':
if group_type: if group_type:
raise APIError(_('not implemented yet')) raise APIError(_('not implemented yet'))
@ -998,68 +1066,80 @@ class TiramisuDispatcher:
pass pass
class TiramisuAPI(TiramisuHelp):
registers = {}
def __init__(self,
config: Union[Config, GroupConfig, MetaConfig, ConfigBag]) -> None:
self._config = config
if not self.registers:
registers(self.registers, 'TiramisuContext')
registers(self.registers, 'TiramisuDispatcher')
def __getattr__(self, subfunc: str) -> Any:
if subfunc == 'forcepermissive':
if isinstance(self._config, ConfigBag):
config = self._config.config
force = self._config.force_unrestraint
else:
config = self._config
force = None
config_bag = ConfigBag(config=config,
force_permissive=True)
if force is not None:
config_bag.force_unrestraint = force
return TiramisuAPI(config_bag)
elif subfunc == 'unrestraint':
if isinstance(self._config, ConfigBag):
config = self._config.config
force = self._config.force_permissive
else:
config = self._config
force = None
config_bag = ConfigBag(config=config,
force_unrestraint=True)
if force is not None:
config_bag.force_permissive = force
return TiramisuAPI(config_bag)
elif subfunc in self.registers:
if not isinstance(self._config, ConfigBag):
config_bag = ConfigBag(config=self._config)
else:
config_bag = self._config
return self.registers[subfunc](config_bag)
else:
raise APIError(_('please specify a valid sub function ({})').format(subfunc))
class TiramisuDispatcherConfig(TiramisuDispatcher, TiramisuContextConfig): class TiramisuDispatcherConfig(TiramisuDispatcher, TiramisuContextConfig):
def __call__(self, path: Optional[str]): def __call__(self,
path: Optional[str]) -> TiramisuAPI:
"""select a child Tiramisu configuration (only with MetaConfig or GroupConfig)""" """select a child Tiramisu configuration (only with MetaConfig or GroupConfig)"""
config = self.config_bag.config
if path is None: if path is None:
return TiramisuAPI(config, return TiramisuAPI(self.config_bag)
force_permissive=self.config_bag.force_permissive,
force_unrestraint=self.config_bag.force_unrestraint)
spaths = path.split('.') spaths = path.split('.')
config = self.config_bag.config
for spath in spaths: for spath in spaths:
config = config.getconfig(spath) config = config.getconfig(spath)
return TiramisuAPI(config, config_bag = ConfigBag(config=config,
force_permissive=self.config_bag.force_permissive, force_unrestraint=self.config_bag.force_unrestraint,
force_unrestraint=self.config_bag.force_unrestraint) force_permissive=self.config_bag.force_permissive)
return TiramisuAPI(config_bag)
class TiramisuDispatcherOption(TiramisuDispatcher, TiramisuContextOption): class TiramisuDispatcherOption(TiramisuDispatcher, TiramisuContextOption):
subhelp = TiramisuOption subhelp = TiramisuOption
def __call__(self, path: str, index: Optional[int]=None) -> TiramisuOption: def __call__(self,
path: str,
index: Optional[int]=None) -> TiramisuOption:
"""select a option (index only for slave option)""" """select a option (index only for slave option)"""
config_bag = self.config_bag.copy() subconfig, name = self.config_bag.config.cfgimpl_get_home_by_path(path,
validate = not config_bag.force_unrestraint self.config_bag)
if not validate:
config_bag.setting_properties = None
subconfig, name = config_bag.config.cfgimpl_get_home_by_path(path,
config_bag)
return TiramisuOption(name, return TiramisuOption(name,
path, path,
index, index,
subconfig, subconfig,
config_bag) self.config_bag)
class TiramisuAPI(TiramisuHelp):
def __init__(self,
config: Union[Config, GroupConfig, MetaConfig],
force_permissive: bool=False,
force_unrestraint: bool=False) -> None:
self._config = config
self.force_permissive = force_permissive
self.force_unrestraint = force_unrestraint
self.registers = {}
registers(self.registers, 'TiramisuContext')
registers(self.registers, 'TiramisuDispatcher')
def __getattr__(self, subfunc: str) -> Any:
if subfunc == 'forcepermissive':
return TiramisuAPI(config=self._config,
force_permissive=True,
force_unrestraint=self.force_unrestraint)
elif subfunc == 'unrestraint':
return TiramisuAPI(config=self._config,
force_permissive=self.force_permissive,
force_unrestraint=True)
elif subfunc in self.registers:
config_bag = ConfigBag(config=self._config,
force_permissive=self.force_permissive,
force_unrestraint=self.force_unrestraint)
return self.registers[subfunc](config_bag)
else:
raise APIError(_('please specify a valid sub function ({})').format(subfunc))
@count @count

View file

@ -23,7 +23,7 @@ from typing import Any, Optional, Union, Callable, Dict, List
from .error import PropertiesOptionError, ConfigError, SlaveError from .error import PropertiesOptionError, ConfigError, SlaveError
from .i18n import _ from .i18n import _
from .setting import undefined, ConfigBag, Undefined from .setting import undefined, ConfigBag, OptionBag, Undefined
from .option.symlinkoption import DynSymLinkOption from .option.symlinkoption import DynSymLinkOption
from .storage import get_default_values_storages, get_default_settings_storages from .storage import get_default_values_storages, get_default_settings_storages
from .function import ParamValue, ParamContext, ParamIndex, ParamOption, Params from .function import ParamValue, ParamContext, ParamIndex, ParamOption, Params
@ -34,7 +34,7 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
option, option,
index: Optional[int], index: Optional[int],
orig_value, orig_value,
config_bag: ConfigBag, option_bag: OptionBag,
context) -> Any: context) -> Any:
"""replace Param by true value""" """replace Param by true value"""
if isinstance(callbk, ParamValue): if isinstance(callbk, ParamValue):
@ -55,10 +55,6 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
path = opt.impl_getpath(context) path = opt.impl_getpath(context)
else: else:
path = context.cfgimpl_get_description().impl_get_path_by_opt(opt) path = context.cfgimpl_get_description().impl_get_path_by_opt(opt)
# don't validate if option is option that we tried to validate
sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = opt
sconfig_bag.force_permissive = True
if index is not None and opt.impl_is_master_slaves() and \ if index is not None and opt.impl_is_master_slaves() and \
opt.impl_get_master_slaves().in_same_group(option): opt.impl_get_master_slaves().in_same_group(option):
if opt == option: if opt == option:
@ -76,15 +72,25 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
if opt == option and orig_value is not undefined and \ if opt == option and orig_value is not undefined and \
(not opt.impl_is_master_slaves('slave') or index is None): (not opt.impl_is_master_slaves('slave') or index is None):
return orig_value return orig_value
# don't validate if option is option that we tried to validate
config_bag = ConfigBag(config=option_bag.config_bag.config,
_setting_properties=option_bag.config_bag._setting_properties,
force_permissive=True,
force_unrestraint=option_bag.config_bag.force_unrestraint,
_validate=option_bag.config_bag._validate)
soption_bag = OptionBag()
soption_bag.set_option(opt,
path,
index_,
config_bag)
soption_bag.fromconsistency = option_bag.fromconsistency.copy()
if opt == option: if opt == option:
sconfig_bag.setting_properties = None soption_bag.config_bag.force_unrestraint = True
sconfig_bag.force_unrestraint= False soption_bag.config_bag.validate = False
sconfig_bag.validate = False
try: try:
# get value # get value
value = context.getattr(path, value = context.getattr(path,
index_, soption_bag)
sconfig_bag)
if with_index: if with_index:
return value[index] return value[index]
return value return value
@ -100,7 +106,7 @@ def carry_out_calculation(option,
callback: Callable, callback: Callable,
callback_params: Optional[Params], callback_params: Optional[Params],
index: Optional[int], index: Optional[int],
config_bag: Optional[ConfigBag], option_bag: Optional[OptionBag],
orig_value=undefined, orig_value=undefined,
is_validator: int=False): is_validator: int=False):
@ -217,7 +223,7 @@ def carry_out_calculation(option,
kwargs = {} kwargs = {}
# if callback_params has a callback, launch several time calculate() # if callback_params has a callback, launch several time calculate()
if option.issubdyn(): if option.issubdyn():
#FIXME why here? should be ParamSuffix ! #FIXME why here? should be a ParamSuffix !
kwargs['suffix'] = option.impl_getsuffix() kwargs['suffix'] = option.impl_getsuffix()
if callback_params: if callback_params:
for callbk in callback_params.args: for callbk in callback_params.args:
@ -226,7 +232,7 @@ def carry_out_calculation(option,
option, option,
index, index,
orig_value, orig_value,
config_bag, option_bag,
context) context)
if value is undefined: if value is undefined:
return undefined return undefined
@ -239,7 +245,7 @@ def carry_out_calculation(option,
option, option,
index, index,
orig_value, orig_value,
config_bag, option_bag,
context) context)
if value is undefined: if value is undefined:
return undefined return undefined

View file

@ -20,7 +20,6 @@
# ____________________________________________________________ # ____________________________________________________________
"options handler global entry point" "options handler global entry point"
import weakref import weakref
from time import time
from copy import copy from copy import copy
@ -29,7 +28,7 @@ from .option.syndynoptiondescription import SynDynOptionDescription
from .option.dynoptiondescription import DynOptionDescription from .option.dynoptiondescription import DynOptionDescription
from .option.masterslave import MasterSlaves from .option.masterslave import MasterSlaves
from .option.baseoption import BaseOption, valid_name from .option.baseoption import BaseOption, valid_name
from .setting import ConfigBag, groups, Settings, undefined from .setting import OptionBag, ConfigBag, groups, Settings, undefined
from .storage import get_storages, get_default_values_storages from .storage import get_storages, get_default_values_storages
from .value import Values # , Multi from .value import Values # , Multi
from .i18n import _ from .i18n import _
@ -50,7 +49,8 @@ class SubConfig(object):
descr, descr,
context, context,
config_bag, config_bag,
subpath=None): subpath=None,
fromconsistency=None):
""" Configuration option management master class """ Configuration option management master class
:param descr: describes the configuration schema :param descr: describes the configuration schema
@ -73,23 +73,38 @@ class SubConfig(object):
descr.impl_get_group_type() == groups.master: descr.impl_get_group_type() == groups.master:
master = descr.getmaster() master = descr.getmaster()
masterpath = master.impl_getname() masterpath = master.impl_getname()
mconfig_bag = config_bag.copy('nooption') full_masterpath = self._get_subpath(masterpath)
mconfig_bag.option = master cconfig_bag = ConfigBag(config=config_bag.config,
mconfig_bag.validate = False _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, value = self.getattr(masterpath,
None, moption_bag)
mconfig_bag)
self._impl_length = len(value) self._impl_length = len(value)
def cfgimpl_get_length(self): def cfgimpl_get_length(self):
return self._impl_length return self._impl_length
def cfgimpl_get_length_slave(self, option, config_bag): def cfgimpl_get_length_slave(self,
if option.impl_is_symlinkoption(): option_bag):
if option_bag.option.impl_is_symlinkoption():
context = self.cfgimpl_get_context() context = self.cfgimpl_get_context()
sconfig_bag = config_bag.copy('nooption') #soption_bag = OptionBag()
subconfig, _ = context.cfgimpl_get_home_by_path(option.impl_getopt().impl_getpath(context), #soption_bag.set_option(option_bag.option.impl_getopt(),
sconfig_bag) # 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() return subconfig.cfgimpl_get_length()
else: else:
return self.cfgimpl_get_length() return self.cfgimpl_get_length()
@ -99,54 +114,65 @@ class SubConfig(object):
values, values,
settings, settings,
resetted_opts, resetted_opts,
config_bag, option_bag):
opt,
path):
if path in resetted_opts: if option_bag.path in resetted_opts:
return return
resetted_opts.append(path) resetted_opts.append(option_bag.path)
for woption in opt._get_dependencies(self): for woption in option_bag.option._get_dependencies(self):
option = woption() option = woption()
if option.impl_is_dynoptiondescription(): if option.impl_is_dynoptiondescription():
for doption in option.get_syndynoptiondescriptions(config_bag): for doption in option.get_syndynoptiondescriptions(option_bag):
doption_path = doption.impl_getpath(self) 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, self.reset_one_option_cache(desc,
values, values,
settings, settings,
resetted_opts, resetted_opts,
config_bag, doption_bag)
doption,
doption_path)
elif option.issubdyn(): elif option.issubdyn():
for doption in desc.build_dynoptions(option, config_bag): 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_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, self.reset_one_option_cache(desc,
values, values,
settings, settings,
resetted_opts, resetted_opts,
config_bag, doption_bag)
doption,
doption_path)
else: else:
option_path = option.impl_getpath(self) 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, self.reset_one_option_cache(desc,
values, values,
settings, settings,
resetted_opts, resetted_opts,
config_bag, doption_bag)
option,
option_path)
del option del option
opt.reset_cache(path, option_bag.option.reset_cache(option_bag.path,
values, values,
settings, settings,
resetted_opts) resetted_opts)
def cfgimpl_reset_cache(self, def cfgimpl_reset_cache(self,
opt, option_bag,
path,
config_bag,
resetted_opts=None): resetted_opts=None):
"""reset all settings in cache """reset all settings in cache
""" """
@ -158,79 +184,40 @@ class SubConfig(object):
values = context.cfgimpl_get_values() values = context.cfgimpl_get_values()
settings = context.cfgimpl_get_settings() settings = context.cfgimpl_get_settings()
if not None in (opt, path): if option_bag is not None:
self.reset_one_option_cache(desc, self.reset_one_option_cache(desc,
values, values,
settings, settings,
resetted_opts, resetted_opts,
config_bag, option_bag)
opt,
path)
else: else:
values._p_.reset_all_cache() values._p_.reset_all_cache()
settings._p_.reset_all_cache() settings._p_.reset_all_cache()
def cfgimpl_get_home_by_path(self, def cfgimpl_get_home_by_path(self,
path, path,
config_bag): config_bag,
fromconsistency=None):
""":returns: tuple (config, name)""" """:returns: tuple (config, name)"""
path = path.split('.') path = path.split('.')
for step in path[:-1]: for step in path[:-1]:
sconfig_bag = config_bag.copy('nooption') 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.getattr(step, self = self.getattr(step,
None, option_bag)
sconfig_bag)
if not isinstance(self, SubConfig): if not isinstance(self, SubConfig):
raise AttributeError(_('unknown option {}').format(path[-1])) raise AttributeError(_('unknown option {}').format(path[-1]))
return self, path[-1] return self, path[-1]
# ______________________________________________________________________
def iter_groups(self,
config_bag,
group_type=None):
"""iteration on groups objects only.
All groups are returned if `group_type` is `None`, otherwise the groups
can be filtered by categories (families, or whatever).
:param group_type: if defined, is an instance of `groups.GroupType`
or `groups.MasterGroupType` that lives in
`setting.groups`
"""
if group_type is not None and not isinstance(group_type,
groups.GroupType):
raise TypeError(_("unknown group_type: {0}").format(group_type))
for child in self.cfgimpl_get_description().impl_getchildren(config_bag):
if child.impl_is_optiondescription():
nconfig_bag = config_bag.copy('nooption')
nconfig_bag.option = child
try:
if group_type is None or (group_type is not None and
child.impl_get_group_type()
== group_type):
name = child.impl_getname()
yield name, self.getattr(name,
None,
nconfig_bag)
except PropertiesOptionError:
pass
def cfgimpl_get_children(self,
config_bag):
context = self.cfgimpl_get_context()
for opt in self.cfgimpl_get_description().impl_getchildren(config_bag):
nconfig_bag = config_bag.copy('nooption')
nconfig_bag.option = opt
name = opt.impl_getname()
if nconfig_bag.setting_properties is not None:
subpath = self._get_subpath(name)
try:
context.cfgimpl_get_settings().validate_properties(subpath,
None,
nconfig_bag)
except PropertiesOptionError:
continue
yield name
# ______________________________________________________________________ # ______________________________________________________________________
def cfgimpl_get_context(self): def cfgimpl_get_context(self):
"""context could be None, we need to test it """context could be None, we need to test it
@ -245,7 +232,7 @@ class SubConfig(object):
def cfgimpl_get_description(self): def cfgimpl_get_description(self):
if self._impl_descr is None: if self._impl_descr is None:
raise ConfigError(_('no option description found for this config' raise ConfigError(_('there is no option description for this config'
' (may be GroupConfig)')) ' (may be GroupConfig)'))
else: else:
return self._impl_descr return self._impl_descr
@ -257,63 +244,39 @@ class SubConfig(object):
return self.cfgimpl_get_context()._impl_values return self.cfgimpl_get_context()._impl_values
def setattr(self, def setattr(self,
name,
index,
value, value,
config_bag, option_bag,
_commit=True): _commit=True):
context = self.cfgimpl_get_context() #self, name = self.cfgimpl_get_home_by_path(option_bag.path,
if '.' in name: # option_bag.config_bag)
# when set_value #if config_bag.option is None:
self, name = self.cfgimpl_get_home_by_path(name, # config_bag.option = self.cfgimpl_get_description().impl_getchild(name,
config_bag) # config_bag,
if config_bag.option is None: # self)
config_bag.option = self.cfgimpl_get_description().impl_getchild(name, if option_bag.option.impl_is_symlinkoption():
config_bag,
self)
if config_bag.option.impl_is_symlinkoption():
raise ConfigError(_("can't assign to a SymLinkOption")) raise ConfigError(_("can't assign to a SymLinkOption"))
else: else:
path = self._get_subpath(name) context = self.cfgimpl_get_context()
if config_bag.setting_properties: if option_bag.config_bag.setting_properties:
context.cfgimpl_get_settings().validate_properties(path, context.cfgimpl_get_settings().validate_properties(option_bag)
index, self.cfgimpl_get_description().impl_validate_value(option_bag.option,
config_bag)
self.cfgimpl_get_description().impl_validate_value(config_bag.option,
value, value,
self) self)
return context.cfgimpl_get_values().setvalue(path, return context.cfgimpl_get_values().setvalue(value,
index, option_bag,
value,
config_bag,
_commit) _commit)
def delattr(self, def delattr(self,
name, option_bag):
index, option = option_bag.option
config_bag):
if '.' in name:
self, name = self.cfgimpl_get_home_by_path(name,
config_bag)
option = config_bag.option
if option.impl_is_symlinkoption(): if option.impl_is_symlinkoption():
raise TypeError(_("can't delete a SymLinkOption")) raise TypeError(_("can't delete a SymLinkOption"))
subpath = self._get_subpath(name)
values = self.cfgimpl_get_values() values = self.cfgimpl_get_values()
if index is not None: if option_bag.index is not None:
if option.impl_is_master_slaves('master'): values.reset_slave(option_bag)
values.reset_master(self,
subpath,
index,
config_bag)
elif option.impl_is_master_slaves('slave'):
values.reset_slave(subpath,
index,
config_bag)
else: else:
values.reset(subpath, values.reset(option_bag)
config_bag)
def _get_subpath(self, name): def _get_subpath(self, name):
if self._impl_path is None: if self._impl_path is None:
@ -324,71 +287,73 @@ class SubConfig(object):
def getattr(self, def getattr(self,
name, name,
index, option_bag):
config_bag):
""" """
attribute notation mechanism for accessing the value of an option attribute notation mechanism for accessing the value of an option
:param name: attribute name :param name: attribute name
:return: option's value if name is an option name, OptionDescription :return: option's value if name is an option name, OptionDescription
otherwise otherwise
""" """
config_bag = option_bag.config_bag
if '.' in name: if '.' in name:
if option_bag.fromconsistency:
fromconsistency = option_bag.fromconsistency.copy()
else:
fromconsistency = None
self, name = self.cfgimpl_get_home_by_path(name, self, name = self.cfgimpl_get_home_by_path(name,
config_bag) config_bag,
fromconsistency)
context = self.cfgimpl_get_context() option = option_bag.option
option = config_bag.option
if option is None:
option = self.cfgimpl_get_description().impl_getchild(name,
config_bag,
self)
config_bag.option = option
if option.impl_is_symlinkoption(): if option.impl_is_symlinkoption():
opt = option.impl_getopt() soption_bag = OptionBag()
path = context.cfgimpl_get_description().impl_get_path_by_opt(opt) soption_bag.set_option(option.impl_getopt(),
sconfig_bag = config_bag.copy('nooption') None,
sconfig_bag.ori_option = option option_bag.index,
sconfig_bag.option = opt config_bag)
return context.getattr(path, soption_bag.ori_option = option
index, context = self.cfgimpl_get_context()
sconfig_bag) return context.getattr(soption_bag.path,
soption_bag)
subpath = self._get_subpath(name)
if config_bag.setting_properties: if config_bag.setting_properties:
self.cfgimpl_get_settings().validate_properties(subpath, self.cfgimpl_get_settings().validate_properties(option_bag)
index,
config_bag)
if option.impl_is_optiondescription(): if option.impl_is_optiondescription():
if option_bag.fromconsistency:
fromconsistency = option_bag.fromconsistency.copy()
else:
fromconsistency = None
return SubConfig(option, return SubConfig(option,
self._impl_context, self._impl_context,
config_bag, config_bag,
subpath) option_bag.path,
fromconsistency)
if option.impl_is_master_slaves('slave'): if option.impl_is_master_slaves('slave'):
length = self.cfgimpl_get_length_slave(option, config_bag) length = self.cfgimpl_get_length_slave(option_bag)
slave_len = self.cfgimpl_get_values()._p_.get_max_length(subpath) slave_len = self.cfgimpl_get_values()._p_.get_max_length(option_bag.path)
if slave_len > length: if slave_len > length:
raise SlaveError(_('slave option "{}" has higher length "{}" than the master ' raise SlaveError(_('slave option "{}" has higher length "{}" than the master '
'length "{}"').format(option.impl_get_display_name(), 'length "{}"').format(option.impl_get_display_name(),
slave_len, slave_len,
length, length,
subpath)) option_bag.index))
if option.impl_is_master_slaves('slave') and index is None: if option.impl_is_master_slaves('slave') and option_bag.index is None:
value = [] value = []
for idx in range(length): for idx in range(length):
config_bag.properties = None 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, value.append(self.getattr(name,
idx, soption_bag))
config_bag))
else: else:
value = self.cfgimpl_get_values().get_cached_value(subpath, value = self.cfgimpl_get_values().get_cached_value(option_bag)
index,
config_bag)
if config_bag.validate_properties: if config_bag.validate_properties:
self.cfgimpl_get_settings().validate_mandatory(subpath, self.cfgimpl_get_settings().validate_mandatory(value,
index, option_bag)
value,
config_bag)
return value return value
def find(self, def find(self,
@ -406,11 +371,10 @@ class SubConfig(object):
:param first: return only one option if True, a list otherwise :param first: return only one option if True, a list otherwise
:return: find list or an exception if nothing has been found :return: find list or an exception if nothing has been found
""" """
def _filter_by_value(sconfig_bag): def _filter_by_value(soption_bag):
try: try:
value = self.getattr(path, value = self.getattr(path,
None, soption_bag)
sconfig_bag)
except PropertiesOptionError: except PropertiesOptionError:
return False return False
if isinstance(value, list): if isinstance(value, list):
@ -427,18 +391,19 @@ class SubConfig(object):
_subpath, _subpath,
config_bag) config_bag)
for path, option in options: for path, option in options:
sconfig_bag = config_bag.copy('nooption') option_bag = OptionBag()
sconfig_bag.option = option option_bag.set_option(option,
if byvalue is not undefined and not _filter_by_value(sconfig_bag): path,
None,
config_bag)
if byvalue is not undefined and not _filter_by_value(option_bag):
continue continue
elif sconfig_bag.validate_properties: elif config_bag.validate_properties:
#remove option with propertyerror, ... #remove option with propertyerror, ...
try: try:
self.unwrap_from_path(path, self.unwrap_from_path(path,
sconfig_bag) config_bag)
self.cfgimpl_get_settings().validate_properties(path, self.cfgimpl_get_settings().validate_properties(option_bag)
None,
sconfig_bag)
except PropertiesOptionError: except PropertiesOptionError:
continue continue
found = True found = True
@ -513,8 +478,11 @@ class SubConfig(object):
path = '.'.join(path.split('.')[:-1]) path = '.'.join(path.split('.')[:-1])
opt = context.unwrap_from_path(path, opt = context.unwrap_from_path(path,
config_bag) config_bag)
sconfig_bag = config_bag.copy('nooption') soption_bag = OptionBag()
sconfig_bag.option = opt soption_bag.set_option(opt,
path,
None,
config_bag)
if mypath is not None: if mypath is not None:
if mypath == path: if mypath == path:
withoption = None withoption = None
@ -531,19 +499,24 @@ class SubConfig(object):
pathsvalues, pathsvalues,
_currpath, _currpath,
flatten, flatten,
sconfig_bag, soption_bag,
fullpath=fullpath) fullpath=fullpath)
#withoption can be set to None below ! #withoption can be set to None below !
if withoption is None: if withoption is None:
for opt in self.cfgimpl_get_description().impl_getchildren(config_bag, context): for opt in self.cfgimpl_get_description().impl_getchildren(config_bag, context):
sconfig_bag = config_bag.copy('nooption') name = opt.impl_getname()
sconfig_bag.option = opt path = self._get_subpath(name)
path = opt.impl_getname() soption_bag = OptionBag()
self._make_sub_dict(path, soption_bag.set_option(opt,
path,
None,
config_bag)
#path = self._get_subpath(name)
self._make_sub_dict(name,
pathsvalues, pathsvalues,
_currpath, _currpath,
flatten, flatten,
sconfig_bag, soption_bag,
fullpath=fullpath) fullpath=fullpath)
if _currpath == []: if _currpath == []:
options = dict(pathsvalues) options = dict(pathsvalues)
@ -555,33 +528,32 @@ class SubConfig(object):
pathsvalues, pathsvalues,
_currpath, _currpath,
flatten, flatten,
config_bag, option_bag,
fullpath=False): fullpath=False):
try: try:
option = config_bag.option option = option_bag.option
if not option.impl_is_optiondescription() and option.impl_is_master_slaves('slave'): if not option.impl_is_optiondescription() and option.impl_is_master_slaves('slave'):
ret = [] ret = []
length = self.cfgimpl_get_length_slave(option, config_bag) length = self.cfgimpl_get_length_slave(option_bag)
if length: if length:
for idx in range(length): for idx in range(length):
config_bag.properties = None soption_bag = OptionBag()
soption_bag.set_option(option,
option_bag.path,
idx,
option_bag.config_bag)
ret.append(self.getattr(name, ret.append(self.getattr(name,
idx, soption_bag))
config_bag)) elif option_bag.config_bag.setting_properties:
elif config_bag.setting_properties: self.cfgimpl_get_settings().validate_properties(option_bag)
path = self._get_subpath(name)
self.cfgimpl_get_settings().validate_properties(path,
None,
config_bag)
else: else:
ret = self.getattr(name, ret = self.getattr(name,
None, option_bag)
config_bag)
except PropertiesOptionError: except PropertiesOptionError:
pass pass
else: else:
if option.impl_is_optiondescription(): if option.impl_is_optiondescription():
pathsvalues += ret.make_dict(config_bag, pathsvalues += ret.make_dict(option_bag.config_bag,
flatten=flatten, flatten=flatten,
_currpath=_currpath + [name], _currpath=_currpath + [name],
fullpath=fullpath) fullpath=fullpath)
@ -638,12 +610,12 @@ class _CommonConfig(SubConfig):
true_option = option.impl_getopt() true_option = option.impl_getopt()
context = self.cfgimpl_get_context() context = self.cfgimpl_get_context()
true_path = true_option.impl_getpath(context) true_path = true_option.impl_getpath(context)
self, path = context.cfgimpl_get_home_by_path(true_path, self, path = context.cfgimpl_get_home_by_path(path,
config_bag) config_bag)
config_bag.option = true_option config_bag.option = true_option
else: else:
true_path = path true_path = path
config_bag.option = option #config_bag.option = option
return option return option
def cfgimpl_get_path(self, dyn=True): def cfgimpl_get_path(self, dyn=True):
@ -816,25 +788,15 @@ class GroupConfig(_CommonConfig):
return self._impl_children return self._impl_children
def cfgimpl_reset_cache(self, def cfgimpl_reset_cache(self,
opt, option_bag,
path,
config_bag,
resetted_opts=None): resetted_opts=None):
if resetted_opts is None: if resetted_opts is None:
resetted_opts = [] resetted_opts = []
if isinstance(self, MetaConfig): if isinstance(self, MetaConfig):
super(GroupConfig, self).cfgimpl_reset_cache(opt, super(GroupConfig, self).cfgimpl_reset_cache(option_bag,
path,
config_bag=config_bag,
resetted_opts=copy(resetted_opts)) resetted_opts=copy(resetted_opts))
for child in self._impl_children: for child in self._impl_children:
if config_bag is None: child.cfgimpl_reset_cache(option_bag,
nconfig_bag = config_bag
else:
nconfig_bag = config_bag.copy('nooption')
child.cfgimpl_reset_cache(opt,
path,
config_bag=nconfig_bag,
resetted_opts=copy(resetted_opts)) resetted_opts=copy(resetted_opts))
def set_value(self, def set_value(self,
@ -857,16 +819,21 @@ class GroupConfig(_CommonConfig):
only_config=only_config, only_config=only_config,
_commit=False)) _commit=False))
else: else:
nconfig_bag = config_bag.copy('nooption') subconfig, name = child.cfgimpl_get_home_by_path(path,
child.setattr(path, config_bag)
index, option = subconfig.cfgimpl_get_description().impl_getchild(name,
value, config_bag,
nconfig_bag, child)
option_bag = OptionBag()
option_bag.set_option(option,
path,
index,
config_bag)
child.setattr(value,
option_bag,
_commit=False) _commit=False)
except PropertiesOptionError as err: except PropertiesOptionError as err:
ret.append(PropertiesOptionError(err._path, ret.append(PropertiesOptionError(err._option_bag,
err._index,
err._config_bag,
err.proptype, err.proptype,
err._settings, err._settings,
err._opt_type, err._opt_type,
@ -905,8 +872,6 @@ class GroupConfig(_CommonConfig):
ret = [] ret = []
for child in self._impl_children: for child in self._impl_children:
nconfig_bag = config_bag.copy('nooption')
nconfig_bag.option = child
if isinstance(child, GroupConfig): if isinstance(child, GroupConfig):
ret.extend(child.find_firsts(byname=byname, ret.extend(child.find_firsts(byname=byname,
bypath=bypath, bypath=bypath,
@ -1011,59 +976,77 @@ class MetaConfig(GroupConfig):
' cannot be set together')) ' cannot be set together'))
opt = self.cfgimpl_get_description().impl_get_opt_by_path(path) opt = self.cfgimpl_get_description().impl_get_opt_by_path(path)
for child in self._impl_children: for child in self._impl_children:
nconfig_bag = config_bag.copy('nooption') subconfig, name = child.cfgimpl_get_home_by_path(path,
nconfig_bag.option = opt 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 force_default_if_same:
if not child.cfgimpl_get_values()._p_.hasvalue(path): if not child.cfgimpl_get_values()._p_.hasvalue(path):
child_value = undefined child_value = undefined
else: else:
child_value = child.getattr(path, child_value = child.getattr(name,
None, option_bag)
nconfig_bag)
if force_default or (force_default_if_same and value == child_value): if force_default or (force_default_if_same and value == child_value):
child.cfgimpl_get_values().reset(path, child.cfgimpl_get_values().reset(option_bag,
nconfig_bag,
_commit=False) _commit=False)
continue continue
if force_dont_change_value: if force_dont_change_value:
try: try:
child_value = child.getattr(path, child_value = child.getattr(name,
None, option_bag)
nconfig_bag)
if value != child_value: if value != child_value:
child.setattr(path, child.setattr(child_value,
None, option_bag,
child_value,
nconfig_bag,
_commit=False) _commit=False)
except (PropertiesOptionError, ValueError, SlaveError) as err: except (PropertiesOptionError, ValueError, SlaveError) as err:
ret.append(err) ret.append(err)
nconfig_bag = config_bag.copy('nooption')
try: try:
self.setattr(path, subconfig, name = self.cfgimpl_get_home_by_path(path,
index, config_bag)
value, option = subconfig.cfgimpl_get_description().impl_getchild(name,
nconfig_bag, config_bag,
_commit=_commit) 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: except (PropertiesOptionError, ValueError, SlaveError) as err:
ret.append(err) ret.append(err)
return ret return ret
def reset(self, path, config_bag): def reset(self,
#FIXME not working with DynSymLinkOption path,
#FIXME fonctionne avec sous metaconfig ?? config_bag):
opt = self.cfgimpl_get_description().impl_get_opt_by_path(path) rconfig_bag = ConfigBag(config=config_bag.config,
config_bag.option = opt _setting_properties=config_bag._setting_properties,
config_bag.validate = False 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: for child in self._impl_children:
sconfig_bag = config_bag.copy('nooption') child.cfgimpl_get_values().reset(option_bag,
sconfig_bag.option = opt
child.cfgimpl_get_values().reset(path,
sconfig_bag,
_commit=False) _commit=False)
self.cfgimpl_get_values().reset(path, self.cfgimpl_get_values().reset(option_bag)
config_bag)
def new_config(self, def new_config(self,
session_id, session_id,

View file

@ -53,31 +53,27 @@ def display_list(lst, separator='and', add_quote=False):
class PropertiesOptionError(AttributeError): class PropertiesOptionError(AttributeError):
"attempt to access to an option with a property that is not allowed" "attempt to access to an option with a property that is not allowed"
def __init__(self, def __init__(self,
path, option_bag,
index,
config_bag,
proptype, proptype,
settings, settings,
opt_type=None, opt_type=None,
requires=None, requires=None,
name=None, name=None,
orig_opt=None): orig_opt=None):
self._path = path
self._index = index
if opt_type: if opt_type:
self._opt_type = opt_type self._opt_type = opt_type
self._requires = requires self._requires = requires
self._name = name self._name = name
self._orig_opt = orig_opt self._orig_opt = orig_opt
else: else:
if config_bag.option.impl_is_optiondescription(): if option_bag.option.impl_is_optiondescription():
self._opt_type = 'optiondescription' self._opt_type = 'optiondescription'
else: else:
self._opt_type = 'option' self._opt_type = 'option'
self._requires = config_bag.option.impl_getrequires() self._requires = option_bag.option.impl_getrequires()
self._name = config_bag.option.impl_get_display_name() self._name = option_bag.option.impl_get_display_name()
self._orig_opt = None self._orig_opt = None
self._config_bag = config_bag.copy() self._option_bag = option_bag
self.proptype = proptype self.proptype = proptype
self._settings = settings self._settings = settings
self.msg = None self.msg = None
@ -90,12 +86,8 @@ class PropertiesOptionError(AttributeError):
#this part is a bit slow, so only execute when display #this part is a bit slow, so only execute when display
if self.msg: if self.msg:
return self.msg return self.msg
req = self._settings.apply_requires(self._path, req = self._settings.apply_requires(self._option_bag,
self._requires, True)
self._index,
True,
self._config_bag,
self._name)
#if req != {} or self._orig_opt is not None: #if req != {} or self._orig_opt is not None:
if req != {}: if req != {}:
only_one = len(req) == 1 only_one = len(req) == 1
@ -123,7 +115,7 @@ class PropertiesOptionError(AttributeError):
self._name, self._name,
prop_msg, prop_msg,
msg)) msg))
del self._path, self._index, self._requires, self._opt_type, self._name, self._config_bag del self._requires, self._opt_type, self._name, self._option_bag
del self._settings, self._orig_opt del self._settings, self._orig_opt
return self.msg return self.msg

View file

@ -81,22 +81,26 @@ class ChoiceOption(Option):
warnings_only=warnings_only) warnings_only=warnings_only)
def impl_get_values(self, def impl_get_values(self,
config_bag, option_bag,
current_opt=undefined): current_opt=undefined):
if current_opt is undefined: if current_opt is undefined:
current_opt = self current_opt = self
#FIXME cache? but in context... #FIXME cache? but in context...
values = self._choice_values values = self._choice_values
if isinstance(values, FunctionType): if isinstance(values, FunctionType):
if config_bag is undefined: if option_bag is undefined:
values = undefined values = undefined
else: else:
if option_bag.config_bag == undefined:
config = undefined
else:
config = option_bag.config_bag.config
values = carry_out_calculation(current_opt, values = carry_out_calculation(current_opt,
config_bag.config, context=config,
values, callback=values,
getattr(self, '_choice_values_params', {}), callback_params=getattr(self, '_choice_values_params', {}),
None, index=None,
config_bag) option_bag=option_bag)
if values is not undefined and not isinstance(values, list): if values is not undefined and not isinstance(values, list):
raise ConfigError(_('calculated values for {0} is not a list' raise ConfigError(_('calculated values for {0} is not a list'
'').format(self.impl_getname())) '').format(self.impl_getname()))
@ -105,9 +109,9 @@ class ChoiceOption(Option):
def _validate(self, def _validate(self,
value, value,
config_bag, option_bag,
current_opt=undefined): current_opt=undefined):
values = self.impl_get_values(config_bag, values = self.impl_get_values(option_bag,
current_opt=current_opt) current_opt=current_opt)
if values is not undefined and not value in values: if values is not undefined and not value in values:
if len(values) == 1: if len(values) == 1:

View file

@ -72,14 +72,14 @@ class DynOptionDescription(OptionDescription):
'').format(self.impl_get_display_name())) '').format(self.impl_get_display_name()))
def _impl_get_suffixes(self, def _impl_get_suffixes(self,
config_bag): option_bag):
callback, callback_params = self.impl_get_callback() callback, callback_params = self.impl_get_callback()
values = carry_out_calculation(self, values = carry_out_calculation(self,
config_bag.config, option_bag.config_bag.config,
callback, callback,
callback_params, callback_params,
None, None,
config_bag) option_bag)
if not isinstance(values, list): if not isinstance(values, list):
raise ValueError(_('DynOptionDescription callback for option "{}", is not a list ({})' raise ValueError(_('DynOptionDescription callback for option "{}", is not a list ({})'
'').format(self.impl_get_display_name(), values)) '').format(self.impl_get_display_name(), values))
@ -92,9 +92,9 @@ class DynOptionDescription(OptionDescription):
self.impl_get_display_name())) self.impl_get_display_name()))
return values return values
def get_syndynoptiondescriptions(self, config_bag): def get_syndynoptiondescriptions(self, option_bag):
subpath = self.impl_getpath(config_bag.config).rsplit('.', 1)[0] subpath = self.impl_getpath(option_bag.config_bag.config).rsplit('.', 1)[0]
for suffix in self._impl_get_suffixes(config_bag): for suffix in self._impl_get_suffixes(option_bag):
yield SynDynOptionDescription(self, yield SynDynOptionDescription(self,
subpath, subpath,
suffix) suffix)

View file

@ -24,7 +24,7 @@ from itertools import chain
from ..i18n import _ from ..i18n import _
from ..setting import groups, undefined from ..setting import groups, undefined, OptionBag, ConfigBag
from .optiondescription import OptionDescription from .optiondescription import OptionDescription
from .option import Option from .option import Option
from ..error import SlaveError, PropertiesOptionError from ..error import SlaveError, PropertiesOptionError
@ -104,35 +104,49 @@ class MasterSlaves(OptionDescription):
def reset(self, def reset(self,
values, values,
config_bag, option_bag,
_commit=True): _commit=True):
config_bag = ConfigBag(config=option_bag.config_bag.config,
_setting_properties=option_bag.config_bag._setting_properties,
force_permissive=option_bag.config_bag.force_permissive,
force_unrestraint=option_bag.config_bag.force_unrestraint,
_validate=False)
for slave in self.getslaves(): for slave in self.getslaves():
sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = slave
sconfig_bag.validate = False
slave_path = slave.impl_getpath(values._getcontext()) slave_path = slave.impl_getpath(values._getcontext())
values.reset(slave_path, soption_bag = OptionBag()
sconfig_bag, soption_bag.set_option(slave,
slave_path,
None,
config_bag)
values.reset(soption_bag,
_commit=_commit) _commit=_commit)
def pop(self, def pop(self,
values, values,
index, index,
config_bag, option_bag,
slaves=undefined): slaves=undefined):
context = values._getcontext() context = values._getcontext()
if slaves is undefined: if slaves is undefined:
slaves = self.getslaves() slaves = self.getslaves()
config_bag = ConfigBag(config=option_bag.config_bag.config,
_setting_properties=None,
force_permissive=option_bag.config_bag.force_permissive,
force_unrestraint=option_bag.config_bag.force_unrestraint,
_validate=False)
for slave in slaves: for slave in slaves:
slave_path = slave.impl_getpath(context) slave_path = slave.impl_getpath(context)
slavelen = values._p_.get_max_length(slave_path) slavelen = values._p_.get_max_length(slave_path)
sconfig_bag = config_bag.copy('nooption') soption_bag = OptionBag()
sconfig_bag.option = slave soption_bag.set_option(slave,
if not values.is_default_owner(slave_path, slave_path,
index, index,
config_bag, config_bag)
# do not check force_default_on_freeze
soption_bag.properties = {}
if not values.is_default_owner(soption_bag,
validate_meta=False): validate_meta=False):
if slavelen > index: if slavelen > index:
values._p_.resetvalue_index(slave_path, values._p_.resetvalue_index(slave_path,

View file

@ -95,9 +95,15 @@ class NetmaskOption(Option):
if make_net and ip.prefixlen() != 32: if make_net and ip.prefixlen() != 32:
val_ip = IP(val_ipnetwork) val_ip = IP(val_ipnetwork)
if ip.net() == val_ip: if ip.net() == val_ip:
msg = _('this is a network with netmask "{0}" ("{1}")') if current_opt == opts[1]:
msg = _('this is a network with netmask "{0}" ("{1}")')
else:
msg = _('this is a network with {2} "{0}" ("{1}")')
if ip.broadcast() == val_ip: if ip.broadcast() == val_ip:
msg = _('this is a broadcast with netmask "{0}" ("{1}")') if current_opt == opts[1]:
msg = _('this is a broadcast with netmask "{0}" ("{1}")')
else:
msg = _('this is a broadcast with {2} "{0}" ("{1}")')
except ValueError: except ValueError:
if not make_net: if not make_net:
@ -106,5 +112,10 @@ class NetmaskOption(Option):
else: else:
raise ValueError(_('with {2} "{0}" ("{1}")').format(val_ipnetwork, opts[1].impl_get_display_name(), typ)) raise ValueError(_('with {2} "{0}" ("{1}")').format(val_ipnetwork, opts[1].impl_get_display_name(), typ))
if msg is not None: if msg is not None:
raise ValueError(msg.format(val_netmask, if current_opt == opts[1]:
opts[1].impl_get_display_name())) raise ValueError(msg.format(val_netmask,
opts[1].impl_get_display_name()))
else:
raise ValueError(msg.format(val_ipnetwork,
opts[0].impl_get_display_name(),
typ))

View file

@ -25,7 +25,7 @@ import weakref
from .baseoption import OnlyOption, submulti, STATIC_TUPLE from .baseoption import OnlyOption, submulti, STATIC_TUPLE
from .symlinkoption import DynSymLinkOption from .symlinkoption import DynSymLinkOption
from ..i18n import _ from ..i18n import _
from ..setting import log, undefined, debug from ..setting import log, undefined, debug, OptionBag, ConfigBag
from ..autolib import carry_out_calculation from ..autolib import carry_out_calculation
from ..error import (ConfigError, ValueWarning, PropertiesOptionError, from ..error import (ConfigError, ValueWarning, PropertiesOptionError,
display_list) display_list)
@ -145,9 +145,13 @@ class Option(OnlyOption):
_setattr(self, '_default_multi', default_multi) _setattr(self, '_default_multi', default_multi)
if unique is not undefined: if unique is not undefined:
_setattr(self, '_unique', unique) _setattr(self, '_unique', unique)
option_bag = OptionBag()
option_bag.set_option(self,
undefined,
None,
undefined)
self.impl_validate(default, self.impl_validate(default,
is_multi=is_multi, option_bag)
config_bag=undefined)
if (is_multi and default != []) or \ if (is_multi and default != []) or \
(not is_multi and default is not None): (not is_multi and default is not None):
if is_multi: if is_multi:
@ -180,34 +184,25 @@ class Option(OnlyOption):
def impl_validate(self, def impl_validate(self,
value, value,
config_bag, option_bag,
context=undefined, context=undefined,
force_index=None, check_error=True):
current_opt=undefined,
is_multi=None,
check_error=True,
multi=None):
""" """
:param value: the option's value
:param context: Config's context
:type context: :class:`tiramisu.config.Config`
:type validate: boolean
:param force_index: if multi, value has to be a list
not if force_index is not None
:type force_index: integer
""" """
if current_opt is undefined: if option_bag:
current_opt = self config_bag = option_bag.config_bag
force_index = option_bag.index
else:
config_bag = undefined
force_index = None
if check_error and config_bag is not undefined and \ if check_error and config_bag is not undefined and \
not config_bag.validate: not config_bag.validate:
# just to check propertieserror # just to check propertieserror
self.valid_consistency(current_opt, self.valid_consistency(option_bag,
value, value,
context, context,
force_index, check_error)
check_error,
config_bag)
return return
def _is_not_unique(value): def _is_not_unique(value):
@ -233,13 +228,13 @@ class Option(OnlyOption):
args.insert(0, ParamValue(val)) args.insert(0, ParamValue(val))
validator_params_ = Params(tuple(args), kwargs) validator_params_ = Params(tuple(args), kwargs)
# Raise ValueError if not valid # Raise ValueError if not valid
carry_out_calculation(current_opt, carry_out_calculation(option_bag.ori_option,
context=context, context=context,
callback=validator, callback=validator,
callback_params=validator_params_, callback_params=validator_params_,
index=_index, index=_index,
option_bag=option_bag,
orig_value=value, orig_value=value,
config_bag=config_bag,
is_validator=True) is_validator=True)
def do_validation(_value, def do_validation(_value,
@ -251,13 +246,9 @@ class Option(OnlyOption):
if _value is not None: if _value is not None:
if check_error: if check_error:
# option validation # option validation
if config_bag is undefined:
setting_properties = None
else:
setting_properties = config_bag.setting_properties
self._validate(_value, self._validate(_value,
config_bag, option_bag,
current_opt) option_bag.ori_option)
if ((check_error and not is_warnings_only) or if ((check_error and not is_warnings_only) or
(not check_error and is_warnings_only)): (not check_error and is_warnings_only)):
calculation_validator(_value, calculation_validator(_value,
@ -265,13 +256,13 @@ class Option(OnlyOption):
self._second_level_validation(_value, self._second_level_validation(_value,
is_warnings_only) is_warnings_only)
if is_multi is None: #if is_multi is None:
is_multi = self.impl_is_multi() # is_multi = self.impl_is_multi()
is_warnings_only = getattr(self, '_warnings_only', False) is_warnings_only = getattr(self, '_warnings_only', False)
try: try:
val = value val = value
if not is_multi: if not self.impl_is_multi():
do_validation(val, None) do_validation(val, None)
elif force_index is not None: elif force_index is not None:
if self.impl_is_submulti(): if self.impl_is_submulti():
@ -282,14 +273,6 @@ class Option(OnlyOption):
do_validation(val, do_validation(val,
force_index) force_index)
else: else:
if multi is not None and self.impl_is_unique() and value in multi:
if not self.impl_is_submulti() and len(multi) - 1 >= force_index:
lst = list(multi)
lst.pop(force_index)
else:
lst = multi
if value in lst:
raise ValueError(_('this value is not uniq'))
do_validation(val, do_validation(val,
force_index) force_index)
elif not isinstance(value, list): elif not isinstance(value, list):
@ -309,17 +292,15 @@ class Option(OnlyOption):
do_validation(val, do_validation(val,
idx) idx)
self.valid_consistency(current_opt, self.valid_consistency(option_bag,
value, value,
context, context,
force_index, check_error)
check_error,
config_bag)
except ValueError as err: except ValueError as err:
if debug: # pragma: no cover if debug: # pragma: no cover
log.debug('do_validation: value: {0}, index: {1}:' log.debug('do_validation: value: {0}, index: {1}:'
' {2}'.format(val, ' {2}'.format(val,
_index, force_index,
err), err),
exc_info=True) exc_info=True)
if is_warnings_only: if is_warnings_only:
@ -443,15 +424,16 @@ class Option(OnlyOption):
all_cons_opts, all_cons_opts,
params) params)
#validate default value when add consistency #validate default value when add consistency
#FIXME validation! option_bag = OptionBag()
option_bag.set_option(self,
undefined,
None,
undefined)
self.impl_validate(self.impl_getdefault(), self.impl_validate(self.impl_getdefault(),
undefined) option_bag)
self.impl_validate(self.impl_getdefault(), self.impl_validate(self.impl_getdefault(),
undefined, option_bag,
check_error=False) check_error=False)
#FIXME
#if err:
# self._del_consistency()
if func != '_cons_not_equal': if func != '_cons_not_equal':
#consistency could generate warnings or errors #consistency could generate warnings or errors
self._has_dependency = True self._has_dependency = True
@ -465,37 +447,45 @@ class Option(OnlyOption):
opt._add_dependency(self) opt._add_dependency(self)
def valid_consistency(self, def valid_consistency(self,
option, option_bag,
value, value,
context, context,
index, check_error):
check_error,
config_bag):
if context is not undefined: if context is not undefined:
descr = context.cfgimpl_get_description() descr = context.cfgimpl_get_description()
# no consistency found at all # no consistency found at all
if descr._cache_consistencies is None: if descr._cache_consistencies is None:
return return
# get consistencies for this option # get consistencies for this option
if isinstance(option, DynSymLinkOption): if isinstance(option_bag.option, DynSymLinkOption):
consistencies = descr._cache_consistencies.get(option.impl_getopt()) consistencies = descr._cache_consistencies.get(option_bag.option.impl_getopt())
else: else:
consistencies = descr._cache_consistencies.get(option) consistencies = descr._cache_consistencies.get(option_bag.option)
else: else:
# is no context, get consistencies in option # is no context, get consistencies in option
consistencies = option.get_consistencies() consistencies = option_bag.option.get_consistencies()
if consistencies is not None: if consistencies:
if option_bag.config_bag is undefined:
cconfig_bag = undefined
elif option_bag.config_bag.force_permissive != True:
cconfig_bag = ConfigBag(config=option_bag.config_bag.config,
_setting_properties=option_bag.config_bag._setting_properties,
force_permissive=True,
force_unrestraint=option_bag.config_bag.force_unrestraint,
_validate=option_bag.config_bag._validate)
else:
cconfig_bag = option_bag.config_bag
for cons_id, func, all_cons_opts, params in consistencies: for cons_id, func, all_cons_opts, params in consistencies:
warnings_only = params.get('warnings_only', False) warnings_only = params.get('warnings_only', False)
if (warnings_only and not check_error) or (not warnings_only and check_error): if (warnings_only and not check_error) or (not warnings_only and check_error):
transitive = params.get('transitive', True) transitive = params.get('transitive', True)
#all_cons_opts[0] is the option where func is set #all_cons_opts[0] is the option where func is set
if isinstance(option, DynSymLinkOption): if isinstance(option_bag.ori_option, DynSymLinkOption):
opts = [] opts = []
for opt in all_cons_opts: for opt in all_cons_opts:
opts.append(DynSymLinkOption(opt(), opts.append(DynSymLinkOption(opt(),
option._rootpath, option_bag.ori_option._rootpath,
option._suffix)) option_bag.ori_option._suffix))
wopt = opts[0] wopt = opts[0]
else: else:
opts = all_cons_opts opts = all_cons_opts
@ -503,25 +493,23 @@ class Option(OnlyOption):
wopt.launch_consistency(self, wopt.launch_consistency(self,
func, func,
cons_id, cons_id,
option, option_bag,
value, value,
context, context,
index,
opts, opts,
warnings_only, warnings_only,
transitive, transitive,
config_bag) cconfig_bag)
def _get_consistency_value(self, def _get_consistency_value(self,
orig_option, option_bag,
current_option, current_option,
index,
cons_id, cons_id,
context, context,
config_bag, config_bag,
value, value,
transitive,
func): func):
index = option_bag.index
if func in ALLOWED_CONST_LIST: if func in ALLOWED_CONST_LIST:
index = None index = None
index_ = None index_ = None
@ -529,7 +517,7 @@ class Option(OnlyOption):
index_ = None index_ = None
else: else:
index_ = index index_ = index
if orig_option == current_option: if option_bag.ori_option == current_option:
# orig_option is current option # orig_option is current option
# we have already value, so use it # we have already value, so use it
return value return value
@ -537,14 +525,18 @@ class Option(OnlyOption):
#if no context get default value #if no context get default value
return current_option.impl_getdefault() return current_option.impl_getdefault()
#otherwise calculate value #otherwise calculate value
sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = current_option
sconfig_bag.fromconsistency.append(cons_id)
sconfig_bag.force_permissive = True
path = current_option.impl_getpath(context) path = current_option.impl_getpath(context)
coption_bag = OptionBag()
coption_bag.set_option(current_option,
path,
index_,
config_bag)
cons_ids = option_bag.fromconsistency.copy()
cons_ids.append(cons_id)
coption_bag.fromconsistency = cons_ids
opt_value = context.getattr(path, opt_value = context.getattr(path,
index_, coption_bag)
sconfig_bag)
if index_ is None and index is not None: if index_ is None and index is not None:
if len(opt_value) <= index: if len(opt_value) <= index:
opt_value = current_option.impl_getdefault_multi() opt_value = current_option.impl_getdefault_multi()
@ -556,10 +548,9 @@ class Option(OnlyOption):
current_opt, current_opt,
func, func,
cons_id, cons_id,
option, option_bag,
value, value,
context, context,
index,
opts, opts,
warnings_only, warnings_only,
transitive, transitive,
@ -583,9 +574,7 @@ class Option(OnlyOption):
:param transitive: propertyerror is transitive :param transitive: propertyerror is transitive
:type transitive: `boolean` :type transitive: `boolean`
""" """
#if context is not undefined: if cons_id in option_bag.fromconsistency:
# descr = context.cfgimpl_get_description()
if config_bag is not undefined and cons_id in config_bag.fromconsistency:
return return
all_cons_vals = [] all_cons_vals = []
all_cons_opts = [] all_cons_opts = []
@ -595,31 +584,30 @@ class Option(OnlyOption):
opt = opt() opt = opt()
is_multi = False is_multi = False
try: try:
opt_value = self._get_consistency_value(option, opt_value = self._get_consistency_value(option_bag,
opt, opt,
index,
cons_id, cons_id,
context, context,
config_bag, config_bag,
value, value,
transitive,
func) func)
except PropertiesOptionError as err: except PropertiesOptionError as err:
if debug: # pragma: no cover if debug: # pragma: no cover
log.debug('propertyerror in launch_consistency: {0}'.format(err)) log.debug('propertyerror in launch_consistency: {0}'.format(err))
if transitive: if transitive:
err.set_orig_opt(option) err.set_orig_opt(option_bag.option)
raise err raise err
else: else:
if opt.impl_is_multi() and index is None and func not in ALLOWED_CONST_LIST: if opt.impl_is_multi() and option_bag.index is None and \
func not in ALLOWED_CONST_LIST:
len_value = len(opt_value) len_value = len(opt_value)
if length is not None and length != len_value: if length is not None and length != len_value:
if context is undefined: if context is undefined:
return return
raise ValueError(_('unexpected length of "{}" in constency "{}", should be "{}"' raise ValueError(_('unexpected length of "{}" in constency "{}", '
'').format(len(opt_value), 'should be "{}"').format(len(opt_value),
opt.impl_get_display_name(), opt.impl_get_display_name(),
length)) length))
else: else:
length = len_value length = len_value
is_multi = True is_multi = True

View file

@ -22,7 +22,7 @@ from copy import copy
from ..i18n import _ from ..i18n import _
from ..setting import ConfigBag, groups, undefined, owners from ..setting import ConfigBag, OptionBag, groups, undefined, owners
from .baseoption import BaseOption, OnlyOption from .baseoption import BaseOption, OnlyOption
from .option import ALLOWED_CONST_LIST, DynSymLinkOption from .option import ALLOWED_CONST_LIST, DynSymLinkOption
from .syndynoptiondescription import SynDynOptionDescription from .syndynoptiondescription import SynDynOptionDescription
@ -173,11 +173,14 @@ class CacheOptionDescription(BaseOption):
'"force_store_value" property').format( '"force_store_value" property').format(
option.impl_get_display_name())) option.impl_get_display_name()))
if not values._p_.hasvalue(subpath): if not values._p_.hasvalue(subpath):
config_bag = ConfigBag(config=context, option=option) config_bag = ConfigBag(config=context)
config_bag.properties = frozenset() option_bag = OptionBag()
value = values.getvalue(subpath, option_bag.set_option(option,
None, subpath,
config_bag) None,
config_bag)
option_bag.properties = frozenset()
value = values.getvalue(option_bag)
value_setted = True value_setted = True
values._p_.setvalue(subpath, values._p_.setvalue(subpath,
value, value,
@ -224,13 +227,14 @@ class OptionDescriptionWalk(CacheOptionDescription):
__slots__ = ('_children',) __slots__ = ('_children',)
def build_dynoptions(self, def build_dynoptions(self,
option, option_bag):
config_bag): option = option_bag.option
dynopt = option.getsubdyn() dynopt = option.getsubdyn()
rootpath = self.impl_get_path_by_opt(dynopt) rootpath = self.impl_get_path_by_opt(dynopt)
ori_index = len(rootpath) + 1 ori_index = len(rootpath) + 1
subpaths = [rootpath] + option.impl_getpath(config_bag.config)[ori_index:].split('.')[:-1] subpaths = [rootpath] + option.impl_getpath(
for suffix in dynopt._impl_get_suffixes(config_bag): option_bag.config_bag.config)[ori_index:].split('.')[:-1]
for suffix in dynopt._impl_get_suffixes(option_bag):
subpath = '.'.join([subp + suffix for subp in subpaths]) subpath = '.'.join([subp + suffix for subp in subpaths])
if isinstance(option, OnlyOption): if isinstance(option, OnlyOption):
yield DynSymLinkOption(option, yield DynSymLinkOption(option,
@ -257,7 +261,12 @@ class OptionDescriptionWalk(CacheOptionDescription):
name = option.impl_getname() name = option.impl_getname()
if option.issubdyn(): if option.issubdyn():
if byname.startswith(name): if byname.startswith(name):
for doption in self.build_dynoptions(option, config_bag): option_bag = OptionBag()
option_bag.set_option(option,
path,
None,
config_bag)
for doption in self.build_dynoptions(option_bag):
if byname == doption.impl_getname(): if byname == doption.impl_getname():
dpath = doption.impl_getpath(config_bag.config) dpath = doption.impl_getpath(config_bag.config)
return (dpath, doption) return (dpath, doption)
@ -319,9 +328,12 @@ class OptionDescriptionWalk(CacheOptionDescription):
subpath = '' subpath = ''
else: else:
subpath = self.impl_getpath(config_bag.config) subpath = self.impl_getpath(config_bag.config)
sconfig_bag = config_bag.copy('nooption') option_bag = OptionBag()
sconfig_bag.option = child option_bag.set_option(child,
for suffix in child._impl_get_suffixes(sconfig_bag): subpath,
None,
config_bag)
for suffix in child._impl_get_suffixes(option_bag):
yield SynDynOptionDescription(child, yield SynDynOptionDescription(child,
subpath, subpath,
suffix) suffix)
@ -339,11 +351,16 @@ class OptionDescriptionWalk(CacheOptionDescription):
subconfig, subconfig,
config_bag): config_bag):
for child in self._impl_st_getchildren(only_dyn=True): for child in self._impl_st_getchildren(only_dyn=True):
sconfig_bag = config_bag.copy('nooption') #sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = child #sconfig_bag.option = child
cname = child.impl_getname() cname = child.impl_getname()
if name.startswith(cname): if name.startswith(cname):
for value in child._impl_get_suffixes(sconfig_bag): option_bag = OptionBag()
option_bag.set_option(child,
subconfig.cfgimpl_get_path(),
None,
config_bag)
for value in child._impl_get_suffixes(option_bag):
if name == cname + value: if name == cname + value:
return SynDynOptionDescription(child, return SynDynOptionDescription(child,
subconfig.cfgimpl_get_path(), subconfig.cfgimpl_get_path(),

View file

@ -20,7 +20,7 @@
# ____________________________________________________________ # ____________________________________________________________
from .baseoption import OnlyOption from .baseoption import OnlyOption
from ..i18n import _ from ..i18n import _
from ..setting import undefined from ..setting import undefined, OptionBag
class SymLinkOption(OnlyOption): class SymLinkOption(OnlyOption):
@ -104,22 +104,21 @@ class DynSymLinkOption(object):
def impl_validate(self, def impl_validate(self,
value, value,
config_bag, option_bag,
context=undefined, context=undefined,
force_index=None, check_error=True):
current_opt=undefined, context = option_bag.config_bag.config
is_multi=None, soption_bag = OptionBag()
check_error=True, soption_bag.set_option(self._opt,
multi=None): self.impl_getpath(context),
# add current_opt ! option_bag.index,
option_bag.config_bag)
soption_bag.ori_option = option_bag.option
soption_bag.fromconsistency = option_bag.fromconsistency.copy()
self._opt.impl_validate(value, self._opt.impl_validate(value,
config_bag, soption_bag,
context, context=context,
force_index, check_error=check_error)
current_opt=self,
is_multi=is_multi,
check_error=check_error,
multi=multi)
def impl_is_dynsymlinkoption(self): def impl_is_dynsymlinkoption(self):
return True return True

View file

@ -117,77 +117,99 @@ debug = False
static_set = frozenset() static_set = frozenset()
class ConfigBag(object): class OptionBag:
__slots__ = ('default', __slots__ = ('option', # current option
'config', 'path',
'option', 'index',
'ori_option', 'config_bag',
'properties', 'ori_option', # original option (for example useful for symlinkoption)
'setting_properties', 'properties', # properties of current option
'force_permissive', 'apply_requires',
'force_unrestraint', 'fromconsistency' # history for consistency
'trusted_cached_properties', )
'fromconsistency',
'_validator' def __init__(self):
self.option = None
self.fromconsistency = []
def set_option(self,
option,
path,
index,
config_bag):
if self.option != None:
raise Exception('hu?')
if path is None:
path = config_bag.config.cfgimpl_get_description().impl_get_path_by_opt(option)
self.path = path
self.index = index
self.option = option
self.config_bag = config_bag
def __getattr__(self, key):
if key == 'properties':
settings = self.config_bag.config.cfgimpl_get_settings()
self.properties = settings.getproperties(self, apply_requires=self.apply_requires)
return self.properties
elif key == 'ori_option':
return self.option
elif key == 'apply_requires':
return True
raise KeyError('unknown key {} for OptionBag'.format(key))
class ConfigBag:
__slots__ = ('config', # link to the current config (context)
'_setting_properties', # properties for current config
'force_permissive', # force permissive
'force_unrestraint', # do not validate properties
'_validate', # validate
) )
def __init__(self, config, **kwargs): def __init__(self, config, **kwargs):
self.default = {'force_permissive': False, self.force_permissive = False
'force_unrestraint': False, self.force_unrestraint = False
'trusted_cached_properties': True,
}
self.config = config self.config = config
self._validator = True self._validate = True
self.fromconsistency = []
for key, value in kwargs.items(): for key, value in kwargs.items():
if value != self.default.get(key): setattr(self, key, value)
setattr(self, key, value)
def __getattr__(self, key): def __getattr__(self, key):
if key == 'validate_properties': if key == 'validate_properties':
return not self.force_unrestraint return not self.force_unrestraint
if key == 'validate': if key == 'validate':
if self.setting_properties is not None: if self._validate and self._setting_properties is not None:
return 'validator' in self.setting_properties return 'validator' in self._setting_properties
return self._validator return self._validate
if key == 'setting_properties': if key == 'setting_properties':
if self.force_unrestraint: if self.force_unrestraint:
return None return None
self.setting_properties = self.config.cfgimpl_get_settings().get_context_properties() return self._setting_properties
return self.setting_properties if key == '_setting_properties':
self._setting_properties = self.config.cfgimpl_get_settings().get_context_properties()
if self._validate is False:
self._setting_properties = self._setting_properties - {'validator'}
return self._setting_properties
if key not in self.__slots__: if key not in self.__slots__:
raise KeyError('unknown key {}'.format(key)) raise KeyError('unknown key {} for ConfigBag'.format(key))
return self.default.get(key) return None
def __setattr__(self, key, value): def __setattr__(self, key, value):
if key == 'validate': if key == 'validate':
if self.setting_properties is not None: try:
if value is False: del self._setting_properties
self.setting_properties = frozenset(set(self.setting_properties) - {'validator'}) except AttributeError:
else: pass
self.setting_properties = frozenset(set(self.setting_properties) | {'validator'}) self._validate = value
else:
self._validator = value
else: else:
super().__setattr__(key, value) super().__setattr__(key, value)
def delete(self, key): def copy(self):
try:
return self.__delattr__(key)
except AttributeError:
pass
def copy(self, filters='all'):
kwargs = {} kwargs = {}
for key in self.__slots__: for key in self.__slots__:
if filters == 'nooption' and (key.startswith('option') or \ if key == 'fromconsistency' and self.fromconsistency != []:
key == 'properties'):
continue
if key == 'fromconsistency':
kwargs['fromconsistency'] = copy(self.fromconsistency) kwargs['fromconsistency'] = copy(self.fromconsistency)
elif key != 'default': else:
value = getattr(self, key) kwargs[key] = getattr(self, key)
if value != self.default.get(key):
kwargs[key] = value
return ConfigBag(**kwargs) return ConfigBag(**kwargs)
@ -357,13 +379,14 @@ class Settings(object):
return props return props
def getproperties(self, def getproperties(self,
path, option_bag,
index,
config_bag,
apply_requires=True): apply_requires=True):
""" """
""" """
opt = config_bag.option opt = option_bag.option
config_bag = option_bag.config_bag
path = option_bag.path
index = option_bag.index
if opt.impl_is_symlinkoption(): if opt.impl_is_symlinkoption():
opt = opt.impl_getopt() opt = opt.impl_getopt()
path = opt.impl_getpath(self._getcontext()) path = opt.impl_getpath(self._getcontext())
@ -384,17 +407,11 @@ class Settings(object):
props = self._p_.getproperties(path, props = self._p_.getproperties(path,
opt.impl_getproperties()) opt.impl_getproperties())
else: else:
props = meta.cfgimpl_get_settings().getproperties(path, props = meta.cfgimpl_get_settings().getproperties(option_bag,
index,
config_bag,
apply_requires) apply_requires)
if apply_requires: if apply_requires:
props |= self.apply_requires(path, props |= self.apply_requires(option_bag,
opt.impl_getrequires(), False)
index,
False,
config_bag,
opt.impl_get_display_name())
props -= self.getpermissive(opt, props -= self.getpermissive(opt,
path) path)
if apply_requires: if apply_requires:
@ -421,12 +438,8 @@ class Settings(object):
return self._pp_.getpermissive(path) return self._pp_.getpermissive(path)
def apply_requires(self, def apply_requires(self,
path, option_bag,
current_requires, readable):
index,
readable,
config_bag,
name):
"""carries out the jit (just in time) requirements between options """carries out the jit (just in time) requirements between options
a requirement is a tuple of this form that comes from the option's a requirement is a tuple of this form that comes from the option's
@ -470,7 +483,7 @@ class Settings(object):
:param path: the option's path in the config :param path: the option's path in the config
:type path: str :type path: str
""" """
#current_requires = opt.impl_getrequires() current_requires = option_bag.option.impl_getrequires()
# filters the callbacks # filters the callbacks
if readable: if readable:
@ -489,32 +502,38 @@ class Settings(object):
breaked = False breaked = False
for option, expected in exps: for option, expected in exps:
reqpath = option.impl_getpath(context) reqpath = option.impl_getpath(context)
#FIXME c'est un peut tard ! #FIXME c'est un peu tard !
if reqpath.startswith(path + '.'): if reqpath.startswith(option_bag.path + '.'):
raise RequirementError(_("malformed requirements " raise RequirementError(_("malformed requirements "
"imbrication detected for option:" "imbrication detected for option:"
" '{0}' with requirement on: " " '{0}' with requirement on: "
"'{1}'").format(path, reqpath)) "'{1}'").format(option_bag.path, reqpath))
idx = None idx = None
is_indexed = False is_indexed = False
if option.impl_is_master_slaves('slave'): if option.impl_is_master_slaves('slave'):
idx = index idx = option_bag.index
elif option.impl_is_multi(): elif option.impl_is_multi():
is_indexed = True is_indexed = True
sconfig_bag = config_bag.copy('nooption') config_bag = ConfigBag(config=option_bag.config_bag.config,
if config_bag.option == option: _setting_properties=option_bag.config_bag._setting_properties,
sconfig_bag.setting_properties = None force_permissive=True,
sconfig_bag.force_unrestraint= False force_unrestraint=option_bag.config_bag.force_unrestraint,
sconfig_bag.validate = False _validate=option_bag.config_bag._validate)
else: soption_bag = OptionBag()
sconfig_bag.force_permissive = True soption_bag.set_option(option,
sconfig_bag.option = option reqpath,
idx,
config_bag)
soption_bag.config_bag.force_permissive = True
if option_bag.option == option:
soption_bag.config_bag.force_unrestraint = True
soption_bag.config_bag.validate = False
soption_bag.apply_requires = False
try: try:
value = context.getattr(reqpath, value = context.getattr(reqpath,
idx, soption_bag)
sconfig_bag)
if is_indexed: if is_indexed:
value = value[index] value = value[option_bag.index]
except PropertiesOptionError as err: except PropertiesOptionError as err:
properties = err.proptype properties = err.proptype
if not transitive: if not transitive:
@ -532,19 +551,15 @@ class Settings(object):
prop_msg = _('properties') prop_msg = _('properties')
raise RequirementError(_('cannot access to option "{0}" because ' raise RequirementError(_('cannot access to option "{0}" because '
'required option "{1}" has {2} {3}' 'required option "{1}" has {2} {3}'
'').format(name, '').format(option_bag.option.impl_get_display_name(),
option.impl_get_display_name(), option.impl_get_display_name(),
prop_msg, prop_msg,
display_list(list(properties), add_quote=True))) display_list(list(properties), add_quote=True)))
# transitive action, add action # transitive action, add action
if operator != 'and': if operator != 'and':
if readable: if readable:
for msg in self.apply_requires(err._path, for msg in self.apply_requires(err._option_bag,
err._requires, True).values():
err._index,
True,
err._config_bag,
err._name).values():
calc_properties.setdefault(action, []).extend(msg) calc_properties.setdefault(action, []).extend(msg)
else: else:
calc_properties.add(action) calc_properties.add(action)
@ -587,23 +602,25 @@ class Settings(object):
def setproperties(self, def setproperties(self,
path, path,
properties, properties,
config_bag): option_bag):
"""save properties for specified path """save properties for specified path
(never save properties if same has option properties) (never save properties if same has option properties)
""" """
# should have index !!! # should have index !!!
if self._getcontext().cfgimpl_get_meta() is not None: if self._getcontext().cfgimpl_get_meta() is not None:
raise ConfigError(_('cannot change property with metaconfig')) raise ConfigError(_('cannot change property with metaconfig'))
if path is not None and config_bag.option.impl_getrequires() is not None: if path is not None and option_bag.option.impl_getrequires() is not None:
not_allowed_props = properties & getattr(config_bag.option, '_calc_properties', static_set) not_allowed_props = properties & \
getattr(option_bag.option, '_calc_properties', static_set)
if not_allowed_props: if not_allowed_props:
raise ValueError(_('cannot set property {} for option "{}" this property is calculated' raise ValueError(_('cannot set property {} for option "{}" this property is '
'').format(display_list(list(not_allowed_props), add_quote=True), 'calculated').format(display_list(list(not_allowed_props),
config_bag.option.impl_get_display_name())) add_quote=True),
if config_bag is None: option_bag.option.impl_get_display_name()))
if option_bag is None:
opt = None opt = None
else: else:
opt = config_bag.option opt = option_bag.option
if opt and opt.impl_is_symlinkoption(): if opt and opt.impl_is_symlinkoption():
raise TypeError(_("can't assign property to the symlinkoption \"{}\"" raise TypeError(_("can't assign property to the symlinkoption \"{}\""
"").format(opt.impl_get_display_name())) "").format(opt.impl_get_display_name()))
@ -616,21 +633,20 @@ class Settings(object):
self._p_.setproperties(path, self._p_.setproperties(path,
properties) properties)
#values too because of slave values could have a PropertiesOptionError has value #values too because of slave values could have a PropertiesOptionError has value
self._getcontext().cfgimpl_reset_cache(opt, self._getcontext().cfgimpl_reset_cache(option_bag)
path, if option_bag is not None:
config_bag) try:
del option_bag.properties
except AttributeError:
pass
def set_context_permissive(self, def set_context_permissive(self,
permissive): permissive):
self.setpermissive(None, self.setpermissive(None,
None,
None,
permissive) permissive)
def setpermissive(self, def setpermissive(self,
opt, option_bag,
path,
config_bag,
permissives): permissives):
""" """
enables us to put the permissives in the storage enables us to put the permissives in the storage
@ -645,51 +661,55 @@ class Settings(object):
raise ConfigError(_('cannot change permissive with metaconfig')) raise ConfigError(_('cannot change permissive with metaconfig'))
if not isinstance(permissives, frozenset): if not isinstance(permissives, frozenset):
raise TypeError(_('permissive must be a frozenset')) raise TypeError(_('permissive must be a frozenset'))
if opt and opt.impl_is_symlinkoption(): if option_bag is not None:
raise TypeError(_("can't assign permissive to the symlinkoption \"{}\"" opt = option_bag.option
"").format(opt.impl_get_display_name())) if opt and opt.impl_is_symlinkoption():
raise TypeError(_("can't assign permissive to the symlinkoption \"{}\""
"").format(opt.impl_get_display_name()))
path = option_bag.path
else:
path = None
forbidden_permissives = FORBIDDEN_SET_PERMISSIVES & permissives forbidden_permissives = FORBIDDEN_SET_PERMISSIVES & permissives
if forbidden_permissives: if forbidden_permissives:
raise ConfigError(_('cannot add those permissives: {0}').format( raise ConfigError(_('cannot add those permissives: {0}').format(
' '.join(forbidden_permissives))) ' '.join(forbidden_permissives)))
self._pp_.setpermissive(path, permissives) self._pp_.setpermissive(path, permissives)
self._getcontext().cfgimpl_reset_cache(opt, if option_bag is not None:
path, self._getcontext().cfgimpl_reset_cache(option_bag)
config_bag)
#____________________________________________________________ #____________________________________________________________
# reset methods # reset methods
def reset(self, def reset(self,
opt, option_bag):
path, # all_properties=False):
config_bag,
all_properties=False):
if self._getcontext().cfgimpl_get_meta() is not None: if self._getcontext().cfgimpl_get_meta() is not None:
raise ConfigError(_('cannot change property with metaconfig')) raise ConfigError(_('cannot change property with metaconfig'))
if option_bag is None:
opt = None
else:
opt = option_bag.option
if opt and opt.impl_is_symlinkoption(): if opt and opt.impl_is_symlinkoption():
raise TypeError(_("can't reset properties to the symlinkoption \"{}\"" raise TypeError(_("can't reset properties to the symlinkoption \"{}\""
"").format(opt.impl_get_display_name())) "").format(opt.impl_get_display_name()))
if all_properties and (path or opt): #if all_properties and (path or opt):
raise ValueError(_('opt and all_properties must not be set ' # raise ValueError(_('opt and all_properties must not be set '
'together in reset')) # 'together in reset'))
if all_properties: #if all_properties:
self._p_.reset_all_properties() # self._p_.reset_all_properties()
else: else:
if opt is not None and path is None: if opt is not None:
path = opt.impl_getpath(self._getcontext()) path = option_bag.path
else:
path = None
self._p_.delproperties(path) self._p_.delproperties(path)
self._getcontext().cfgimpl_reset_cache(opt, self._getcontext().cfgimpl_reset_cache(option_bag)
path,
config_bag)
#____________________________________________________________ #____________________________________________________________
# validate properties # validate properties
def validate_properties(self, def validate_properties(self,
path, option_bag):
index,
config_bag):
""" """
validation upon the properties related to `opt` validation upon the properties related to `opt`
@ -697,70 +717,56 @@ class Settings(object):
:param force_permissive: behaves as if the permissive property :param force_permissive: behaves as if the permissive property
was present was present
""" """
opt = config_bag.option
# calc properties # calc properties
self_properties = config_bag.properties self_properties = option_bag.properties
if self_properties is None: config_bag = option_bag.config_bag
self_properties = self.getproperties(path,
index,
config_bag)
config_bag.properties = self_properties
properties = self_properties & config_bag.setting_properties - {'frozen', 'mandatory', 'empty'} properties = self_properties & config_bag.setting_properties - {'frozen', 'mandatory', 'empty'}
# remove permissive properties # remove permissive properties
if (config_bag.force_permissive is True or 'permissive' in config_bag.setting_properties) and properties: if (config_bag.force_permissive is True or \
'permissive' in config_bag.setting_properties) and properties:
# remove global permissive if need # remove global permissive if need
properties -= self.get_context_permissive() properties -= self.get_context_permissive()
# at this point an option should not remain in properties # at this point an option should not remain in properties
if properties != frozenset(): if properties != frozenset():
raise PropertiesOptionError(path, raise PropertiesOptionError(option_bag,
index,
config_bag,
properties, properties,
self) self)
def validate_mandatory(self, def validate_mandatory(self,
path,
index,
value, value,
config_bag): option_bag):
values = self._getcontext().cfgimpl_get_values() values = self._getcontext().cfgimpl_get_values()
opt = config_bag.option opt = option_bag.option
config_bag = option_bag.config_bag
is_mandatory = False is_mandatory = False
if config_bag.setting_properties and 'mandatory' in config_bag.setting_properties: if config_bag.setting_properties and 'mandatory' in config_bag.setting_properties:
if (config_bag.force_permissive is True or 'permissive' in config_bag.setting_properties) and \ if (config_bag.force_permissive is True or 'permissive' in config_bag.setting_properties) and \
'mandatory' in self.get_context_permissive(): 'mandatory' in self.get_context_permissive():
pass pass
elif 'mandatory' in config_bag.properties and values.isempty(opt, elif 'mandatory' in option_bag.properties and values.isempty(opt,
value, value,
index=index): index=option_bag.index):
is_mandatory = True is_mandatory = True
if 'empty' in config_bag.properties and values.isempty(opt, if 'empty' in option_bag.properties and values.isempty(opt,
value, value,
force_allow_empty_list=True, force_allow_empty_list=True,
index=index): index=option_bag.index):
is_mandatory = True is_mandatory = True
if is_mandatory: if is_mandatory:
raise PropertiesOptionError(path, raise PropertiesOptionError(option_bag,
index,
config_bag,
['mandatory'], ['mandatory'],
self) self)
def validate_frozen(self, def validate_frozen(self,
path, option_bag):
index, if option_bag.config_bag.setting_properties and \
config_bag): ('everything_frozen' in option_bag.config_bag.setting_properties or
if config_bag.setting_properties and \ 'frozen' in option_bag.properties) and \
('everything_frozen' in config_bag.setting_properties or not ((option_bag.config_bag.force_permissive is True or
'frozen' in config_bag.properties) and \ 'permissive' in option_bag.config_bag.setting_properties) and
not ((config_bag.force_permissive is True or
'permissive' in config_bag.setting_properties) and
'frozen' in self.get_context_permissive()): 'frozen' in self.get_context_permissive()):
raise PropertiesOptionError(path, raise PropertiesOptionError(option_bag,
index,
config_bag,
['frozen'], ['frozen'],
self) self)
return False return False

View file

@ -44,13 +44,14 @@ class Cache(DictCache):
_display_classname(self), _display_classname(self),
id(self))) id(self)))
self._setcache(path, index, val, time()) self._setcache(path, index, val, time())
if DEBUG: elif DEBUG:
print('not setcache {} with index {} and value {} in {} ({})'.format(path, print('not setcache {} with index {} and value {} and props {} and {} in {} ({})'.format(path,
index, index,
val, val,
_display_classname(self), props,
id(self))) self_props,
return _display_classname(self),
id(self)))
def getcache(self, def getcache(self,
path, path,
@ -119,5 +120,5 @@ class Cache(DictCache):
example: {'path1': {'index1': ('value1', 'time1')}, 'path2': {'index2': ('value2', 'time2', )}} example: {'path1': {'index1': ('value1', 'time1')}, 'path2': {'index2': ('value2', 'time2', )}}
""" """
if DEBUG: if DEBUG:
print('get_chached', self._cache) print('get_chached {} for {} ({})'.format(self._cache, _display_classname(self), id(self)))
return self._get_cached() return self._get_cached()

View file

@ -17,7 +17,7 @@
# ____________________________________________________________ # ____________________________________________________________
import weakref import weakref
from .error import ConfigError, PropertiesOptionError from .error import ConfigError, PropertiesOptionError
from .setting import owners, expires_time, undefined, forbidden_owners from .setting import owners, expires_time, undefined, forbidden_owners, OptionBag, ConfigBag
from .autolib import carry_out_calculation from .autolib import carry_out_calculation
from .i18n import _ from .i18n import _
@ -63,9 +63,7 @@ class Values(object):
# get value # get value
def get_cached_value(self, def get_cached_value(self,
path, option_bag):
index,
config_bag):
"""get value directly in cache if set """get value directly in cache if set
otherwise calculated value and set it in cache otherwise calculated value and set it in cache
@ -81,40 +79,36 @@ class Values(object):
:returns: value :returns: value
""" """
# try to retrive value in cache # try to retrive value in cache
setting_properties = config_bag.setting_properties setting_properties = option_bag.config_bag.setting_properties
is_cached, value = self._p_.getcache(path, is_cached, value = self._p_.getcache(option_bag.path,
expires_time, expires_time,
index, option_bag.index,
setting_properties, setting_properties,
config_bag.properties, option_bag.properties,
'value') 'value')
if not is_cached: if not is_cached:
# no cached value so get value # no cached value so get value
value = self.getvalue(path, value = self.getvalue(option_bag)
index,
config_bag)
# validate value # validate value
context = self._getcontext() context = self._getcontext()
opt = config_bag.option opt = option_bag.option
opt.impl_validate(value, opt.impl_validate(value,
option_bag,
context=context, context=context,
force_index=index, check_error=True)
check_error=True,
config_bag=config_bag)
if setting_properties and 'warnings' in setting_properties: if setting_properties and 'warnings' in setting_properties:
opt.impl_validate(value, opt.impl_validate(value,
option_bag,
context=context, context=context,
force_index=index, check_error=False)
check_error=False,
config_bag=config_bag)
# store value in cache # store value in cache
if not is_cached: if not is_cached:
self._p_.setcache(path, self._p_.setcache(option_bag.path,
index, option_bag.index,
value, value,
setting_properties, setting_properties,
config_bag.properties) option_bag.properties)
if isinstance(value, list): if isinstance(value, list):
# return a copy, so value cannot be modified # return a copy, so value cannot be modified
return value.copy() return value.copy()
@ -122,9 +116,7 @@ class Values(object):
return value return value
def getvalue(self, def getvalue(self,
path, option_bag):
index,
config_bag):
"""actually retrieves the value """actually retrieves the value
:param path: the path of the `Option` :param path: the path of the `Option`
@ -134,37 +126,22 @@ class Values(object):
""" """
# get owner and value from store # get owner and value from store
# index allowed only for slave # index allowed only for slave
opt = config_bag.option index = option_bag.index
is_slave = opt.impl_is_master_slaves('slave') is_slave = option_bag.option.impl_is_master_slaves('slave')
if index is None or not is_slave: if index is None or not is_slave:
_index = None _index = None
else: else:
_index = index _index = index
owner, value = self._p_.getowner(path, owner, value = self._p_.getowner(option_bag.path,
owners.default, owners.default,
index=_index, index=_index,
with_value=True) with_value=True)
if owner != owners.default: if owner != owners.default:
if config_bag.setting_properties is None: # if a value is store in storage, check if not frozen + force_default_on_freeze
# get property without apply requires # if frozen + force_default_on_freeze => force default value
settings = self._getcontext().cfgimpl_get_settings() if not ('frozen' in option_bag.properties and \
self_properties = settings.getproperties(path, 'force_default_on_freeze' in option_bag.properties):
index,
config_bag,
apply_requires=False)
else:
# if a value is store in storage, check if not frozen + force_default_on_freeze
# if frozen + force_default_on_freeze => force default value
self_properties = config_bag.properties
if self_properties is None:
settings = self._getcontext().cfgimpl_get_settings()
self_properties = settings.getproperties(path,
index,
config_bag)
config_bag.properties = self_properties
if not ('frozen' in self_properties and \
'force_default_on_freeze' in self_properties):
if index is not None and not is_slave: if index is not None and not is_slave:
if len(value) > index: if len(value) > index:
return value[index] return value[index]
@ -172,14 +149,10 @@ class Values(object):
#so return default value #so return default value
else: else:
return value return value
return self.getdefaultvalue(path, return self.getdefaultvalue(option_bag)
index,
config_bag)
def getdefaultvalue(self, def getdefaultvalue(self,
path, option_bag):
index,
config_bag):
"""get default value: """get default value:
- get meta config value or - get meta config value or
- get calculated value or - get calculated value or
@ -192,36 +165,43 @@ class Values(object):
:returns: default value :returns: default value
""" """
context = self._getcontext() context = self._getcontext()
opt = config_bag.option config_bag = option_bag.config_bag
opt = option_bag.option
index = option_bag.index
def _reset_cache(_value): def _reset_cache(_value):
is_cache, cache_value = self._p_.getcache(path, is_cache, cache_value = self._p_.getcache(option_bag.path,
expires_time, expires_time,
index, index,
config_bag.setting_properties, config_bag.setting_properties,
config_bag.properties, option_bag.properties,
'value') 'value')
if is_cache and cache_value == _value: if is_cache and cache_value == _value:
# calculation return same value as previous value, # calculation return same value as previous value,
# so do not invalidate cache # so do not invalidate cache
return return
# calculated value is a new value, so reset cache # calculated value is a new value, so reset cache
context.cfgimpl_reset_cache(opt, context.cfgimpl_reset_cache(option_bag)
path,
config_bag)
if opt.impl_is_master_slaves('slave'): if opt.impl_is_master_slaves('slave'):
index_ = index index_ = index
else: else:
index_ = None index_ = None
if self._is_meta(path, if option_bag.index != index_:
index_, moption_bag = OptionBag()
config_bag): moption_bag.set_option(opt,
option_bag.path,
index_,
config_bag)
moption_bag.fromconsistency = option_bag.fromconsistency.copy()
else:
moption_bag = option_bag
if self._is_meta(moption_bag):
meta = context.cfgimpl_get_meta() meta = context.cfgimpl_get_meta()
# retrieved value from meta config # retrieved value from meta config
try: try:
value = meta.getattr(path, # FIXME could have different property!
index, value = meta.getattr(moption_bag.path,
config_bag) moption_bag)
except PropertiesOptionError: except PropertiesOptionError:
# if properties error, return an other default value # if properties error, return an other default value
# unexpected error, should not happened # unexpected error, should not happened
@ -237,7 +217,7 @@ class Values(object):
callback=callback, callback=callback,
callback_params=callback_params, callback_params=callback_params,
index=index, index=index,
config_bag=config_bag) option_bag=option_bag)
if isinstance(value, list) and index is not None: if isinstance(value, list) and index is not None:
# if value is a list and index is set # if value is a list and index is set
if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)): if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)):
@ -309,116 +289,94 @@ class Values(object):
# set value # set value
def setvalue(self, def setvalue(self,
path,
index,
value, value,
config_bag, option_bag,
_commit): _commit):
context = self._getcontext() context = self._getcontext()
owner = context.cfgimpl_get_settings().getowner() owner = context.cfgimpl_get_settings().getowner()
if config_bag.validate: if option_bag.config_bag.validate:
if index is not None or config_bag.option._has_consistencies(context): if option_bag.index is not None or option_bag.option._has_consistencies(context):
# set value to a fake config when option has dependency # set value to a fake config when option has dependency
# validation will be complet in this case (consistency, ...) # validation will be complet in this case (consistency, ...)
tested_context = context._gen_fake_values() tested_context = context._gen_fake_values()
sconfig_bag = config_bag.copy() #sconfig_bag = config_bag.copy()
sconfig_bag.validate = False ori_validate = option_bag.config_bag.validate
tested_context.cfgimpl_get_values().setvalue(path, if ori_validate is True:
index, option_bag.config_bag.validate = False
value, try:
sconfig_bag, tested_context.cfgimpl_get_values().setvalue(value,
True) option_bag,
sconfig_bag.validate = True True)
tested_context.getattr(path, option_bag.config_bag.validate = True
index, tested_context.getattr(option_bag.path,
sconfig_bag) option_bag)
except Exception as exc:
if ori_validate is True:
option_bag.config_bag.validate = True
raise exc
else: else:
self.setvalue_validation(path, self.setvalue_validation(value,
index, option_bag)
value,
config_bag)
self._setvalue(path, self._setvalue(option_bag,
index,
value, value,
owner, owner,
config_bag,
commit=_commit) commit=_commit)
def setvalue_validation(self, def setvalue_validation(self,
path,
index,
value, value,
config_bag): option_bag):
context = self._getcontext() context = self._getcontext()
settings = context.cfgimpl_get_settings() settings = context.cfgimpl_get_settings()
# First validate properties with this value # First validate properties with this value
self_properties = config_bag.properties opt = option_bag.option
if self_properties is None: settings.validate_frozen(option_bag)
self_properties = settings.getproperties(path, settings.validate_mandatory(value,
index, option_bag)
config_bag)
config_bag.properties = self_properties
opt = config_bag.option
settings.validate_frozen(path,
index,
config_bag)
settings.validate_mandatory(path,
index,
value,
config_bag)
# Value must be valid for option # Value must be valid for option
opt.impl_validate(value, opt.impl_validate(value,
config_bag, option_bag,
context, context,
check_error=True, check_error=True)
force_index=index) if option_bag.config_bag.setting_properties and \
if config_bag.setting_properties and 'warnings' in config_bag.setting_properties: 'warnings' in option_bag.config_bag.setting_properties:
# No error found so emit warnings # No error found so emit warnings
opt.impl_validate(value, opt.impl_validate(value,
config_bag, option_bag,
context, context,
check_error=False, check_error=False)
force_index=index)
def _setvalue(self, def _setvalue(self,
path, option_bag,
index,
value, value,
owner, owner,
config_bag,
commit=True): commit=True):
self._getcontext().cfgimpl_reset_cache(option_bag)
self._getcontext().cfgimpl_reset_cache(config_bag.option,
path,
config_bag)
if isinstance(value, list): if isinstance(value, list):
# copy # copy
value = list(value) value = value.copy()
self._p_.setvalue(path, self._p_.setvalue(option_bag.path,
value, value,
owner, owner,
index, option_bag.index,
commit) commit)
def _is_meta(self, def _is_meta(self,
path, option_bag,
index,
config_bag,
force_owner_is_default=False): force_owner_is_default=False):
if not force_owner_is_default and self._p_.hasvalue(path, if not force_owner_is_default and self._p_.hasvalue(option_bag.path,
index=index): index=option_bag.index):
# has already a value, so not meta # has already a value, so not meta
return False return False
context = self._getcontext() context = self._getcontext()
meta = context.cfgimpl_get_meta() meta = context.cfgimpl_get_meta()
if meta is None: if meta is None:
return False return False
opt = config_bag.option opt = option_bag.option
if opt.impl_is_master_slaves('slave'): if opt.impl_is_master_slaves('slave'):
master = opt.impl_get_master_slaves().getmaster() master = opt.impl_get_master_slaves().getmaster()
masterp = master.impl_getpath(context) masterp = master.impl_getpath(context)
@ -426,29 +384,23 @@ class Values(object):
if self._p_.hasvalue(masterp, if self._p_.hasvalue(masterp,
index=None): index=None):
return False return False
return not meta.cfgimpl_get_values().is_default_owner(path, return not meta.cfgimpl_get_values().is_default_owner(option_bag)
index,
config_bag)
#______________________________________________________________________ #______________________________________________________________________
# owner # owner
def is_default_owner(self, def is_default_owner(self,
path, option_bag,
index,
config_bag,
validate_meta=undefined): validate_meta=undefined):
return self._getowner(path, return self.getowner(option_bag,
index, validate_meta=validate_meta,
config_bag, only_default=True) == owners.default
validate_meta=validate_meta,
only_default=True) == owners.default
def getowner(self, def getowner(self,
path, option_bag,
index, validate_meta=True,
config_bag): only_default=False):
""" """
retrieves the option's owner retrieves the option's owner
@ -457,199 +409,144 @@ class Values(object):
was present was present
:returns: a `setting.owners.Owner` object :returns: a `setting.owners.Owner` object
""" """
return self._getowner(path,
index,
config_bag)
def _getowner(self,
path,
index,
config_bag,
validate_meta=True,
only_default=False):
"""get owner of an option
"""
context = self._getcontext() context = self._getcontext()
opt = config_bag.option opt = option_bag.option
if opt.impl_is_symlinkoption(): if opt.impl_is_symlinkoption():
config_bag.ori_option = opt option_bag.ori_option = opt
opt = opt.impl_getopt() opt = opt.impl_getopt()
config_bag.option = opt option_bag.option = opt
path = opt.impl_getpath(context) option_bag.path = opt.impl_getpath(context)
self_properties = config_bag.properties self_properties = option_bag.properties
settings = context.cfgimpl_get_settings() settings = context.cfgimpl_get_settings()
if self_properties is None: if option_bag.config_bag.setting_properties is not None:
self_properties = settings.getproperties(path, settings.validate_properties(option_bag)
index,
config_bag)
config_bag.properties = self_properties
if config_bag.setting_properties is not None:
settings.validate_properties(path,
index,
config_bag)
if 'frozen' in self_properties and 'force_default_on_freeze' in self_properties: if 'frozen' in self_properties and 'force_default_on_freeze' in self_properties:
return owners.default return owners.default
if only_default: if only_default:
if self._p_.hasvalue(path, if self._p_.hasvalue(option_bag.path,
index): option_bag.index):
owner = undefined owner = undefined
else: else:
owner = owners.default owner = owners.default
else: else:
owner = self._p_.getowner(path, owner = self._p_.getowner(option_bag.path,
owners.default, owners.default,
index=index) index=option_bag.index)
if owner is owners.default and validate_meta is not False: if owner is owners.default and validate_meta is not False:
meta = context.cfgimpl_get_meta() meta = context.cfgimpl_get_meta()
if meta is not None and self._is_meta(path, if meta is not None and self._is_meta(option_bag):
index, owner = meta.cfgimpl_get_values().getowner(option_bag,
config_bag): only_default=only_default)
owner = meta.cfgimpl_get_values()._getowner(path,
index,
config_bag,
only_default=only_default)
return owner return owner
def setowner(self, def setowner(self,
path,
index,
owner, owner,
config_bag): option_bag):
""" """
sets a owner to an option sets a owner to an option
:param opt: the `option.Option` object :param opt: the `option.Option` object
:param owner: a valid owner, that is a `setting.owners.Owner` object :param owner: a valid owner, that is a `setting.owners.Owner` object
""" """
opt = config_bag.option opt = option_bag.option
if opt.impl_is_symlinkoption(): if opt.impl_is_symlinkoption():
raise ConfigError(_("can't set owner for the symlinkoption \"{}\"" raise ConfigError(_("can't set owner for the symlinkoption \"{}\""
"").format(opt.impl_get_display_name())) "").format(opt.impl_get_display_name()))
if owner in forbidden_owners: if owner in forbidden_owners:
raise ConfigError(_('set owner "{0}" is forbidden').format(str(owner))) raise ConfigError(_('set owner "{0}" is forbidden').format(str(owner)))
if not self._p_.hasvalue(path): if not self._p_.hasvalue(option_bag.path):
raise ConfigError(_('no value for {0} cannot change owner to {1}' raise ConfigError(_('no value for {0} cannot change owner to {1}'
'').format(path, owner)) '').format(option_bag.path, owner))
self.setowner_validation(path, self._getcontext().cfgimpl_get_settings().validate_frozen(option_bag)
index, self._p_.setowner(option_bag.path,
config_bag) owner,
self._p_.setowner(path, owner, index=index) index=option_bag.index)
#______________________________________________________________________ #______________________________________________________________________
# reset # reset
def reset(self, def reset(self,
path, option_bag,
config_bag,
_commit=True): _commit=True):
context = self._getcontext() context = self._getcontext()
setting = context.cfgimpl_get_settings() setting = context.cfgimpl_get_settings()
hasvalue = self._p_.hasvalue(path) hasvalue = self._p_.hasvalue(option_bag.path)
if hasvalue and config_bag.validate: if hasvalue and option_bag.config_bag.validate:
ori_validate = option_bag.config_bag.validate
if ori_validate is True:
option_bag.config_bag.validate = False
fake_context = context._gen_fake_values() fake_context = context._gen_fake_values()
fake_value = fake_context.cfgimpl_get_values() fake_value = fake_context.cfgimpl_get_values()
sconfig_bag = config_bag.copy() fake_value.reset(option_bag)
sconfig_bag.validate = False if ori_validate is True:
fake_value.reset(path, option_bag.config_bag.validate = True
sconfig_bag) value = fake_value.getdefaultvalue(option_bag)
value = fake_value.getdefaultvalue(path, fake_value.setvalue_validation(value,
None, option_bag)
config_bag) opt = option_bag.option
fake_value.setvalue_validation(path,
None,
value,
config_bag)
opt = config_bag.option
if opt.impl_is_master_slaves('master'): if opt.impl_is_master_slaves('master'):
opt.impl_get_master_slaves().reset(self, opt.impl_get_master_slaves().reset(self,
config_bag, option_bag,
_commit=_commit) _commit=_commit)
if hasvalue: if hasvalue:
if 'force_store_value' in setting.getproperties(path, if 'force_store_value' in option_bag.properties:
None, value = self.getdefaultvalue(option_bag)
config_bag):
value = self.getdefaultvalue(path, self._setvalue(option_bag,
None,
config_bag)
self._setvalue(path,
None,
value, value,
owners.forced, owners.forced,
config_bag,
commit=_commit) commit=_commit)
else: else:
self._p_.resetvalue(path, self._p_.resetvalue(option_bag.path,
_commit) _commit)
context.cfgimpl_reset_cache(config_bag.option, if not opt.impl_is_master_slaves('master'):
path, # if master, already reset behind
config_bag) pass
context.cfgimpl_reset_cache(option_bag)
def reset_slave(self, def reset_slave(self,
path, option_bag):
index,
config_bag):
if self._p_.hasvalue(path, index=index): if self._p_.hasvalue(option_bag.path, index=option_bag.index):
context = self._getcontext() context = self._getcontext()
if config_bag.validate: if option_bag.config_bag.validate:
fake_context = context._gen_fake_values() fake_context = context._gen_fake_values()
fake_value = fake_context.cfgimpl_get_values() fake_value = fake_context.cfgimpl_get_values()
sconfig_bag = config_bag.copy() ori_validate = option_bag.config_bag.validate
sconfig_bag.validate = False option_bag.config_bag.validate = False
fake_value.reset_slave(path, try:
index, fake_value.reset_slave(option_bag)
sconfig_bag) value = fake_value.getdefaultvalue(option_bag)
value = fake_value.getdefaultvalue(path, fake_value.setvalue_validation(value,
index, option_bag)
config_bag) option_bag.config_bag.validate = ori_validate
fake_value.setvalue_validation(path, except Exception as err:
index, option_bag.config_bag.validate = ori_validate
value, raise err
config_bag) self._p_.resetvalue_index(option_bag.path, option_bag.index)
self._p_.resetvalue_index(path, index) context.cfgimpl_reset_cache(option_bag)
context.cfgimpl_reset_cache(config_bag.option,
path,
config_bag)
def reset_master(self, def reset_master(self,
subconfig,
path,
index, index,
config_bag): option_bag,
subconfig):
current_value = self.get_cached_value(path, current_value = self.get_cached_value(option_bag)
None,
config_bag)
length = len(current_value) length = len(current_value)
if index >= length: if index >= length:
raise IndexError(_('index "{}" is higher than the length "{}" ' raise IndexError(_('index "{}" is higher than the length "{}" '
'for option "{}"').format(index, 'for option "{}"').format(index,
length, length,
config_bag.option.impl_get_display_name())) option_bag.option.impl_get_display_name()))
current_value.pop(index) current_value.pop(index)
self.setvalue(path, self.setvalue(current_value,
None, option_bag,
current_value,
config_bag,
_commit=True) _commit=True)
subconfig.cfgimpl_get_description().pop(self, subconfig.cfgimpl_get_description().pop(self,
index, index,
config_bag) option_bag)
def setowner_validation(self,
path,
index,
config_bag):
context = self._getcontext()
settings = context.cfgimpl_get_settings()
# First validate properties with this value
self_properties = config_bag.properties
settings.validate_frozen(path,
index,
config_bag)
#______________________________________________________________________ #______________________________________________________________________
# information # information
@ -684,24 +581,26 @@ class Values(object):
settings = context.cfgimpl_get_settings() settings = context.cfgimpl_get_settings()
# for option in config.cfgimpl_get_children(self.config_bag): # for option in config.cfgimpl_get_children(self.config_bag):
for option in description.impl_getchildren(config_bag, context): for option in description.impl_getchildren(config_bag, context):
sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = option
name = option.impl_getname() name = option.impl_getname()
path = '.'.join(currpath + [name]) path = '.'.join(currpath + [name])
if option.impl_is_optiondescription(): if option.impl_is_optiondescription():
ori_setting_properties = sconfig_bag.setting_properties ori_setting_properties = config_bag._setting_properties
sconfig_bag.setting_properties = od_setting_properties config_bag._setting_properties = od_setting_properties
try: try:
option_bag = OptionBag()
option_bag.set_option(option,
path,
None,
config_bag)
subconfig = config.getattr(name, subconfig = config.getattr(name,
None, option_bag)
sconfig_bag)
except PropertiesOptionError as err: except PropertiesOptionError as err:
pass pass
else: else:
sconfig_bag.setting_properties = ori_setting_properties config_bag._setting_properties = ori_setting_properties
for path in self._mandatory_warnings(context, for path in self._mandatory_warnings(context,
sconfig_bag, config_bag,
option, option,
currpath + [name], currpath + [name],
subconfig, subconfig,
@ -711,26 +610,24 @@ class Values(object):
# don't verifying symlink # don't verifying symlink
try: try:
if not option.impl_is_master_slaves('slave'): if not option.impl_is_master_slaves('slave'):
self_properties = settings.getproperties(path, option_bag = OptionBag()
None, option_bag.set_option(option,
sconfig_bag) path,
None,
sconfig_bag.properties = self_properties config_bag)
if 'mandatory' in self_properties or 'empty' in self_properties: if 'mandatory' in option_bag.properties or 'empty' in option_bag.properties:
config.getattr(name, config.getattr(name,
None, option_bag)
sconfig_bag)
else: else:
for index in range(config.cfgimpl_get_length()): for index in range(config.cfgimpl_get_length()):
self_properties = settings.getproperties(path, option_bag = OptionBag()
index, option_bag.set_option(option,
sconfig_bag) path,
index,
sconfig_bag.properties = self_properties config_bag)
if 'mandatory' in self_properties: if 'mandatory' in option_bag.properties:
config.getattr(name, config.getattr(name,
index, option_bag)
sconfig_bag)
except PropertiesOptionError as err: except PropertiesOptionError as err:
if err.proptype == ['mandatory']: if err.proptype == ['mandatory']:
yield path yield path
@ -750,7 +647,8 @@ class Values(object):
od_setting_properties = config_bag.setting_properties - {'mandatory', 'empty'} od_setting_properties = config_bag.setting_properties - {'mandatory', 'empty'}
setting_properties = set(config_bag.setting_properties) - {'warnings'} setting_properties = set(config_bag.setting_properties) - {'warnings'}
setting_properties.update(['mandatory', 'empty']) setting_properties.update(['mandatory', 'empty'])
config_bag.setting_properties = frozenset(setting_properties) config_bag = ConfigBag(config=config_bag.config)
config_bag._setting_properties = frozenset(setting_properties)
config_bag.force_permissive = True config_bag.force_permissive = True
descr = context.cfgimpl_get_description() descr = context.cfgimpl_get_description()