async version of tiramisu

This commit is contained in:
2019-12-24 15:24:20 +01:00
parent 76e7fd93b2
commit 503d4b2cca
113 changed files with 12037 additions and 10420 deletions

View File

@ -18,7 +18,7 @@ from .function import calc_value, calc_value_property_help, valid_ip_netmask, \
valid_network_netmask, valid_in_network, valid_broadcast, \
valid_not_equal
from .autolib import Calculation, Params, ParamOption, ParamSelfOption, ParamValue, \
ParamIndex, ParamContext, ParamSuffix
ParamIndex, ParamSuffix
from .option import *
from .error import APIError
from .api import Config, MetaConfig, GroupConfig, MixConfig
@ -34,7 +34,6 @@ allfuncs = ['Calculation',
'ParamSelfOption',
'ParamValue',
'ParamIndex',
'ParamContext',
'ParamSuffix',
'MetaConfig',
'MixConfig',

View File

@ -18,6 +18,7 @@ from inspect import ismethod, getdoc, signature
from time import time
from typing import List, Set, Any, Optional, Callable, Union, Dict
from warnings import catch_warnings, simplefilter
from functools import wraps
from .error import APIError, ConfigError, LeadershipError, PropertiesOptionError, ValueErrorWarning
@ -27,6 +28,7 @@ from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined,
from .config import KernelConfig, SubConfig, KernelGroupConfig, KernelMetaConfig, KernelMixConfig
from .option import ChoiceOption, RegexpOption, OptionDescription
from .todict import TiramisuDict
from .asyncinit import asyncinit
TIRAMISU_VERSION = 3
@ -61,7 +63,7 @@ class TiramisuHelp:
display(self._tmpl_help.format('forcepermissive', _('Access to option without verifying permissive properties')).expandtabs(max_len + 10))
display(self._tmpl_help.format('unrestraint', _('Access to option without property restriction')).expandtabs(max_len + 10))
display()
if isinstance(self, TiramisuDispatcher):
if isinstance(self, TiramisuDispatcherOption):
doc = _(getdoc(self.__call__))
display(_('Call: {}').format(doc))
display()
@ -82,31 +84,45 @@ class CommonTiramisu(TiramisuHelp):
_allow_optiondescription = True
_validate_properties = True
def _get_option(self) -> Any:
async def _get_option(self) -> Any:
if not self._subconfig:
config_bag = self._option_bag.config_bag
try:
subconfig, name = await config_bag.context.cfgimpl_get_home_by_path(self._option_bag.path,
config_bag,
validate_properties=self._validate_properties)
except AssertionError as err:
raise APIError(str(err))
except Exception as err:
raise err
self._subconfig = subconfig
self._name = name
option = self._option_bag.option
if option is None:
option = self._subconfig.cfgimpl_get_description().get_child(self._name,
self._option_bag.config_bag,
self._subconfig.cfgimpl_get_path())
option_bag = OptionBag()
option_bag.set_option(option,
self._option_bag.path,
self._option_bag.index,
self._option_bag.config_bag)
option = await self._subconfig.cfgimpl_get_description().get_child(name,
config_bag,
self._subconfig.cfgimpl_get_path())
self._option_bag.option = option
# Calculate option's properties
settings = config_bag.context.cfgimpl_get_settings()
self._option_bag.properties = await settings.getproperties(self._option_bag)
if self._validate_properties:
option_bag.config_bag.context.cfgimpl_get_settings().validate_properties(option_bag)
self._option_bag = option_bag
await settings.validate_properties(self._option_bag)
index = self._option_bag.index
if index is not None:
if option.impl_is_optiondescription() or not option.impl_is_follower():
self._option_bag.option = None
raise APIError('index must be set only with a follower option')
self._length = self._subconfig.cfgimpl_get_length_leadership(self._option_bag)
self._length = await self._subconfig.cfgimpl_get_length_leadership(self._option_bag)
if index >= self._length:
self._option_bag.option = None
raise LeadershipError(_('index "{}" is greater than the leadership length "{}" '
'for option "{}"').format(index,
self._length,
option.impl_get_display_name()))
if not self._allow_optiondescription and option.impl_is_optiondescription():
self._option_bag.option = None
raise APIError(_('option must not be an optiondescription'))
return option
@ -117,28 +133,12 @@ class CommonTiramisuOption(CommonTiramisu):
_validate_properties = False
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag,
config: 'Config'=None) -> None:
option_bag: OptionBag) -> None:
self._option_bag = option_bag
self._name = name
self._subconfig = subconfig
# for help()
if option_bag is not None and self._option_bag.config_bag.context.impl_type != 'group':
self._get_option()
if option_bag.config_bag is not None and self._follower_need_index:
self._test_follower_index()
def _test_follower_index(self) -> None:
option = self._option_bag.option
if not option.impl_is_optiondescription() and \
self._option_bag.index is None and \
option.impl_is_follower():
raise APIError(_('index must be set with the follower option "{}"').format(self._option_bag.option.impl_get_display_name()))
self._subconfig = None
def __getattr__(self, name):
raise APIError(_('unknown method {} in {}').format(name, self.__class__.__name__))
raise APIError(_('unknown method "{}" in "{}"').format(name, self.__class__.__name__))
class _TiramisuOptionOptionDescription(CommonTiramisuOption):
@ -148,147 +148,145 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
_validate_properties = False
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag,
config: "Subconfig") -> None:
super().__init__(name, subconfig, option_bag)
self._config = config
option_bag: OptionBag):
super().__init__(option_bag)
self._config = option_bag.config_bag.context
def get(self):
async def get(self):
"""Get Tiramisu option"""
return self._option_bag.option
return await self._get_option()
def type(self):
return self._option_bag.option.impl_get_group_type()
async def type(self):
option = await self._get_option()
return option.impl_get_group_type()
def isleadership(self):
async def isleadership(self):
"""Test if option is a leader or a follower"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_is_leadership()
def doc(self):
async def doc(self):
"""Get option document"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_get_display_name()
def description(self):
async def description(self):
"""Get option description"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_get_information('doc', None)
def name(self,
async def name(self,
follow_symlink: bool=False) -> str:
"""Get option name"""
option = await self._get_option()
if not follow_symlink or \
self.isoptiondescription() or \
not self.issymlinkoption():
return self._name
await self.isoptiondescription() or \
not await self.issymlinkoption():
return option.impl_getname()
else:
option = self._option_bag.option
return option.impl_getopt().impl_getname()
def path(self) -> str:
async def path(self) -> str:
"""Get option path"""
return self._option_bag.path
def has_dependency(self, self_is_dep=True):
async def has_dependency(self, self_is_dep=True):
"""Test if option has dependency"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_has_dependency(self_is_dep)
def isoptiondescription(self):
async def isoptiondescription(self):
"""Test if option is an optiondescription"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_is_optiondescription()
def properties(self,
only_raises=False,
uncalculated=False):
async def properties(self,
only_raises=False,
uncalculated=False):
"""Get properties for an option"""
settings = self._option_bag.config_bag.context.cfgimpl_get_settings()
option = await self._get_option()
if uncalculated:
return settings.getproperties(self._option_bag,
uncalculated=True)
return await settings.getproperties(self._option_bag,
uncalculated=True)
if not only_raises:
return settings.getproperties(self._option_bag,
apply_requires=False)
return await settings.getproperties(self._option_bag,
apply_requires=False)
# do not check cache properties/permissives which are not save (unrestraint, ...)
return settings.calc_raises_properties(self._option_bag,
apply_requires=False)
return await settings.calc_raises_properties(self._option_bag,
apply_requires=False)
def __call__(self,
name: str,
index: Optional[int]=None) -> 'TiramisuOption':
"""Select an option by path"""
path = self._option_bag.path + '.' + name
return TiramisuOption(name,
path,
return TiramisuOption(path,
index,
self._config,
self._option_bag.config_bag)
class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
class TiramisuOptionOption(_TiramisuOptionOptionDescription):
"""Manage option"""
def ismulti(self):
async def ismulti(self):
"""Test if option could have multi value"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_is_multi()
def issubmulti(self):
async def issubmulti(self):
"""Test if option could have submulti value"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_is_submulti()
def isleader(self):
async def isleader(self):
"""Test if option is a leader"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_is_leader()
def isfollower(self):
async def isfollower(self):
"""Test if option is a follower"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_is_follower()
def issymlinkoption(self) -> bool:
option = self._option_bag.option
async def issymlinkoption(self) -> bool:
option = await self._get_option()
return option.impl_is_symlinkoption()
def default(self):
async def default(self):
"""Get default value for an option (not for optiondescription)"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_getdefault()
def defaultmulti(self):
async def defaultmulti(self):
"""Get default value when added a value for a multi option (not for optiondescription)"""
option = self._option_bag.option
option = await self._get_option()
ret = option.impl_getdefault_multi()
if ret is None and option.impl_is_multi() and option.impl_has_callback() and not self.isfollower():
callback, callback_params = option.impl_get_callback()
values = self._option_bag.config_bag.context.cfgimpl_get_values()
value = values.carry_out_calculation(self._option_bag,
callback,
callback_params)
value = await values.carry_out_calculation(self._option_bag,
callback,
callback_params)
if not isinstance(value, list):
ret = value
return ret
def callbacks(self):
async def callbacks(self):
"""Get callbacks for an option (not for optiondescription)"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_get_callback()
def validator(self):
async def validator(self):
"""Get validator for an option (not for optiondescription)"""
option = self._option_bag.option
option = await self._get_option()
return option.impl_get_validator()
def type(self):
return self._option_bag.option.get_type()
async def type(self):
option = await self._get_option()
return option.get_type()
def pattern(self) -> str:
option = self._option_bag.option
async def pattern(self) -> str:
option = await self._get_option()
type = option.get_type()
if isinstance(option, RegexpOption):
return option._regexp.pattern
@ -302,121 +300,91 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
return r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
class TiramisuOptionOption(CommonTiramisuOption):
"""Manage option"""
_allow_optiondescription = True
_follower_need_index = False
def __new__(cls,
name,
subconfig,
option_bag,
config):
if option_bag.option.impl_is_optiondescription():
return _TiramisuOptionOptionDescription(name=name,
subconfig=subconfig,
option_bag=option_bag,
config=config)
else:
return _TiramisuOptionOption(name=name,
subconfig=subconfig,
option_bag=option_bag,
config=config)
class TiramisuOptionOwner(CommonTiramisuOption):
#FIXME optiondescription must not have Owner!
"""Manage option's owner"""
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag,
config: Optional['SubConfig']) -> None:
option_bag: OptionBag) -> None:
super().__init__(name,
subconfig,
option_bag)
super().__init__(option_bag)
if option_bag is not None:
# for help()
self._values = self._option_bag.config_bag.context.cfgimpl_get_values()
def get(self):
async def get(self):
"""Get owner for a specified option"""
self._option_bag.option
return self._values.getowner(self._option_bag)
await self._get_option()
return await self._values.getowner(self._option_bag)
def isdefault(self):
async def isdefault(self):
"""Is option has defaut value"""
self._option_bag.option
return self._values.is_default_owner(self._option_bag)
await self._get_option()
return await self._values.is_default_owner(self._option_bag)
def set(self, owner):
async def set(self, owner):
"""Get owner for a specified option"""
self._option_bag.option
await self._get_option()
try:
obj_owner = getattr(owners, owner)
except AttributeError:
owners.addowner(owner)
obj_owner = getattr(owners, owner)
self._values.setowner(obj_owner,
self._option_bag)
await self._values.setowner(obj_owner,
self._option_bag)
class TiramisuOptionProperty(CommonTiramisuOption):
"""Manage option's property"""
_allow_optiondescription = True
_follower_need_index = False
_validate_properties = False
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag,
config: Optional['SubConfig']) -> None:
super().__init__(name,
subconfig,
option_bag)
option_bag: OptionBag) -> None:
super().__init__(option_bag)
if option_bag and option_bag.config_bag:
self._settings = option_bag.config_bag.context.cfgimpl_get_settings()
def get(self,
async def get(self,
only_raises=False):
"""Get properties for an option"""
await self._get_option()
if not only_raises:
return self._option_bag.properties
# do not check cache properties/permissives which are not save (unrestraint, ...)
return self._settings.calc_raises_properties(self._option_bag)
return await self._settings.calc_raises_properties(self._option_bag)
def add(self, prop):
async def add(self, prop):
"""Add new property for an option"""
option = self._option_bag.option
option = await self._get_option()
if prop in FORBIDDEN_SET_PROPERTIES:
raise ConfigError(_('cannot add this property: "{0}"').format(
' '.join(prop)))
props = self._settings._p_.getproperties(self._option_bag.path,
self._option_bag.index,
option.impl_getproperties())
self._settings.setproperties(self._option_bag.path,
props | {prop},
self._option_bag,
self._option_bag.config_bag.context)
props = await self._settings._p_.getproperties(self._option_bag.path,
self._option_bag.index,
option.impl_getproperties())
await self._settings.setproperties(self._option_bag.path,
props | {prop},
self._option_bag,
self._option_bag.config_bag.context)
def pop(self, prop):
async def pop(self, prop):
"""Remove new property for an option"""
option = self._option_bag.option
props = self._settings._p_.getproperties(self._option_bag.path,
self._option_bag.index,
option.impl_getproperties())
self._settings.setproperties(self._option_bag.path,
props - {prop},
self._option_bag,
self._option_bag.config_bag.context)
option = await self._get_option()
props = await self._settings._p_.getproperties(self._option_bag.path,
self._option_bag.index,
option.impl_getproperties())
await self._settings.setproperties(self._option_bag.path,
props - {prop},
self._option_bag,
self._option_bag.config_bag.context)
def reset(self):
async def reset(self):
"""Reset all personalised properties"""
option = self._option_bag.option
self._settings.reset(self._option_bag,
self._option_bag.config_bag.context)
await self._get_option()
await self._settings.reset(self._option_bag,
self._option_bag.config_bag.context)
class TiramisuOptionPermissive(CommonTiramisuOption):
@ -425,29 +393,27 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
_follower_need_index = False
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag,
config: Optional['SubConfig']) -> None:
super().__init__(name,
subconfig,
option_bag)
option_bag: OptionBag) -> None:
super().__init__(option_bag)
if option_bag and option_bag.config_bag:
self._settings = option_bag.config_bag.context.cfgimpl_get_settings()
def get(self):
async def get(self):
"""Get permissives value"""
return self._settings.getpermissives(self._option_bag)
await self._get_option()
return await self._settings.getpermissives(self._option_bag)
def set(self, permissives):
async def set(self, permissives):
"""Set permissives value"""
self._settings.setpermissives(self._option_bag,
permissives=permissives)
await self._get_option()
await self._settings.setpermissives(self._option_bag,
permissives=permissives)
def reset(self):
async def reset(self):
"""Reset all personalised permissive"""
self._settings.reset_permissives(self._option_bag,
self._option_bag.config_bag.context)
await self._get_option()
await self._settings.reset_permissives(self._option_bag,
self._option_bag.config_bag.context)
class TiramisuOptionInformation(CommonTiramisuOption):
@ -455,88 +421,176 @@ class TiramisuOptionInformation(CommonTiramisuOption):
_allow_optiondescription = True
_follower_need_index = False
def get(self, key, default=undefined):
def __init__(self,
option_bag: OptionBag) -> None:
super().__init__(option_bag)
async def get(self, key, default=undefined):
"""Get information"""
path = self._option_bag.path
values = self._option_bag.config_bag.context.cfgimpl_get_values()
try:
return values.get_information(key, path=path)
return await values.get_information(key,
path=path)
except ValueError:
option = self._option_bag.option
option = await self._get_option()
return option.impl_get_information(key, default)
def set(self, key, value):
async def set(self, key, value):
"""Set information"""
path = self._option_bag.path
values = self._option_bag.config_bag.context.cfgimpl_get_values()
values.set_information(key, value, path=path)
await values.set_information(key, value, path=path)
def reset(self,
async def reset(self,
key):
"""Remove information"""
path = self._option_bag.path
values = self._option_bag.config_bag.context.cfgimpl_get_values()
values.del_information(key, path=path)
await values.del_information(key,
path=path)
def list(self):
async def list(self):
"""List information's keys"""
await self._get_option()
path = self._option_bag.path
values = self._option_bag.config_bag.context.cfgimpl_get_values()
return values.list_information(path)
return await values.list_information(path)
async def len(self):
"""Length of leadership"""
option = await self._get_option()
# for example if index is None
if '_length' not in vars(self):
self._length = self._subconfig.cfgimpl_get_length()
return self._length
class _TiramisuOptionValueOption:
def get(self):
def option_type(typ):
if not isinstance(typ, list):
types = [typ]
else:
types = typ
def wrapper(func):
@wraps(func)
async def wrapped(*args, **kwargs):
for typ in types:
if typ == 'group':
if args[0]._option_bag.config_bag.context.impl_type == 'group':
return await func(*args, **kwargs, is_group=True)
else:
option = await args[0]._get_option()
if typ == 'option':
if option.impl_is_optiondescription():
raise APIError(_('please specify a valid sub function ({})').format(func.__name__))
elif typ == 'optiondescription':
if not option.impl_is_optiondescription():
raise APIError(_('please specify a valid sub function ({})').format(func.__name__))
elif typ == 'leader':
if not option.impl_is_leader():
raise APIError(_('please specify a valid sub function ({})').format(func.__name__))
elif typ == 'follower':
if not option.impl_is_follower() and not option.impl_is_leader():
raise APIError(_('please specify a valid sub function ({})').format(func.__name__))
elif typ == 'choice':
if not isinstance(option, ChoiceOption):
raise APIError(_('please specify a valid sub function ({})').format(func.__name__))
return await func(*args, **kwargs)
return wrapped
return wrapper
class TiramisuOptionValue(CommonTiramisuOption):
"""Manage option's value"""
_allow_optiondescription = True
_follower_need_index = True
_validate_properties = True
@option_type('optiondescription')
async def dict(self,
flatten=False,
withvalue=undefined,
withoption=None,
withwarning: bool=False,
fullpath=False):
"""Dict with path as key and value"""
name = self._option_bag.option.impl_getname()
subconfig = await self._subconfig.get_subconfig(self._option_bag)
config_bag = self._option_bag.config_bag
if not withwarning and config_bag.properties and 'warnings' in config_bag.properties:
config_bag = config_bag.copy()
config_bag.remove_warnings()
return await subconfig.make_dict(config_bag=config_bag,
flatten=flatten,
fullpath=fullpath,
withoption=withoption,
withvalue=withvalue)
@option_type('option')
async def get(self):
"""Get option's value"""
option = self._option_bag.option
self._test_follower_index()
return self._subconfig.getattr(self._name,
self._option_bag)
if self._option_bag.option.impl_is_follower() and self._option_bag.index is None:
raise APIError('index must be set with a follower option')
return await self._subconfig.getattr(self._name,
self._option_bag)
def set(self, value):
@option_type('option')
async def set(self, value):
"""Change option's value"""
option = self._option_bag.option
self._test_follower_index()
if self._option_bag.option.impl_is_follower() and \
self._option_bag.index is None:
raise APIError('index must be set with a follower option')
values = self._option_bag.config_bag.context.cfgimpl_get_values()
if isinstance(value, list):
while undefined in value:
idx = value.index(undefined)
soption_bag = self._option_bag.copy()
soption_bag.index = idx
value[idx] = values.getdefaultvalue(soption_bag)
value[idx] = await values.getdefaultvalue(soption_bag)
elif value == undefined:
value = values.getdefaultvalue(self._option_bag)
self._subconfig.setattr(value,
self._option_bag)
value = await values.getdefaultvalue(self._option_bag)
await self._subconfig.setattr(value,
self._option_bag)
def reset(self):
@option_type(['group', 'option'])
async def reset(self,
is_group: bool=False):
"""Reset value for an option"""
self._test_follower_index()
self._subconfig.delattr(self._option_bag)
if is_group:
await self._option_bag.config_bag.context.reset(self._option_bag.path)
else:
if self._option_bag.option.impl_is_follower() and self._option_bag.index is None:
raise APIError('index must be set with a follower option')
await self._subconfig.delattr(self._option_bag)
def default(self):
@option_type('option')
async def default(self):
"""Get default value (default of option or calculated value)"""
option = self._option_bag.option
option = await self._get_option()
values = self._option_bag.config_bag.context.cfgimpl_get_values()
if option.impl_is_follower() and self._option_bag.index is None:
value = []
length = self._subconfig.cfgimpl_get_length_leadership(self._option_bag)
length = await self._subconfig.cfgimpl_get_length_leadership(self._option_bag)
settings = self._option_bag.config_bag.context.cfgimpl_get_settings()
for idx in range(length):
soption_bag = OptionBag()
soption_bag.set_option(option,
self._option_bag.path,
idx,
self._option_bag.config_bag)
value.append(values.getdefaultvalue(soption_bag))
soption_bag.properties = await settings.getproperties(soption_bag)
value.append(await values.getdefaultvalue(soption_bag))
return value
else:
return values.getdefaultvalue(self._option_bag)
return await values.getdefaultvalue(self._option_bag)
def valid(self):
@option_type('option')
async def valid(self):
try:
with catch_warnings(record=True) as warns:
simplefilter("always", ValueErrorWarning)
self.get()
await self.get()
for warn in warns:
if isinstance(warns.message, ValueErrorWarning):
return False
@ -544,266 +598,179 @@ class _TiramisuOptionValueOption:
return False
return True
class _TiramisuOptionValueChoiceOption:
def list(self):
@option_type('choice')
async def list(self):
"""All values available for a ChoiceOption"""
option = self._option_bag.option
return option.impl_get_values(self._option_bag)
option = await self._get_option()
return await option.impl_get_values(self._option_bag)
class _TiramisuOptionValueLeader:
def pop(self, index):
@option_type('leader')
async def pop(self, index):
"""Pop a value"""
if self._option_bag.option.impl_is_follower() and self._option_bag.index is None:
raise APIError('index must be set with a follower option')
option_bag = self._option_bag
assert not option_bag.option.impl_is_symlinkoption(), _("can't delete a SymLinkOption")
option_bag.config_bag.context.cfgimpl_get_values().reset_leadership(index,
option_bag,
self._subconfig)
await option_bag.config_bag.context.cfgimpl_get_values().reset_leadership(index,
option_bag,
self._subconfig)
def len(self):
"""Length of leadership"""
option = self._option_bag.option
# for example if index is None
if '_length' not in vars(self):
self._length = self._subconfig.cfgimpl_get_length()
return self._length
class _TiramisuOptionValueFollower:
def len(self):
@option_type('follower')
async def len(self):
"""Length of follower option"""
option = self._option_bag.option
option = await self._get_option()
# for example if index is None
if '_length' not in vars(self):
self._length = self._subconfig.cfgimpl_get_length_leadership(self._option_bag)
self._length = await self._subconfig.cfgimpl_get_length_leadership(self._option_bag)
return self._length
class _TiramisuOptionValueGroup:
def reset(self):
"""Reset value"""
self._option_bag.config_bag.context.reset(self._option_bag.path)
class _TiramisuOptionValueOptionDescription:
def dict(self,
flatten=False,
withvalue=undefined,
withoption=None,
withwarning: bool=False,
fullpath=False):
"""Dict with path as key and value"""
self._get_option()
name = self._option_bag.option.impl_getname()
subconfig = self._subconfig.get_subconfig(self._option_bag)
config_bag = self._option_bag.config_bag
if not withwarning and config_bag.properties and 'warnings' in config_bag.properties:
config_bag = config_bag.copy()
config_bag.remove_warnings()
return subconfig.make_dict(config_bag=config_bag,
flatten=flatten,
fullpath=fullpath,
withoption=withoption,
withvalue=withvalue)
class TiramisuOptionValue(CommonTiramisuOption):
"""Manage option's value"""
_allow_optiondescription = True
_follower_need_index = False
def __new__(cls,
name,
subconfig,
option_bag,
config):
types = [CommonTiramisuOption]
if option_bag.option and option_bag.option.impl_is_optiondescription():
types.append(_TiramisuOptionValueOptionDescription)
elif subconfig is not None:
option = subconfig.cfgimpl_get_description().get_child(name,
option_bag.config_bag,
subconfig.cfgimpl_get_path())
types.append(_TiramisuOptionValueOption)
if isinstance(option, ChoiceOption):
types.append(_TiramisuOptionValueChoiceOption)
if option.impl_is_leader():
types.append(_TiramisuOptionValueLeader)
elif option.impl_is_follower():
types.append(_TiramisuOptionValueFollower)
if option_bag.config_bag.context.impl_type == 'group':
types.append(_TiramisuOptionValueGroup)
new_type_dict = {'_allow_optiondescription': cls._allow_optiondescription,
'_follower_need_index': cls._follower_need_index}
if option_bag.option and option_bag.option.impl_is_optiondescription():
new_type = type('TiramisuOptionValue', tuple(types), new_type_dict)(name=name,
subconfig=subconfig,
option_bag=option_bag,
config=config)
else:
new_type = type('TiramisuOptionValue', tuple(types), new_type_dict)(name=name,
subconfig=subconfig,
option_bag=option_bag)
new_type.__doc__ = cls.__doc__
return new_type
def _registers(_registers: Dict[str, type],
prefix: str,
extra_type: Optional[type]=None) -> None:
extra_type: Optional[type]=None):
for module_name in globals().keys():
if module_name != prefix and module_name.startswith(prefix):
if module_name != prefix and module_name.startswith(prefix): # and \
module = globals()[module_name]
func_name = module_name[len(prefix):].lower()
_registers[func_name] = module
class _TiramisuOption(CommonTiramisu):
"""Manage selected option"""
_validate_properties = False
_registers = {}
def __init__(self,
name: Optional[str],
path: Optional[str]=None,
index: Optional[int]=None,
subconfig: Union[None, KernelConfig, SubConfig]=None,
config_bag: Optional[ConfigBag]=None) -> None:
self._name = name
self._subconfig = subconfig
self._path = path
self._index = index
self._config_bag = config_bag
self._option_bag = OptionBag()
self._option_bag.path = self._path
self._option_bag.index = self._index
self._option_bag.config_bag = self._config_bag
self._tiramisu_dict = None
self._config = None
if not self._registers:
_registers(self._registers, 'TiramisuOption')
def _get_config(self):
if self._config is None and self._subconfig is not None:
self._config = self._subconfig.get_subconfig(self._option_bag)
return self._config
def __getattr__(self, subfunc: str) -> Any:
if subfunc in self._registers:
subconfig = self._subconfig
if subconfig:
option = self._get_option()
if option.impl_is_optiondescription() and subfunc == 'option':
config = self._get_config()
else:
config = None
else:
config = None
return self._registers[subfunc](self._name,
subconfig,
self._option_bag,
config)
raise APIError(_('please specify a valid sub function ({})').format(subfunc)) # pragma: no cover
#__________________________________________________________________________________________________
#
class TiramisuConfig(TiramisuHelp):
def __init__(self,
config_bag: Optional[ConfigBag]) -> None:
config_bag: ConfigBag,
orig_config_bags: Optional[List[OptionBag]]) -> None:
self._config_bag = config_bag
self._orig_config_bags = orig_config_bags
def _return_config(self,
async def _return_config(self,
config):
if isinstance(config, KernelConfig):
return Config(config)
return await Config(config)
if isinstance(config, KernelMetaConfig):
return MetaConfig(config)
return await MetaConfig(config)
if isinstance(config, KernelMixConfig):
return MixConfig([], config)
return await MixConfig([], config)
if isinstance(config, KernelGroupConfig):
return GroupConfig(config)
return await GroupConfig(config)
raise Exception(_('unknown config type {}').format(type(config)))
async def _reset_config_properties(self):
config = self._config_bag.context
settings = config.cfgimpl_get_settings()
properties = await settings.get_context_properties(config._impl_properties_cache)
permissives = await settings.get_context_permissives()
self._config_bag.properties = properties
self._config_bag.permissives = permissives
if self._orig_config_bags:
for config_bag in self._orig_config_bags:
config_bag.properties = properties
config_bag.permissives = permissives
class _TiramisuOptionDescription(_TiramisuOption, TiramisuConfig):
def find(self,
name: str,
value=undefined,
type=None,
first: bool=False):
class TiramisuOption(CommonTiramisu, TiramisuConfig):
"""Manage selected option"""
_validate_properties = False
_registers = {}
def __init__(self,
path: Optional[str]=None,
index: Optional[int]=None,
config_bag: Optional[ConfigBag]=None) -> None:
self._option_bag = OptionBag()
self._option_bag.config_bag = config_bag
self._option_bag.path = path
self._option_bag.index = index
self._subconfig = None
self._tiramisu_dict = None
if not self._registers:
_registers(self._registers, 'TiramisuOption')
def __getattr__(self, subfunc: str) -> Any:
if subfunc in self._registers:
return self._registers[subfunc](self._option_bag)
raise APIError(_('please specify a valid sub function ({})').format(subfunc)) # pragma: no cover
@option_type('optiondescription')
async def find(self,
name: str,
value=undefined,
type=None,
first: bool=False):
"""find an option by name (only for optiondescription)"""
if not first:
ret = []
option = self._get_option()
option = await self._get_option()
config_bag = self._option_bag.config_bag
oname = option.impl_getname()
path = self._subconfig._get_subpath(oname)
option_bag = OptionBag()
option_bag.set_option(option,
path,
None,
self._config_bag)
subconfig = self._subconfig.get_subconfig(option_bag)
for path in subconfig.find(byname=name,
byvalue=value,
bytype=type,
_subpath=self._path,
config_bag=self._config_bag):
subconfig, name = self._config_bag.context.cfgimpl_get_home_by_path(path,
self._config_bag)
t_option = TiramisuOption(name,
path,
config_bag)
subconfig = await self._subconfig.get_subconfig(option_bag)
async for path in subconfig.find(byname=name,
byvalue=value,
bytype=type,
_subpath=option_bag.path,
config_bag=config_bag):
t_option = TiramisuOption(path,
None, # index for a follower ?
subconfig,
self._config_bag)
config_bag)
if first:
return t_option
ret.append(t_option)
return ret
def group_type(self):
@option_type('optiondescription')
async def group_type(self):
"""Get type for an optiondescription (only for optiondescription)"""
return self._get_option().impl_get_group_type()
option = await self._get_option()
return option.impl_get_group_type()
def _filter(self,
opt,
subconfig,
config_bag):
async def _filter(self,
opt,
subconfig,
config_bag):
settings = config_bag.context.cfgimpl_get_settings()
option_bag = OptionBag()
option_bag.set_option(opt,
opt.impl_getpath(),
None,
config_bag)
option_bag.properties = await settings.getproperties(option_bag)
if opt.impl_is_optiondescription():
config_bag.context.cfgimpl_get_settings().validate_properties(option_bag)
return subconfig.get_subconfig(option_bag)
subconfig.getattr(opt.impl_getname(),
option_bag)
await settings.validate_properties(option_bag)
return await subconfig.get_subconfig(option_bag)
await subconfig.getattr(opt.impl_getname(),
option_bag)
def list(self,
type='option',
group_type=None):
@option_type('optiondescription')
async def list(self,
type='option',
group_type=None):
"""List options (by default list only option)"""
assert type in ('all', 'option', 'optiondescription'), _('unknown list type {}').format(type)
assert group_type is None or isinstance(group_type, groups.GroupType), \
_("unknown group_type: {0}").format(group_type)
config_bag = self._config_bag
config_bag = self._option_bag.config_bag
if config_bag.properties and 'warnings' in config_bag.properties:
config_bag = config_bag.copy()
config_bag.remove_warnings()
option = self._get_option()
option = await self._get_option()
option_bag = OptionBag()
option_bag.set_option(option,
option.impl_getpath(),
None,
config_bag)
subconfig = self._subconfig.get_subconfig(option_bag)
for opt in option.get_children(config_bag):
subconfig = await self._subconfig.get_subconfig(option_bag)
options = []
for opt in await option.get_children(config_bag):
try:
self._filter(opt,
subconfig,
config_bag)
await self._filter(opt,
subconfig,
config_bag)
except PropertiesOptionError:
continue
if opt.impl_is_optiondescription():
@ -812,106 +779,78 @@ class _TiramisuOptionDescription(_TiramisuOption, TiramisuConfig):
continue
elif type == 'optiondescription':
continue
name = opt.impl_getname()
path = opt.impl_getpath()
yield TiramisuOption(name,
path,
None,
subconfig,
self._config_bag)
options.append(TiramisuOption(opt.impl_getpath(),
None,
self._option_bag.config_bag))
return options
def _load_dict(self,
clearable: str="all",
remotable: str="minimum"):
root = self._get_option().impl_getpath()
self._tiramisu_dict = TiramisuDict(self._return_config(self._config_bag.context),
async def _load_dict(self,
clearable: str="all",
remotable: str="minimum"):
option = await self._get_option()
root = option.impl_getpath()
self._tiramisu_dict = TiramisuDict(await self._return_config(self._option_bag.config_bag.context),
root=root,
clearable=clearable,
remotable=remotable)
def dict(self,
@option_type('optiondescription')
async def dict(self,
clearable: str="all",
remotable: str="minimum",
form: List=[],
force: bool=False) -> Dict:
"""convert config and option to tiramisu format"""
if force or self._tiramisu_dict is None:
self._load_dict(clearable, remotable)
return self._tiramisu_dict.todict(form)
await self._load_dict(clearable, remotable)
return await self._tiramisu_dict.todict(form)
def updates(self,
body: List) -> Dict:
@option_type('optiondescription')
async def updates(self,
body: List) -> Dict:
"""updates value with tiramisu format"""
if self._tiramisu_dict is None:
self._load_dict()
return self._tiramisu_dict.set_updates(body)
class TiramisuOption(CommonTiramisuOption):
"""Manage selected option"""
def __new__(cls,
name: Optional[str],
path: Optional[str]=None,
index: Optional[int]=None,
subconfig: Union[None, KernelConfig, SubConfig]=None,
config_bag: Optional[ConfigBag]=None) -> None:
if subconfig:
# not for groupconfig
if '.' in name:
subconfig, name = config_bag.context.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().get_child(name,
config_bag,
subconfig.cfgimpl_get_path())
if option.impl_is_optiondescription():
return _TiramisuOptionDescription(name=name,
path=path,
index=index,
subconfig=subconfig,
config_bag=config_bag)
return _TiramisuOption(name=name,
path=path,
index=index,
subconfig=subconfig,
config_bag=config_bag)
await self._load_dict()
return await self._tiramisu_dict.set_updates(body)
class TiramisuContextInformation(TiramisuConfig):
"""Manage config informations"""
def get(self, name, default=undefined):
async def get(self, name, default=undefined):
"""Get an information"""
return self._config_bag.context.impl_get_information(name, default)
return await self._config_bag.context.impl_get_information(name, default)
def set(self, name, value):
async def set(self, name, value):
"""Set an information"""
self._config_bag.context.impl_set_information(name, value)
await self._config_bag.context.impl_set_information(name, value)
def reset(self, name):
async def reset(self, name):
"""Remove an information"""
self._config_bag.context.impl_del_information(name)
await self._config_bag.context.impl_del_information(name)
def list(self):
async def list(self):
"""List information's keys"""
return self._config_bag.context.impl_list_information()
return await self._config_bag.context.impl_list_information()
class TiramisuContextValue(TiramisuConfig):
"""Manage config value"""
def mandatory(self):
async def mandatory(self):
"""Return path of options with mandatory property without any value"""
return self._config_bag.context.cfgimpl_get_values().mandatory_warnings(self._config_bag)
options = []
async for option in self._config_bag.context.cfgimpl_get_values().mandatory_warnings(self._config_bag):
options.append(option)
return options
# FIXME should be only for group/meta
def set(self,
path: str,
value,
index=None,
only_config=undefined,
force_default=undefined,
force_default_if_same=undefined,
force_dont_change_value=undefined):
async def set(self,
path: str,
value,
index=None,
only_config=undefined,
force_default=undefined,
force_default_if_same=undefined,
force_dont_change_value=undefined):
"""Set a value in config or children for a path"""
kwargs = {}
if only_config is not undefined:
@ -922,22 +861,22 @@ class TiramisuContextValue(TiramisuConfig):
kwargs['force_default_if_same'] = force_default_if_same
if force_dont_change_value is not undefined:
kwargs['force_dont_change_value'] = force_dont_change_value
return self._config_bag.context.set_value(path,
index,
value,
self._config_bag,
**kwargs)
return await self._config_bag.context.set_value(path,
index,
value,
self._config_bag,
**kwargs)
# FIXME should be only for group/meta
def reset(self,
async def reset(self,
path: str,
only_children: bool=False):
"""Reset value"""
self._config_bag.context.reset(path,
only_children,
self._config_bag)
await self._config_bag.context.reset(path,
only_children,
self._config_bag)
def dict(self,
async def dict(self,
flatten=False,
withvalue=undefined,
withoption=None,
@ -945,19 +884,19 @@ class TiramisuContextValue(TiramisuConfig):
fullpath=False):
"""Dict with path as key and value"""
config_bag = self._config_bag
if not withwarning and config_bag.properties and 'warnings' in config_bag.properties:
if not withwarning and 'warnings' in config_bag.properties:
config_bag = config_bag.copy()
config_bag.remove_warnings()
return config_bag.context.make_dict(config_bag,
flatten=flatten,
fullpath=fullpath,
withoption=withoption,
withvalue=withvalue)
return await config_bag.context.make_dict(config_bag,
flatten=flatten,
fullpath=fullpath,
withoption=withoption,
withvalue=withvalue)
def exportation(self,
with_default_owner: bool=False):
async def exportation(self,
with_default_owner: bool=False):
"""Export all values"""
exportation = self._config_bag.context.cfgimpl_get_values()._p_.exportation()
exportation = await self._config_bag.context.cfgimpl_get_values()._p_.exportation()
if not with_default_owner:
exportation = [list(exportation[0]), list(exportation[1]), list(exportation[2]), list(exportation[3])]
index = exportation[0].index(None)
@ -967,123 +906,123 @@ class TiramisuContextValue(TiramisuConfig):
exportation[3].pop(index)
return exportation
def importation(self, values):
async def importation(self, values):
"""Import values"""
if None not in values[0]:
context_owner = self._config_bag.context.cfgimpl_get_values().get_context_owner()
context_owner = await self._config_bag.context.cfgimpl_get_values().get_context_owner()
else:
context_owner = None
self._config_bag.context.cfgimpl_get_values()._p_.importation(values)
self._config_bag.context.cfgimpl_reset_cache(None, None)
await self._config_bag.context.cfgimpl_get_values()._p_.importation(values)
await self._config_bag.context.cfgimpl_reset_cache(None, None)
if context_owner is not None:
self._config_bag.context.cfgimpl_get_values()._p_.setvalue(None,
None,
context_owner,
None,
True)
await self._config_bag.context.cfgimpl_get_values()._p_.setvalue(None,
None,
context_owner,
None,
True)
class TiramisuContextOwner(TiramisuConfig):
"""Global owner"""
def get(self):
async def get(self):
"""Get owner"""
return self._config_bag.context.cfgimpl_get_values().get_context_owner()
return await self._config_bag.context.cfgimpl_get_values().get_context_owner()
def set(self, owner):
async def set(self, owner):
"""Set owner"""
try:
obj_owner = getattr(owners, owner)
except AttributeError:
owners.addowner(owner)
obj_owner = getattr(owners, owner)
self._config_bag.context.cfgimpl_get_values().set_context_owner(obj_owner)
await self._config_bag.context.cfgimpl_get_values().set_context_owner(obj_owner)
class TiramisuContextProperty(TiramisuConfig):
"""Manage config properties"""
def read_only(self):
async def read_only(self):
"""Set config to read only mode"""
old_props = self._config_bag.properties
settings = self._config_bag.context.cfgimpl_get_settings()
settings.read_only(self._config_bag.context)
del self._config_bag.properties
await settings.read_only(self._config_bag.context)
await self._reset_config_properties()
if 'force_store_value' not in old_props and \
'force_store_value' in self._config_bag.properties:
self._force_store_value()
await self._force_store_value()
def read_write(self):
async def read_write(self):
"""Set config to read and write mode"""
old_props = self._config_bag.properties
settings = self._config_bag.context.cfgimpl_get_settings()
settings.read_write(self._config_bag.context)
await settings.read_write(self._config_bag.context)
or_properties = settings.rw_append - settings.ro_append - SPECIAL_PROPERTIES
permissives = frozenset(settings.get_context_permissives() | or_properties)
settings.set_context_permissives(permissives)
del self._config_bag.properties
permissives = frozenset(await settings.get_context_permissives() | or_properties)
await settings.set_context_permissives(permissives)
await self._reset_config_properties()
if 'force_store_value' not in old_props and \
'force_store_value' in self._config_bag.properties:
self._force_store_value()
await self._force_store_value()
def add(self, prop):
async def add(self, prop):
"""Add a config property"""
props = set(self.get())
props = set(await self.get())
props.add(prop)
self._set(frozenset(props))
await self._set(frozenset(props))
def pop(self, prop):
async def pop(self, prop):
"""Remove a config property"""
props = set(self.get())
props = set(await self.get())
if prop in props:
props.remove(prop)
self._set(frozenset(props))
await self._set(frozenset(props))
def get(self):
async def get(self):
"""Get all config properties"""
return self._config_bag.properties
def _set(self, props):
async def _set(self, props):
"""Personalise config properties"""
if 'force_store_value' in props:
force_store_value = 'force_store_value' not in self._config_bag.properties
else:
force_store_value = False
context = self._config_bag.context
context.cfgimpl_get_settings().set_context_properties(props,
context)
del self._config_bag.properties
await context.cfgimpl_get_settings().set_context_properties(props,
context)
await self._reset_config_properties()
if force_store_value:
self._force_store_value()
await self._force_store_value()
def reset(self):
async def reset(self):
"""Remove config properties"""
context = self._config_bag.context
context.cfgimpl_get_settings().reset(None,
context)
del self._config_bag.properties
await context.cfgimpl_get_settings().reset(None,
context)
await self._reset_config_properties()
def exportation(self):
async def exportation(self):
"""Export config properties"""
return self._config_bag.context.cfgimpl_get_settings()._p_.exportation()
return await self._config_bag.context.cfgimpl_get_settings()._p_.exportation()
def importation(self, properties):
async def importation(self, properties):
"""Import config properties"""
if 'force_store_value' in properties.get(None, {}).get(None, []):
force_store_value = 'force_store_value' not in self._config_bag.properties
else:
force_store_value = False
self._config_bag.context.cfgimpl_get_settings()._p_.importation(properties)
self._config_bag.context.cfgimpl_reset_cache(None, None)
del self._config_bag.properties
await self._config_bag.context.cfgimpl_get_settings()._p_.importation(properties)
await self._config_bag.context.cfgimpl_reset_cache(None, None)
await self._reset_config_properties()
if force_store_value:
self._force_store_value()
await self._force_store_value()
def _force_store_value(self):
async def _force_store_value(self):
descr = self._config_bag.context.cfgimpl_get_description()
descr.impl_build_force_store_values(self._config_bag)
await descr.impl_build_force_store_values(self._config_bag)
def setdefault(self,
async def setdefault(self,
properties: Set[str],
type: Optional[str]=None,
when: Optional[str]=None) -> None:
@ -1108,9 +1047,9 @@ class TiramisuContextProperty(TiramisuConfig):
else:
raise ValueError(_('unknown type {}').format(type))
def getdefault(self,
type: Optional[str]=None,
when: Optional[str]=None) -> Set[str]:
async def getdefault(self,
type: Optional[str]=None,
when: Optional[str]=None) -> Set[str]:
setting = self._config_bag.context.cfgimpl_get_settings()
if type is None and when is None:
return setting.default_properties
@ -1134,45 +1073,45 @@ class TiramisuContextProperty(TiramisuConfig):
class TiramisuContextPermissive(TiramisuConfig):
"""Manage config permissives"""
def get(self):
async def get(self):
"""Get config permissives"""
return self._config_bag.context.cfgimpl_get_settings().get_context_permissives()
return await self._config_bag.context.cfgimpl_get_settings().get_context_permissives()
def _set(self, permissives):
async def _set(self, permissives):
"""Set config permissives"""
self._config_bag.context.cfgimpl_get_settings().set_context_permissives(permissives)
del self._config_bag.permissives
await self._config_bag.context.cfgimpl_get_settings().set_context_permissives(permissives)
await self._reset_config_properties()
def exportation(self):
async def exportation(self):
"""Export config permissives"""
return self._config_bag.context.cfgimpl_get_settings()._pp_.exportation()
return await self._config_bag.context.cfgimpl_get_settings()._pp_.exportation()
def importation(self, permissives):
async def importation(self, permissives):
"""Import config permissives"""
self._config_bag.context.cfgimpl_get_settings()._pp_.importation(permissives)
self._config_bag.context.cfgimpl_reset_cache(None,
None)
del self._config_bag.permissives
await self._config_bag.context.cfgimpl_get_settings()._pp_.importation(permissives)
await self._config_bag.context.cfgimpl_reset_cache(None,
None)
await self._reset_config_properties()
def reset(self):
async def reset(self):
"""Remove config permissives"""
context = self._config_bag.context
context.cfgimpl_get_settings().reset_permissives(None,
context)
del self._config_bag.properties
await context.cfgimpl_get_settings().reset_permissives(None,
context)
await self._reset_config_properties()
def add(self, prop):
async def add(self, prop):
"""Add a config permissive"""
props = set(self.get())
props = set(await self.get())
props.add(prop)
self._set(frozenset(props))
await self._set(frozenset(props))
def pop(self, prop):
async def pop(self, prop):
"""Remove a config permissive"""
props = set(self.get())
props = set(await self.get())
if prop in props:
props.remove(prop)
self._set(frozenset(props))
await self._set(frozenset(props))
class TiramisuContextOption(TiramisuConfig):
@ -1182,83 +1121,76 @@ class TiramisuContextOption(TiramisuConfig):
self._tiramisu_dict = None
super().__init__(*args, **kwargs)
def _find(self,
name,
value,
type):
for path in self._config_bag.context.find(byname=name,
byvalue=value,
bytype=type,
config_bag=self._config_bag):
subconfig, name = self._config_bag.context.cfgimpl_get_home_by_path(path,
self._config_bag)
yield TiramisuOption(name,
path,
None,
subconfig,
self._config_bag)
def find(self,
async def find(self,
name,
value=undefined,
type=None,
first=False):
"""Find an or a list of options"""
if first:
return next(self._find(name, value, type))
return self._find(name, value, type)
options = []
async for path in self._config_bag.context.find(byname=name,
byvalue=value,
bytype=type,
config_bag=self._config_bag):
option = TiramisuOption(path,
None,
self._config_bag)
if first:
return option
options.append(option)
return options
def _filter(self,
opt,
subconfig,
config_bag):
async def _filter(self,
opt,
subconfig,
config_bag):
option_bag = OptionBag()
option_bag.set_option(opt,
opt.impl_getpath(),
None,
config_bag)
settings = config_bag.context.cfgimpl_get_settings()
option_bag.properties = await settings.getproperties(option_bag)
if opt.impl_is_optiondescription():
config_bag.context.cfgimpl_get_settings().validate_properties(option_bag)
return subconfig.get_subconfig(option_bag)
subconfig.getattr(opt.impl_getname(),
option_bag)
await settings.validate_properties(option_bag)
return await subconfig.get_subconfig(option_bag)
await subconfig.getattr(opt.impl_getname(),
option_bag)
def _walk(self,
async def _walk(self,
option,
recursive,
type_,
group_type,
config_bag,
subconfig):
for opt in option.get_children(config_bag):
options = []
for opt in await option.get_children(config_bag):
try:
subsubconfig = self._filter(opt,
subconfig,
config_bag)
subsubconfig = await self._filter(opt,
subconfig,
config_bag)
except PropertiesOptionError:
continue
if opt.impl_is_optiondescription():
if recursive:
yield from self._walk(opt,
recursive,
type_,
group_type,
config_bag,
subsubconfig)
options.extend(await self._walk(opt,
recursive,
type_,
group_type,
config_bag,
subsubconfig))
if type_ == 'option' or (type_ == 'optiondescription' and \
group_type and opt.impl_get_group_type() != group_type):
continue
elif type_ == 'optiondescription':
continue
name = opt.impl_getname()
path = opt.impl_getpath()
yield TiramisuOption(name,
path,
None,
subconfig,
self._config_bag)
options.append(TiramisuOption(opt.impl_getpath(),
None,
self._config_bag))
return options
def list(self,
async def list(self,
type='option',
group_type=None,
recursive=False):
@ -1271,234 +1203,254 @@ class TiramisuContextOption(TiramisuConfig):
config_bag = config_bag.copy()
config_bag.remove_warnings()
option = config_bag.context.cfgimpl_get_description()
yield from self._walk(option,
recursive,
type,
group_type,
config_bag,
config_bag.context)
options = []
for opt in await self._walk(option,
recursive,
type,
group_type,
config_bag,
config_bag.context):
options.append(opt)
return options
def _load_dict(self,
clearable="all",
remotable="minimum"):
self._tiramisu_dict = TiramisuDict(self._return_config(self._config_bag.context),
async def _load_dict(self,
clearable="all",
remotable="minimum"):
self._tiramisu_dict = TiramisuDict(await self._return_config(self._config_bag.context),
root=None,
clearable=clearable,
remotable=remotable)
def dict(self,
clearable="all",
remotable="minimum",
form=[],
force=False):
async def dict(self,
clearable="all",
remotable="minimum",
form=[],
force=False):
"""convert config and option to tiramisu format"""
if force or self._tiramisu_dict is None:
self._load_dict(clearable, remotable)
return self._tiramisu_dict.todict(form)
await self._load_dict(clearable, remotable)
return await self._tiramisu_dict.todict(form)
def updates(self,
body: List) -> Dict:
async def updates(self,
body: List) -> Dict:
"""updates value with tiramisu format"""
if self._tiramisu_dict is None:
self._load_dict()
return self._tiramisu_dict.set_updates(body)
await self._load_dict()
return await self._tiramisu_dict.set_updates(body)
class _TiramisuContextConfigReset():
def reset(self):
async def reset(self):
"""Remove all datas to current config (informations, values, properties, ...)"""
# Option's values
context_owner = self._config_bag.context.cfgimpl_get_values().get_context_owner()
self._config_bag.context.cfgimpl_get_values()._p_.importation(([], [], [], []))
self._config_bag.context.cfgimpl_get_values()._p_.setvalue(None,
None,
context_owner,
None,
True)
context_owner = await self._config_bag.context.cfgimpl_get_values().get_context_owner()
await self._config_bag.context.cfgimpl_get_values()._p_.importation(([], [], [], []))
await self._config_bag.context.cfgimpl_get_values()._p_.setvalue(None,
None,
context_owner,
None,
True)
# Option's informations
self._config_bag.context.cfgimpl_get_values()._p_.del_informations()
await self._config_bag.context.cfgimpl_get_values()._p_.del_informations()
# Option's properties
self._config_bag.context.cfgimpl_get_settings()._p_.importation({})
await self._config_bag.context.cfgimpl_get_settings()._p_.importation({})
# Option's permissives
self._config_bag.context.cfgimpl_get_settings()._pp_.importation({})
await self._config_bag.context.cfgimpl_get_settings()._pp_.importation({})
# Remove cache
self._config_bag.context.cfgimpl_reset_cache(None, None)
await self._config_bag.context.cfgimpl_reset_cache(None, None)
class _TiramisuContextConfig(TiramisuConfig, _TiramisuContextConfigReset):
"""Actions to Config"""
def name(self):
async def name(self):
return self._config_bag.context.impl_getname()
def copy(self,
session_id=None,
persistent=False,
storage=None):
async def copy(self,
session_id=None,
persistent=False,
storage=None):
"""Copy current config"""
return self._return_config(self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage))
return await self._return_config(await self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage))
def deepcopy(self,
session_id=None,
persistent=False,
storage=None,
metaconfig_prefix=None):
async def deepcopy(self,
session_id=None,
persistent=False,
storage=None,
metaconfig_prefix=None):
"""Copy current config with all parents"""
return self._return_config(self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage,
metaconfig_prefix=metaconfig_prefix,
deep=[]))
return await self._return_config(await self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage,
metaconfig_prefix=metaconfig_prefix,
deep=[]))
def metaconfig(self):
async def metaconfig(self):
"""Get first meta configuration (obsolete please use parents)"""
try:
return next(self.parents())
except StopIteration:
parent = await self.parents()
if not parent:
return None
return parent[0]
def parents(self):
async def parents(self):
"""Get all parents of current config"""
ret = []
for parent in self._config_bag.context.get_parents():
yield self._return_config(parent)
ret.append(await self._return_config(parent))
return ret
def path(self):
async def path(self):
"""Get path from config (all parents name)"""
return self._config_bag.context.cfgimpl_get_config_path()
class _TiramisuContextGroupConfig(TiramisuConfig):
"""Actions to GroupConfig"""
def name(self):
async def name(self):
"""Get config name"""
return self._config_bag.context.impl_getname()
def list(self):
async def list(self):
"""List children's config"""
ret = []
for child in self._config_bag.context.cfgimpl_get_children():
yield self._return_config(child)
ret.append(await self._return_config(child))
return ret
def find(self,
name: str,
value=undefined):
async def find(self,
name: str,
value=undefined):
"""Find an or a list of config with finding option"""
return GroupConfig(self._config_bag.context.find_group(byname=name,
byvalue=value,
config_bag=self._config_bag))
return await GroupConfig(await self._config_bag.context.find_group(byname=name,
byvalue=value,
config_bag=self._config_bag))
def __call__(self,
path: Optional[str]):
"""select a child Tiramisu config"""
if path is None:
return self._return_config(self._config_bag.context)
spaths = path.split('.')
config = self._config_bag.context
for spath in spaths:
config = config.getconfig(spath)
return self._return_config(config)
def copy(self,
session_id=None,
persistent=False,
storage=None):
return self._return_config(self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage))
async def copy(self,
session_id=None,
persistent=False,
storage=None):
return await self._return_config(await self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage))
def deepcopy(self,
session_id=None,
persistent=False,
storage=None,
metaconfig_prefix=None):
return self._return_config(self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage,
metaconfig_prefix=metaconfig_prefix,
deep=[]))
async def deepcopy(self,
session_id=None,
persistent=False,
storage=None,
metaconfig_prefix=None):
return await self._return_config(await self._config_bag.context.duplicate(session_id,
persistent=persistent,
storage=storage,
metaconfig_prefix=metaconfig_prefix,
deep=[]))
def path(self):
async def path(self):
return self._config_bag.context.cfgimpl_get_config_path()
def get(self,
name: str) -> 'Config':
return self._return_config(self._config_bag.context.getconfig(name))
async def get(self,
name: str) -> 'Config':
return await self._return_config(self._config_bag.context.getconfig(name))
class _TiramisuContextMixConfig(_TiramisuContextGroupConfig, _TiramisuContextConfigReset):
"""Actions to MixConfig"""
def pop(self,
session_id=None,
config=None):
async def pop(self,
session_id=None,
config=None):
"""Remove config from MetaConfig"""
if __debug__ and None not in [session_id, config]:
raise APIError(_('cannot set session_id and config together'))
return self._return_config(self._config_bag.context.pop_config(session_id=session_id, config=config))
pop_config = await self._config_bag.context.pop_config(session_id=session_id, config=config)
return await self._return_config(pop_config)
def add(self,
config):
async def add(self,
config):
"""Add config from MetaConfig"""
self._config_bag.context.add_config(config)
await self._config_bag.context.add_config(config)
def parents(self):
async def parents(self):
"""Get all parents of current config"""
ret = []
for parent in self._config_bag.context.get_parents():
yield self._return_config(parent)
ret.append(await self._return_config(parent))
return ret
class _TiramisuContextMetaConfig(_TiramisuContextMixConfig):
"""Actions to MetaConfig"""
def new(self,
session_id,
persistent=False,
storage=None,
type='config'):
async def new(self,
session_id,
persistent=False,
storage=None,
type='config'):
"""Create and add a new config"""
new_config = self._config_bag.context.new_config(session_id=session_id,
persistent=persistent,
storage=storage,
type_=type)
return self._return_config(new_config)
new_config = await self._config_bag.context.new_config(session_id=session_id,
persistent=persistent,
storage=storage,
type_=type)
return await self._return_config(new_config)
class TiramisuContextCache(TiramisuConfig):
def reset(self):
self._config_bag.context.cfgimpl_reset_cache(None, None)
async def reset(self):
await self._config_bag.context.cfgimpl_reset_cache(None, None)
def set_expiration_time(self,
async def set_expiration_time(self,
time: int) -> None:
self._config_bag.expiration_time = time
def get_expiration_time(self) -> int:
async def get_expiration_time(self) -> int:
return self._config_bag.expiration_time
class TiramisuDispatcher:
pass
class TiramisuAPI(TiramisuHelp):
_registers = {}
def __init__(self,
config) -> None:
if not isinstance(config, ConfigBag):
config = ConfigBag(context=config)
self._config_bag = config
config_bag,
orig_config_bags=None) -> None:
if not isinstance(config_bag, ConfigBag):
raise Exception('pfffff')
# config = await ConfigBag(context=config)
self._config_bag = config_bag
self._orig_config_bags = orig_config_bags
if not self._registers:
_registers(self._registers, 'TiramisuContext')
_registers(self._registers, 'TiramisuDispatcher')
def __getattr__(self, subfunc: str) -> Any:
if subfunc == 'forcepermissive':
if subfunc == 'option':
config_bag = self._config_bag
return TiramisuDispatcherOption(config_bag,
self._orig_config_bags)
elif subfunc == 'forcepermissive':
config_bag = self._config_bag.copy()
config_bag.set_permissive()
return TiramisuAPI(config_bag)
if self._orig_config_bags is None:
orig_config_bags = []
else:
orig_config_bags = self._orig_config_bags
orig_config_bags.append(self._config_bag)
return TiramisuAPI(config_bag, orig_config_bags)
elif subfunc == 'unrestraint':
config_bag = self._config_bag.copy()
config_bag.unrestraint()
return TiramisuAPI(config_bag)
if self._orig_config_bags is None:
orig_config_bags = []
else:
orig_config_bags = self._orig_config_bags
orig_config_bags.append(self._config_bag)
return TiramisuAPI(config_bag, orig_config_bags)
elif subfunc == 'config':
config_type = self._config_bag.context.impl_type
if config_type == 'group':
@ -1509,70 +1461,73 @@ class TiramisuAPI(TiramisuHelp):
config = _TiramisuContextMixConfig
else:
config = _TiramisuContextConfig
return config(self._config_bag)
return config(self._config_bag,
self._orig_config_bags)
elif subfunc in self._registers:
config_bag = self._config_bag
del config_bag.permissives
return self._registers[subfunc](config_bag)
# del config_bag.permissives
return self._registers[subfunc](config_bag,
self._orig_config_bags)
raise APIError(_('please specify a valid sub function ({})').format(subfunc))
def __dir__(self):
return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config']
class TiramisuDispatcherOption(TiramisuDispatcher, TiramisuContextOption):
class TiramisuDispatcherOption(TiramisuContextOption):
"""Select an option"""
def __call__(self,
path: str,
index: Optional[int]=None) -> TiramisuOption:
"""Select an option by path"""
if self._config_bag.context.impl_type == 'group':
subpath, name = path.rsplit('.', 1)
subconfig = None
else:
subconfig, name = self._config_bag.context.cfgimpl_get_home_by_path(path,
self._config_bag)
return TiramisuOption(name,
path,
return TiramisuOption(path,
index,
subconfig,
self._config_bag)
def __getattr__(self, subfunc: str) -> Any:
async def __getattr__(self,
subfunc: str) -> Any:
if subfunc == 'unrestraint':
config_bag = self._config_bag.copy()
config_bag.unrestraint()
return TiramisuDispatcherOption(config_bag)
@asyncinit
class Config(TiramisuAPI):
"""Root config object that enables us to handle the configuration options"""
def __init__(self,
descr: OptionDescription,
session_id: str=None,
persistent: bool=False,
storage=None,
display_name=None) -> None:
async def __init__(self,
descr: OptionDescription,
session_id: str=None,
persistent: bool=False,
storage=None,
display_name=None) -> None:
if isinstance(descr, KernelConfig):
config = descr
else:
config = KernelConfig(descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=display_name)
super().__init__(config)
config = await KernelConfig(descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=display_name)
settings = config.cfgimpl_get_settings()
properties = await settings.get_context_properties(config._impl_properties_cache)
permissives = await settings.get_context_permissives()
config_bag = ConfigBag(config,
properties=properties,
permissives=permissives)
super().__init__(config_bag)
@asyncinit
class MetaConfig(TiramisuAPI):
"""MetaConfig object that enables us to handle the sub configuration's options"""
def __init__(self,
children: 'Config'=[],
session_id: Union[str, None]=None,
persistent: bool=False,
optiondescription: Optional[OptionDescription]=None,
storage=None,
display_name=None) -> None:
async def __init__(self,
children: 'Config'=[],
session_id: Union[str, None]=None,
persistent: bool=False,
optiondescription: Optional[OptionDescription]=None,
storage=None,
display_name=None) -> None:
if isinstance(children, KernelMetaConfig):
config = children
else:
@ -1583,24 +1538,31 @@ class MetaConfig(TiramisuAPI):
else:
_children.append(child)
config = KernelMetaConfig(_children,
session_id=session_id,
persistent=persistent,
optiondescription=optiondescription,
display_name=display_name,
storage=storage)
super().__init__(config)
config = await KernelMetaConfig(_children,
session_id=session_id,
persistent=persistent,
optiondescription=optiondescription,
display_name=display_name,
storage=storage)
settings = config.cfgimpl_get_settings()
properties = await settings.get_context_properties(config._impl_properties_cache)
permissives = await settings.get_context_permissives()
config_bag = ConfigBag(config,
properties=properties,
permissives=permissives)
super().__init__(config_bag)
@asyncinit
class MixConfig(TiramisuAPI):
"""MetaConfig object that enables us to handle the sub configuration's options"""
def __init__(self,
optiondescription: OptionDescription,
children: List[Config],
session_id: Optional[str]=None,
persistent: bool=False,
storage=None,
display_name: Callable=None) -> None:
async def __init__(self,
optiondescription: OptionDescription,
children: List[Config],
session_id: Optional[str]=None,
persistent: bool=False,
storage=None,
display_name: Callable=None) -> None:
if isinstance(children, KernelMixConfig):
config = children
else:
@ -1611,20 +1573,27 @@ class MixConfig(TiramisuAPI):
else:
_children.append(child)
config = KernelMixConfig(optiondescription,
_children,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=display_name)
super().__init__(config)
config = await KernelMixConfig(optiondescription,
_children,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=display_name)
settings = config.cfgimpl_get_settings()
properties = await settings.get_context_properties(config._impl_properties_cache)
permissives = await settings.get_context_permissives()
config_bag = ConfigBag(config,
properties=properties,
permissives=permissives)
super().__init__(config_bag)
@asyncinit
class GroupConfig(TiramisuAPI):
"""GroupConfig that enables us to access the Config"""
def __init__(self,
children,
session_id: Optional[str]=None) -> None:
async def __init__(self,
children,
session_id: Optional[str]=None) -> None:
if isinstance(children, KernelGroupConfig):
config = children
else:
@ -1635,6 +1604,9 @@ class GroupConfig(TiramisuAPI):
else:
_children.append(child)
config = KernelGroupConfig(_children,
session_id=session_id)
super().__init__(config)
config = await KernelGroupConfig(_children,
session_id=session_id)
config_bag = ConfigBag(config,
properties=None,
permissives=None)
super().__init__(config_bag)

View File

@ -24,7 +24,6 @@ from itertools import chain
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
from .i18n import _
from .setting import undefined, ConfigBag, OptionBag, Undefined
from .storage import get_default_values_storages, get_default_settings_storages
# ____________________________________________________________
@ -99,10 +98,6 @@ class ParamValue(Param):
self.value = value
class ParamContext(Param):
__slots__ = tuple()
class ParamIndex(Param):
__slots__ = tuple()
@ -137,32 +132,32 @@ class Calculation:
if warnings_only is True:
self.warnings_only = warnings_only
def execute(self,
async def execute(self,
option_bag: OptionBag,
leadership_must_have_index: bool=False,
orig_value: Any=undefined,
allow_raises=False) -> Any:
return carry_out_calculation(option_bag.option,
callback=self.function,
callback_params=self.params,
index=option_bag.index,
config_bag=option_bag.config_bag,
leadership_must_have_index=leadership_must_have_index,
orig_value=orig_value,
allow_raises=allow_raises)
return await carry_out_calculation(option_bag.option,
callback=self.function,
callback_params=self.params,
index=option_bag.index,
config_bag=option_bag.config_bag,
leadership_must_have_index=leadership_must_have_index,
orig_value=orig_value,
allow_raises=allow_raises)
def help(self,
option_bag: OptionBag,
leadership_must_have_index: bool=False) -> str:
async def help(self,
option_bag: OptionBag,
leadership_must_have_index: bool=False) -> str:
if not self.help_function:
return self.execute(option_bag,
leadership_must_have_index=leadership_must_have_index)
return carry_out_calculation(option_bag.option,
callback=self.help_function,
callback_params=self.params,
index=option_bag.index,
config_bag=option_bag.config_bag,
leadership_must_have_index=leadership_must_have_index)
return await carry_out_calculation(option_bag.option,
callback=self.help_function,
callback_params=self.params,
index=option_bag.index,
config_bag=option_bag.config_bag,
leadership_must_have_index=leadership_must_have_index)
def has_index(self, current_option):
if hasattr(self, '_has_index'):
@ -180,12 +175,12 @@ class Break(Exception):
pass
def manager_callback(callbk: Union[ParamOption, ParamValue],
option,
index: Optional[int],
orig_value,
config_bag: ConfigBag,
leadership_must_have_index: bool) -> Any:
async def manager_callback(callbk: Union[ParamOption, ParamValue],
option,
index: Optional[int],
orig_value,
config_bag: ConfigBag,
leadership_must_have_index: bool) -> Any:
"""replace Param by true value"""
def calc_index(callbk, index, same_leadership):
if index is not None:
@ -199,7 +194,7 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
return index
return None
def calc_self(callbk, option, index, value, config_bag):
async def calc_self(callbk, option, index, value, config_bag):
# index must be apply only if follower
is_follower = option.impl_is_follower()
apply_index = calc_index(callbk, index, is_follower)
@ -207,13 +202,13 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
if config_bag is undefined:
return undefined
path = option.impl_getpath()
option_bag = get_option_bag(config_bag, option, path, apply_index)
option_bag = await get_option_bag(config_bag, option, path, apply_index)
option_bag.config_bag.unrestraint()
option_bag.config_bag.remove_validation()
# if we are in properties calculation, cannot calculated properties
option_bag.properties = config_bag.context.cfgimpl_get_settings().getproperties(option_bag,
apply_requires=False)
new_value = get_value(callbk, option_bag, path)
option_bag.properties = await config_bag.context.cfgimpl_get_settings().getproperties(option_bag,
apply_requires=False)
new_value = await get_value(callbk, option_bag, path)
if apply_index is None and is_follower:
new_value[index] = value
value = new_value
@ -221,11 +216,11 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
value = value[apply_index]
return value
def get_value(callbk, option_bag, path):
async def get_value(callbk, option_bag, path):
try:
# get value
value = config_bag.context.getattr(path,
option_bag)
value = await config_bag.context.getattr(path,
option_bag)
except PropertiesOptionError as err:
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
if callbk.notraisepropertyerror or callbk.raisepropertyerror:
@ -236,7 +231,10 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err))
return value
def get_option_bag(config_bag, opt, path, index_):
async def get_option_bag(config_bag,
opt,
path,
index_):
# don't validate if option is option that we tried to validate
config_bag = config_bag.copy()
config_bag.properties = config_bag.true_properties - {'warnings'}
@ -247,6 +245,7 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
path,
index_,
config_bag)
option_bag.properties = await config_bag.context.cfgimpl_get_settings().getproperties(option_bag)
return option_bag
if isinstance(callbk, ParamValue):
@ -260,16 +259,10 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
raise ConfigError('option "{}" is not in a dynoptiondescription'.format(option.impl_get_display_name()))
return option.impl_getsuffix()
if isinstance(callbk, ParamContext):
if config_bag is undefined:
return undefined
# Not an option, set full context
return config_bag.context.duplicate(force_values=get_default_values_storages(),
force_settings=get_default_settings_storages())
if isinstance(callbk, ParamSelfOption):
if leadership_must_have_index and option.impl_get_leadership() and index is None:
raise Break()
value = calc_self(callbk, option, index, orig_value, config_bag)
value = await calc_self(callbk, option, index, orig_value, config_bag)
if not callbk.todict:
return value
return {'name': option.impl_get_display_name(),
@ -299,8 +292,8 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
index_ = None
with_index = False
path = callbk_option.impl_getpath()
option_bag = get_option_bag(config_bag, callbk_option, path, index_)
value = get_value(callbk, option_bag, path)
option_bag = await get_option_bag(config_bag, callbk_option, path, index_)
value = await get_value(callbk, option_bag, path)
if with_index:
value = value[index]
if not callbk.todict:
@ -309,14 +302,14 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
'value': value}
def carry_out_calculation(option,
callback: Callable,
callback_params: Optional[Params],
index: Optional[int],
config_bag: Optional[ConfigBag],
orig_value=undefined,
leadership_must_have_index: bool=False,
allow_raises: int=False):
async def carry_out_calculation(option,
callback: Callable,
callback_params: Optional[Params],
index: Optional[int],
config_bag: Optional[ConfigBag],
orig_value=undefined,
leadership_must_have_index: bool=False,
allow_raises: int=False):
"""a function that carries out a calculation for an option's value
:param option: the option
@ -342,12 +335,12 @@ def carry_out_calculation(option,
if callback_params:
for key, callbk in chain(fake_items(callback_params.args), callback_params.kwargs.items()):
try:
value = manager_callback(callbk,
option,
index,
orig_value,
config_bag,
leadership_must_have_index)
value = await manager_callback(callbk,
option,
index,
orig_value,
config_bag,
leadership_must_have_index)
if value is undefined:
return undefined
if key is None:

View File

@ -31,9 +31,11 @@ from .setting import OptionBag, ConfigBag, Settings, undefined, groups
from .storage import get_storages, gen_storage_id, get_default_values_storages, list_sessions, Cache
from .value import Values
from .i18n import _
from .asyncinit import asyncinit
class SubConfig(object):
@asyncinit
class SubConfig:
"""Sub configuration management entry.
Tree if OptionDescription's responsability. SubConfig are generated
on-demand. A Config is also a SubConfig.
@ -44,11 +46,11 @@ class SubConfig(object):
'_impl_path',
'_impl_length')
def __init__(self,
descr,
context,
config_bag,
subpath=None):
async def __init__(self,
descr,
context,
config_bag=None,
subpath=None):
""" Configuration option management class
:param descr: describes the configuration schema
@ -81,28 +83,29 @@ class SubConfig(object):
full_leaderpath,
None,
cconfig_bag)
value = self.getattr(leaderpath,
moption_bag)
moption_bag.properties = await self.cfgimpl_get_settings().getproperties(moption_bag)
value = await self.getattr(leaderpath,
moption_bag)
self._impl_length = len(value)
def cfgimpl_get_length(self):
return self._impl_length
def cfgimpl_get_length_leadership(self,
async def cfgimpl_get_length_leadership(self,
option_bag):
if option_bag.option.impl_is_symlinkoption():
context = self.cfgimpl_get_context()
path = option_bag.option.impl_getopt().impl_getpath()
subconfig, _ = context.cfgimpl_get_home_by_path(path,
option_bag.config_bag)
subconfig, _ = await context.cfgimpl_get_home_by_path(path,
option_bag.config_bag)
return subconfig.cfgimpl_get_length()
else:
return self.cfgimpl_get_length()
def reset_one_option_cache(self,
desc,
resetted_opts,
option_bag):
async def reset_one_option_cache(self,
desc,
resetted_opts,
option_bag):
if option_bag.path in resetted_opts:
return
@ -110,9 +113,9 @@ class SubConfig(object):
for woption in option_bag.option._get_dependencies(self.cfgimpl_get_description()):
option = woption()
if option.impl_is_dynoptiondescription():
# it's a dynoptiondescription remove cache for all generated optiondescription
for suffix in option.get_suffixes(option_bag.config_bag):
doption = option.to_dynoption(desc.impl_getpath(),
subpath = option.impl_getpath().rsplit('.', 1)[0]
for suffix in await option.get_suffixes(option_bag.config_bag):
doption = option.to_dynoption(subpath,
suffix,
option)
doption_path = doption.impl_getpath()
@ -121,15 +124,16 @@ class SubConfig(object):
doption_path,
option_bag.index,
option_bag.config_bag)
self.reset_one_option_cache(desc,
resetted_opts,
doption_bag)
doption_bag.properties = await self.cfgimpl_get_settings().getproperties(doption_bag)
await self.reset_one_option_cache(desc,
resetted_opts,
doption_bag)
elif option.issubdyn():
# it's an option in dynoptiondescription, remove cache for all generated option
dynopt = option.getsubdyn()
rootpath = dynopt.impl_getpath()
subpaths = [rootpath] + option.impl_getpath()[len(rootpath) + 1:].split('.')[:-1]
for suffix in dynopt.get_suffixes(option_bag.config_bag):
for suffix in await dynopt.get_suffixes(option_bag.config_bag):
path_suffix = dynopt.convert_suffix_to_path(suffix)
subpath = '.'.join([subp + path_suffix for subp in subpaths])
doption = option.to_dynoption(subpath,
@ -141,9 +145,10 @@ class SubConfig(object):
doption_path,
option_bag.index,
option_bag.config_bag)
self.reset_one_option_cache(desc,
resetted_opts,
doption_bag)
doption_bag.properties = await self.cfgimpl_get_settings().getproperties(doption_bag)
await self.reset_one_option_cache(desc,
resetted_opts,
doption_bag)
else:
option_path = option.impl_getpath()
doption_bag = OptionBag()
@ -151,17 +156,18 @@ class SubConfig(object):
option_path,
option_bag.index,
option_bag.config_bag)
self.reset_one_option_cache(desc,
resetted_opts,
doption_bag)
doption_bag.properties = await self.cfgimpl_get_settings().getproperties(doption_bag)
await self.reset_one_option_cache(desc,
resetted_opts,
doption_bag)
del option
option_bag.option.reset_cache(option_bag.path,
option_bag.config_bag,
resetted_opts)
def cfgimpl_reset_cache(self,
option_bag,
resetted_opts=None):
async def cfgimpl_reset_cache(self,
option_bag,
resetted_opts=None):
"""reset all settings in cache
"""
if resetted_opts is None:
@ -169,31 +175,33 @@ class SubConfig(object):
context = self.cfgimpl_get_context()
desc = context.cfgimpl_get_description()
if option_bag is not None:
self.reset_one_option_cache(desc,
resetted_opts,
option_bag)
await self.reset_one_option_cache(desc,
resetted_opts,
option_bag)
else:
context._impl_values_cache.reset_all_cache()
context._impl_properties_cache.reset_all_cache()
def cfgimpl_get_home_by_path(self,
path,
config_bag):
async def cfgimpl_get_home_by_path(self,
path: str,
config_bag: ConfigBag,
validate_properties=True) -> ('Subconfig', str):
""":returns: tuple (config, name)"""
path = path.split('.')
for step in path[:-1]:
option_bag = OptionBag()
option = self.cfgimpl_get_description().get_child(step,
config_bag,
self.cfgimpl_get_path())
option = await self.cfgimpl_get_description().get_child(step,
config_bag,
self.cfgimpl_get_path())
subpath = self._get_subpath(step)
option_bag.set_option(option,
subpath,
None,
config_bag)
self = self.get_subconfig(option_bag)
option_bag.properties = await self.cfgimpl_get_settings().getproperties(option_bag)
self = await self.get_subconfig(option_bag,
validate_properties)
assert isinstance(self, SubConfig), _('unknown option {}').format(path[-1])
return self, path[-1]
@ -212,35 +220,35 @@ class SubConfig(object):
def cfgimpl_get_values(self):
return self.cfgimpl_get_context()._impl_values
def setattr(self,
value,
option_bag,
_commit=True):
async def setattr(self,
value,
option_bag,
_commit=True):
if option_bag.option.impl_is_symlinkoption():
raise ConfigError(_("can't set value to a SymLinkOption"))
context = option_bag.config_bag.context
context.cfgimpl_get_settings().validate_properties(option_bag)
await context.cfgimpl_get_settings().validate_properties(option_bag)
if option_bag.option.impl_is_leader() and len(value) < self._impl_length:
raise LeadershipError(_('cannot reduce length of the leader "{}"'
'').format(option_bag.option.impl_get_display_name()))
return context.cfgimpl_get_values().setvalue(value,
option_bag,
_commit)
return await context.cfgimpl_get_values().setvalue(value,
option_bag,
_commit)
def delattr(self,
option_bag,
_commit=True):
async def delattr(self,
option_bag,
_commit=True):
option = option_bag.option
if option.impl_is_symlinkoption():
raise ConfigError(_("can't delete a SymLinkOption"))
values = self.cfgimpl_get_values()
if option_bag.index is not None:
values.reset_follower(option_bag,
_commit)
await values.reset_follower(option_bag,
_commit)
else:
values.reset(option_bag,
_commit)
await values.reset(option_bag,
_commit)
def _get_subpath(self, name):
if self._impl_path is None:
@ -249,27 +257,29 @@ class SubConfig(object):
subpath = self._impl_path + '.' + name
return subpath
def get_subconfig(self,
option_bag):
self.cfgimpl_get_settings().validate_properties(option_bag)
return SubConfig(option_bag.option,
self._impl_context,
option_bag.config_bag,
option_bag.path)
async def get_subconfig(self,
option_bag: OptionBag,
validate_properties: bool=True) -> 'SubConfig':
if validate_properties:
await self.cfgimpl_get_settings().validate_properties(option_bag)
return await SubConfig(option_bag.option,
self._impl_context,
option_bag.config_bag,
option_bag.path)
def getattr(self,
name,
option_bag,
from_follower=False,
needs_re_verify_follower_properties=False):
async def getattr(self,
name,
option_bag,
from_follower=False,
needs_re_verify_follower_properties=False):
"""
:return: option's value if name is an option name, OptionDescription
otherwise
"""
config_bag = option_bag.config_bag
if '.' in name:
self, name = self.cfgimpl_get_home_by_path(name,
config_bag)
self, name = await self.cfgimpl_get_home_by_path(name,
config_bag)
option = option_bag.option
if option.impl_is_symlinkoption():
@ -278,22 +288,23 @@ class SubConfig(object):
None,
option_bag.index,
config_bag)
soption_bag.properties = await self.cfgimpl_get_settings().getproperties(soption_bag)
soption_bag.ori_option = option
context = self.cfgimpl_get_context()
return context.getattr(soption_bag.path,
return await context.getattr(soption_bag.path,
soption_bag)
#if not from_follower or needs_re_verify_follower_properties:
if option.impl_is_follower() and not from_follower:
needs_re_verify_follower_properties = self.cfgimpl_get_settings().has_properties_index(option_bag)
needs_re_verify_follower_properties = await self.cfgimpl_get_settings().has_properties_index(option_bag)
if not option.impl_is_follower() or \
(needs_re_verify_follower_properties and option_bag.index is not None) or \
(needs_re_verify_follower_properties and option_bag.index is not None) or \
(not needs_re_verify_follower_properties and (not from_follower or option_bag.index is None)):
self.cfgimpl_get_settings().validate_properties(option_bag)
await self.cfgimpl_get_settings().validate_properties(option_bag)
if option.impl_is_follower() and not from_follower:
length = self.cfgimpl_get_length_leadership(option_bag)
follower_len = self.cfgimpl_get_values()._p_.get_max_length(option_bag.path)
length = await self.cfgimpl_get_length_leadership(option_bag)
follower_len = await self.cfgimpl_get_values()._p_.get_max_length(option_bag.path)
if follower_len > length:
raise LeadershipError(_('the follower option "{}" has greater length ({}) than the leader '
'length ({})').format(option.impl_get_display_name(),
@ -308,39 +319,40 @@ class SubConfig(object):
option_bag.path,
idx,
config_bag)
soption_bag.properties = await self.cfgimpl_get_settings().getproperties(soption_bag)
try:
value.append(self.getattr(name,
soption_bag,
from_follower=True,
needs_re_verify_follower_properties=needs_re_verify_follower_properties))
value.append(await self.getattr(name,
soption_bag,
from_follower=True,
needs_re_verify_follower_properties=needs_re_verify_follower_properties))
except PropertiesOptionError as err:
value.append(err)
else:
value = self.cfgimpl_get_values().get_cached_value(option_bag)
value = await self.cfgimpl_get_values().get_cached_value(option_bag)
self.cfgimpl_get_settings().validate_mandatory(value,
option_bag)
return value
def find(self,
bytype,
byname,
byvalue,
config_bag,
_subpath=None,
raise_if_not_found=True,
only_path=undefined,
only_option=undefined,
with_option=False):
async def find(self,
bytype,
byname,
byvalue,
config_bag,
_subpath=None,
raise_if_not_found=True,
only_path=undefined,
only_option=undefined,
with_option=False):
"""
convenience method for finding an option that lives only in the subtree
:param first: return only one option if True, a list otherwise
:return: find list or an exception if nothing has been found
"""
def _filter_by_value(soption_bag):
async def _filter_by_value(soption_bag):
try:
value = context.getattr(path,
soption_bag)
value = await context.getattr(path,
soption_bag)
except PropertiesOptionError:
return False
if isinstance(value, list):
@ -350,34 +362,37 @@ class SubConfig(object):
found = False
if only_path is not undefined:
options = [only_option]
async def _fake_iter():
yield only_option
options = _fake_iter()
else:
options = self.cfgimpl_get_description().get_children_recursively(bytype,
byname,
config_bag)
context = self.cfgimpl_get_context()
for option in options:
async for option in options:
option_bag = OptionBag()
path = option.impl_getpath()
option_bag.set_option(option,
path,
None,
config_bag)
if byvalue is not undefined and not _filter_by_value(option_bag):
option_bag.properties = await self.cfgimpl_get_settings().getproperties(option_bag)
if byvalue is not undefined and not await _filter_by_value(option_bag):
continue
elif config_bag.properties:
#remove option with propertyerror, ...
try:
if '.' in path:
subconfig, subpath = context.cfgimpl_get_home_by_path(path,
config_bag)
subconfig, subpath = await context.cfgimpl_get_home_by_path(path,
config_bag)
else:
subconfig = self
subpath = path
subconfig.cfgimpl_get_description().get_child(subpath,
config_bag,
subconfig.cfgimpl_get_path())
self.cfgimpl_get_settings().validate_properties(option_bag)
await subconfig.cfgimpl_get_description().get_child(subpath,
config_bag,
subconfig.cfgimpl_get_path())
await self.cfgimpl_get_settings().validate_properties(option_bag)
except PropertiesOptionError:
continue
found = True
@ -395,13 +410,13 @@ class SubConfig(object):
raise AttributeError(_("no option found in config"
" with these criteria"))
def make_dict(self,
config_bag,
flatten=False,
_currpath=None,
withoption=None,
withvalue=undefined,
fullpath=False):
async def make_dict(self,
config_bag,
flatten=False,
_currpath=None,
withoption=None,
withvalue=undefined,
fullpath=False):
"""exports the whole config into a `dict`
:returns: dict of Option's name (or path) and values
"""
@ -412,49 +427,50 @@ class SubConfig(object):
raise ValueError(_("make_dict can't filtering with value without "
"option"))
context = self.cfgimpl_get_context()
self._make_dict(context,
config_bag,
flatten,
_currpath,
withoption,
withvalue,
fullpath,
pathsvalues)
await self._make_dict(context,
config_bag,
flatten,
_currpath,
withoption,
withvalue,
fullpath,
pathsvalues)
return pathsvalues
def _make_dict(self,
context,
config_bag,
flatten,
_currpath,
withoption,
withvalue,
fullpath,
pathsvalues):
async def _make_dict(self,
context,
config_bag,
flatten,
_currpath,
withoption,
withvalue,
fullpath,
pathsvalues):
if withoption is not None:
# Find all option with criteria
# retrieve OptionDescription and make_dict on it
mypath = self.cfgimpl_get_path()
for path in context.find(bytype=None,
byname=withoption,
byvalue=withvalue,
_subpath=self.cfgimpl_get_path(False),
config_bag=config_bag):
async for path in context.find(bytype=None,
byname=withoption,
byvalue=withvalue,
_subpath=self.cfgimpl_get_path(False),
config_bag=config_bag):
path = '.'.join(path.split('.')[:-1])
if '.' in path:
subconfig, subpath = context.cfgimpl_get_home_by_path(path,
config_bag)
subconfig, subpath = await context.cfgimpl_get_home_by_path(path,
config_bag)
else:
subconfig = context
subpath = path
opt = subconfig.cfgimpl_get_description().get_child(subpath,
config_bag,
subconfig.cfgimpl_get_path())
opt = await subconfig.cfgimpl_get_description().get_child(subpath,
config_bag,
subconfig.cfgimpl_get_path())
soption_bag = OptionBag()
soption_bag.set_option(opt,
path,
None,
config_bag)
soption_bag.properties = await self.cfgimpl_get_settings().getproperties(soption_bag)
if mypath is not None:
if mypath == path:
withoption = None
@ -466,18 +482,19 @@ class SubConfig(object):
'should start with "{1}"'
'').format(path, mypath)
path = path[len(tmypath):]
self._make_sub_dict(path,
pathsvalues,
_currpath,
flatten,
soption_bag,
fullpath,
context,
withvalue)
await self._make_sub_dict(path,
pathsvalues,
_currpath,
flatten,
soption_bag,
fullpath,
context,
withvalue)
#withoption can be set to None below !
if withoption is None:
for opt in self.cfgimpl_get_description().get_children(config_bag):
children = await self.cfgimpl_get_description().get_children(config_bag)
for opt in children:
name = opt.impl_getname()
path = self._get_subpath(name)
soption_bag = OptionBag()
@ -485,48 +502,49 @@ class SubConfig(object):
path,
None,
config_bag)
self._make_sub_dict(name,
pathsvalues,
_currpath,
flatten,
soption_bag,
fullpath,
context,
withvalue)
soption_bag.properties = await self.cfgimpl_get_settings().getproperties(soption_bag)
await self._make_sub_dict(name,
pathsvalues,
_currpath,
flatten,
soption_bag,
fullpath,
context,
withvalue)
return pathsvalues
def _make_sub_dict(self,
name,
pathsvalues,
_currpath,
flatten,
option_bag,
fullpath,
context,
withvalue):
async def _make_sub_dict(self,
name,
pathsvalues,
_currpath,
flatten,
option_bag,
fullpath,
context,
withvalue):
option = option_bag.option
if option.impl_is_optiondescription():
try:
self.cfgimpl_get_settings().validate_properties(option_bag)
subconfig = SubConfig(option_bag.option,
self._impl_context,
option_bag.config_bag,
option_bag.path)
subconfig._make_dict(context,
option_bag.config_bag,
flatten,
_currpath + [name],
None,
withvalue,
fullpath,
pathsvalues)
await self.cfgimpl_get_settings().validate_properties(option_bag)
subconfig = await SubConfig(option_bag.option,
self._impl_context,
option_bag.config_bag,
option_bag.path)
await subconfig._make_dict(context,
option_bag.config_bag,
flatten,
_currpath + [name],
None,
withvalue,
fullpath,
pathsvalues)
except PropertiesOptionError as err:
if err.proptype in (['mandatory'], ['empty']):
raise err
else:
try:
ret = self.getattr(name,
option_bag)
ret = await self.getattr(name,
option_bag)
except PropertiesOptionError as err:
# import traceback
# traceback.print_exc()
@ -559,93 +577,105 @@ class _CommonConfig(SubConfig):
'parents',
'impl_type')
def _impl_build_all_caches(self):
async def _impl_build_all_caches(self):
descr = self.cfgimpl_get_description()
if not descr.impl_already_build_caches():
descr._group_type = groups.root
descr._build_cache(display_name=self._display_name)
config_bag = ConfigBag(context=self)
descr.impl_build_force_store_values(config_bag)
await descr._build_cache(display_name=self._display_name)
if not hasattr(descr, '_cache_force_store_values'):
raise ConfigError(_('option description seems to be part of an other '
'config'))
def get_parents(self):
for parent in self.parents:
yield parent()
# information
def impl_set_information(self, key, value):
async def impl_set_information(self,
key,
value):
"""updates the information's attribute
:param key: information's key (ex: "help", "doc"
:param value: information's value (ex: "the help string")
"""
self._impl_values.set_information(key, value)
await self._impl_values.set_information(key,
value)
def impl_get_information(self, key, default=undefined):
async def impl_get_information(self,
key,
default=undefined):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
return self._impl_values.get_information(key, default)
return await self._impl_values.get_information(key,
default)
def impl_del_information(self, key, raises=True):
self._impl_values.del_information(key, raises)
async def impl_del_information(self,
key,
raises=True):
await self._impl_values.del_information(key,
raises)
def impl_list_information(self):
return self._impl_values.list_information()
async def impl_list_information(self):
return await self._impl_values.list_information()
def __getstate__(self):
raise NotImplementedError()
def _gen_fake_values(self):
fake_config = KernelConfig(self._impl_descr,
persistent=False,
force_values=get_default_values_storages(),
force_settings=self.cfgimpl_get_settings(),
display_name=self._display_name)
fake_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation())
async def _gen_fake_values(self):
fake_config = await KernelConfig(self._impl_descr,
persistent=False,
force_values=await get_default_values_storages(),
force_settings=self.cfgimpl_get_settings(),
display_name=self._display_name)
export = await self.cfgimpl_get_values()._p_.exportation()
await fake_config.cfgimpl_get_values()._p_.importation(export)
fake_config.parents = self.parents
return fake_config
def duplicate(self,
session_id=None,
force_values=None,
force_settings=None,
storage=None,
persistent=False,
metaconfig_prefix=None,
child=None,
deep=None):
async def duplicate(self,
session_id=None,
force_values=None,
force_settings=None,
storage=None,
persistent=False,
metaconfig_prefix=None,
child=None,
deep=None):
assert isinstance(self, (KernelConfig, KernelMixConfig)), _('cannot duplicate {}').format(self.__class__.__name__)
if isinstance(self, KernelConfig):
duplicated_config = KernelConfig(self._impl_descr,
_duplicate=True,
session_id=session_id,
force_values=force_values,
force_settings=force_settings,
persistent=persistent,
storage=storage,
display_name=self._display_name)
duplicated_config = await KernelConfig(self._impl_descr,
_duplicate=True,
session_id=session_id,
force_values=force_values,
force_settings=force_settings,
persistent=persistent,
storage=storage,
display_name=self._display_name)
else:
if session_id is None and metaconfig_prefix is not None:
session_id = metaconfig_prefix + self.impl_getname()
duplicated_config = KernelMetaConfig([],
_duplicate=True,
optiondescription=self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
duplicated_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation())
properties = self.cfgimpl_get_settings()._p_.exportation()
duplicated_config.cfgimpl_get_settings()._p_.importation(properties)
duplicated_config.cfgimpl_get_settings()._pp_.importation(self.cfgimpl_get_settings(
)._pp_.exportation())
duplicated_config.cfgimpl_get_settings().ro_append = self.cfgimpl_get_settings().ro_append
duplicated_config.cfgimpl_get_settings().rw_append = self.cfgimpl_get_settings().rw_append
duplicated_config.cfgimpl_get_settings().ro_remove = self.cfgimpl_get_settings().ro_remove
duplicated_config.cfgimpl_get_settings().rw_remove = self.cfgimpl_get_settings().rw_remove
duplicated_config.cfgimpl_get_settings().default_properties = self.cfgimpl_get_settings().default_properties
duplicated_config.cfgimpl_reset_cache(None, None)
duplicated_config = await KernelMetaConfig([],
_duplicate=True,
optiondescription=self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
duplicated_values = duplicated_config.cfgimpl_get_values()
duplicated_settings = duplicated_config.cfgimpl_get_settings()
await duplicated_values._p_.importation(await self.cfgimpl_get_values()._p_.exportation())
properties = await self.cfgimpl_get_settings()._p_.exportation()
await duplicated_settings._p_.importation(properties)
await duplicated_settings._pp_.importation(await self.cfgimpl_get_settings()._pp_.exportation())
duplicated_settings.ro_append = self.cfgimpl_get_settings().ro_append
duplicated_settings.rw_append = self.cfgimpl_get_settings().rw_append
duplicated_settings.ro_remove = self.cfgimpl_get_settings().ro_remove
duplicated_settings.rw_remove = self.cfgimpl_get_settings().rw_remove
duplicated_settings.default_properties = self.cfgimpl_get_settings().default_properties
await duplicated_config.cfgimpl_reset_cache(None, None)
if child is not None:
duplicated_config._impl_children.append(child)
child.parents.append(weakref.ref(duplicated_config))
@ -655,11 +685,11 @@ class _CommonConfig(SubConfig):
wparent = parent()
if wparent not in deep:
deep.append(wparent)
duplicated_config = wparent.duplicate(deep=deep,
storage=storage,
metaconfig_prefix=metaconfig_prefix,
child=duplicated_config,
persistent=persistent)
duplicated_config = await wparent.duplicate(deep=deep,
storage=storage,
metaconfig_prefix=metaconfig_prefix,
child=duplicated_config,
persistent=persistent)
else:
duplicated_config.parents = self.parents
for parent in self.parents:
@ -677,6 +707,7 @@ class _CommonConfig(SubConfig):
# ____________________________________________________________
@asyncinit
class KernelConfig(_CommonConfig):
"main configuration management entry"
__slots__ = ('__weakref__',
@ -685,15 +716,15 @@ class KernelConfig(_CommonConfig):
'_impl_symlink')
impl_type = 'config'
def __init__(self,
descr,
session_id=None,
persistent=False,
force_values=None,
force_settings=None,
display_name=None,
_duplicate=False,
storage=None):
async def __init__(self,
descr,
session_id=None,
persistent=False,
force_values=None,
force_settings=None,
display_name=None,
_duplicate=False,
storage=None):
""" Configuration option management class
:param descr: describes the configuration schema
@ -721,43 +752,45 @@ class KernelConfig(_CommonConfig):
self._impl_settings = force_settings
self._impl_permissives_cache = Cache()
self._impl_properties_cache = Cache()
self._impl_values = Values(force_values)
self._impl_values = await Values(force_values)
self._impl_values_cache = Cache()
else:
properties, permissives, values, session_id = get_storages(self,
session_id,
persistent,
storage=storage)
properties, permissives, values, session_id = await get_storages(self,
session_id,
persistent,
storage=storage)
if not valid_name(session_id):
raise ValueError(_("invalid session ID: {0} for config").format(session_id))
self._impl_settings = Settings(properties,
permissives)
self._impl_permissives_cache = Cache()
self._impl_properties_cache = Cache()
self._impl_values = Values(values)
self._impl_values = await Values(values)
self._impl_values_cache = Cache()
super().__init__(descr,
weakref.ref(self),
ConfigBag(self),
None)
self._impl_context = weakref.ref(self)
await super().__init__(descr,
self._impl_context,
None,
None)
if None in [force_settings, force_values]:
self._impl_build_all_caches()
await self._impl_build_all_caches()
self._impl_name = session_id
def impl_getname(self):
return self._impl_name
@asyncinit
class KernelGroupConfig(_CommonConfig):
__slots__ = ('__weakref__',
'_impl_children',
'_impl_name')
impl_type = 'group'
def __init__(self,
children,
session_id=None,
_descr=None):
async def __init__(self,
children,
session_id=None,
_descr=None):
assert isinstance(children, list), _("groupconfig's children must be a list")
names = []
for child in children:
@ -775,23 +808,26 @@ class KernelGroupConfig(_CommonConfig):
self.parents = []
session_id = gen_storage_id(session_id, self)
assert valid_name(session_id), _("invalid session ID: {0} for config").format(session_id)
super().__init__(_descr,
weakref.ref(self),
ConfigBag(self),
None)
config_bag = ConfigBag(self,
properties=None,
permissives=None)
await super().__init__(_descr,
weakref.ref(self),
config_bag,
None)
self._impl_name = session_id
def cfgimpl_get_children(self):
return self._impl_children
def cfgimpl_reset_cache(self,
option_bag,
resetted_opts=None):
async def cfgimpl_reset_cache(self,
option_bag,
resetted_opts=None):
if resetted_opts is None:
resetted_opts = []
if isinstance(self, KernelMixConfig):
super().cfgimpl_reset_cache(option_bag,
resetted_opts=copy(resetted_opts))
await super().cfgimpl_reset_cache(option_bag,
resetted_opts=copy(resetted_opts))
for child in self._impl_children:
if option_bag is not None:
coption_bag = option_bag.copy()
@ -800,16 +836,16 @@ class KernelGroupConfig(_CommonConfig):
coption_bag.config_bag = cconfig_bag
else:
coption_bag = None
child.cfgimpl_reset_cache(coption_bag,
resetted_opts=copy(resetted_opts))
await child.cfgimpl_reset_cache(coption_bag,
resetted_opts=copy(resetted_opts))
def set_value(self,
path,
index,
value,
config_bag,
only_config=False,
_commit=True):
async def set_value(self,
path,
index,
value,
config_bag,
only_config=False,
_commit=True):
"""Setattr not in current KernelGroupConfig, but in each children
"""
ret = []
@ -823,27 +859,33 @@ class KernelGroupConfig(_CommonConfig):
cconfig_bag = config_bag.copy()
cconfig_bag.context = child
if isinstance(child, KernelGroupConfig):
ret.extend(child.set_value(path,
index,
value,
cconfig_bag,
only_config=only_config,
_commit=commit))
ret.extend(await child.set_value(path,
index,
value,
cconfig_bag,
only_config=only_config,
_commit=commit))
else:
settings = child.cfgimpl_get_settings()
properties = await settings.get_context_properties(child._impl_properties_cache)
permissives = await settings.get_context_permissives()
cconfig_bag.properties = properties
cconfig_bag.permissives = permissives
try:
subconfig, name = child.cfgimpl_get_home_by_path(path,
cconfig_bag)
option = subconfig.cfgimpl_get_description().get_child(name,
cconfig_bag,
child.cfgimpl_get_path())
subconfig, name = await child.cfgimpl_get_home_by_path(path,
cconfig_bag)
option = await subconfig.cfgimpl_get_description().get_child(name,
cconfig_bag,
child.cfgimpl_get_path())
option_bag = OptionBag()
option_bag.set_option(option,
path,
index,
cconfig_bag)
child.setattr(value,
option_bag,
_commit=commit)
option_bag.properties = await settings.getproperties(option_bag)
await child.setattr(value,
option_bag,
_commit=commit)
except PropertiesOptionError as err:
ret.append(PropertiesOptionError(err._option_bag,
err.proptype,
@ -854,18 +896,18 @@ class KernelGroupConfig(_CommonConfig):
except (ValueError, LeadershipError, AttributeError) as err:
ret.append(err)
if _commit and self.impl_type != 'group':
self.cfgimpl_get_values()._p_.commit()
await self.cfgimpl_get_values()._p_.commit()
return ret
def find_group(self,
config_bag,
byname=None,
bypath=undefined,
byoption=undefined,
byvalue=undefined,
raise_if_not_found=True,
_sub=False):
async def find_group(self,
config_bag,
byname=None,
bypath=undefined,
byoption=undefined,
byvalue=undefined,
raise_if_not_found=True,
_sub=False):
"""Find first not in current KernelGroupConfig, but in each children
"""
# if KernelMetaConfig, all children have same OptionDescription in
@ -873,38 +915,42 @@ class KernelGroupConfig(_CommonConfig):
if bypath is undefined and byname is not None and \
isinstance(self,
KernelMixConfig):
bypath, byoption = next(self.find(bytype=None,
byvalue=undefined,
byname=byname,
config_bag=config_bag,
raise_if_not_found=raise_if_not_found,
with_option=True))
async for bypath, byoption in self.find(bytype=None,
byvalue=undefined,
byname=byname,
config_bag=config_bag,
raise_if_not_found=raise_if_not_found,
with_option=True):
break
byname = None
ret = []
for child in self._impl_children:
if isinstance(child, KernelGroupConfig):
ret.extend(child.find_group(byname=byname,
bypath=bypath,
byoption=byoption,
byvalue=byvalue,
config_bag=config_bag,
raise_if_not_found=False,
_sub=True))
ret.extend(await child.find_group(byname=byname,
bypath=bypath,
byoption=byoption,
byvalue=byvalue,
config_bag=config_bag,
raise_if_not_found=False,
_sub=True))
else:
try:
cconfig_bag = config_bag.copy()
cconfig_bag.context = child
next(child.find(None,
byname,
byvalue,
config_bag=cconfig_bag,
raise_if_not_found=False,
only_path=bypath,
only_option=byoption))
cconfig_bag = config_bag.copy()
cconfig_bag.context = child
settings = child.cfgimpl_get_settings()
properties = await settings.get_context_properties(child._impl_properties_cache)
permissives = await settings.get_context_permissives()
cconfig_bag.properties = properties
cconfig_bag.permissives = permissives
async for path in child.find(None,
byname,
byvalue,
config_bag=cconfig_bag,
raise_if_not_found=False,
only_path=bypath,
only_option=byoption):
ret.append(child)
except StopIteration:
pass
break
if not _sub:
self._find_return_results(ret != [],
raise_if_not_found)
@ -913,25 +959,31 @@ class KernelGroupConfig(_CommonConfig):
def impl_getname(self):
return self._impl_name
def reset(self,
path,
_commit=True):
async def reset(self,
path,
_commit=True):
for child in self._impl_children:
config_bag = ConfigBag(child)
settings = child.cfgimpl_get_settings()
properties = await settings.get_context_properties(child._impl_properties_cache)
permissives = await settings.get_context_permissives()
config_bag = ConfigBag(child,
properties=properties,
permissives=permissives)
config_bag.remove_validation()
subconfig, name = child.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().get_child(name,
config_bag,
subconfig.cfgimpl_get_path())
subconfig, name = await child.cfgimpl_get_home_by_path(path,
config_bag)
option = await subconfig.cfgimpl_get_description().get_child(name,
config_bag,
subconfig.cfgimpl_get_path())
option_bag = OptionBag()
option_bag.set_option(option,
path,
option,
None,
config_bag)
option_bag.properties = await child.cfgimpl_get_settings().getproperties(option_bag)
option_bag.config_bag.context = child
child.cfgimpl_get_values().reset(option_bag,
_commit=_commit)
await child.cfgimpl_get_values().reset(option_bag,
_commit=_commit)
def getconfig(self,
name):
@ -941,19 +993,20 @@ class KernelGroupConfig(_CommonConfig):
raise ConfigError(_('unknown config "{}"').format(name))
@asyncinit
class KernelMixConfig(KernelGroupConfig):
__slots__ = ('_display_name',
'_impl_symlink')
impl_type = 'mix'
def __init__(self,
optiondescription,
children,
session_id=None,
persistent=False,
storage=None,
display_name=None,
_duplicate=False):
async def __init__(self,
optiondescription,
children,
session_id=None,
persistent=False,
storage=None,
display_name=None,
_duplicate=False):
# FIXME _duplicate
self._display_name = display_name
self._impl_symlink = []
@ -961,31 +1014,31 @@ class KernelMixConfig(KernelGroupConfig):
if not isinstance(child, (KernelConfig, KernelMixConfig)):
raise TypeError(_("child must be a Config, MixConfig or MetaConfig"))
child.parents.append(weakref.ref(self))
properties, permissives, values, session_id = get_storages(self,
session_id,
persistent,
storage=storage)
properties, permissives, values, session_id = await get_storages(self,
session_id,
persistent,
storage=storage)
self._impl_settings = Settings(properties,
permissives)
self._impl_permissives_cache = Cache()
self._impl_properties_cache = Cache()
self._impl_values = Values(values)
self._impl_values = await Values(values)
self._impl_values_cache = Cache()
super().__init__(children,
session_id=session_id,
_descr=optiondescription)
self._impl_build_all_caches()
await super().__init__(children,
session_id=session_id,
_descr=optiondescription)
await self._impl_build_all_caches()
def set_value(self,
path,
index,
value,
config_bag,
force_default=False,
force_dont_change_value=False,
force_default_if_same=False,
only_config=False,
_commit=True):
async def set_value(self,
path,
index,
value,
config_bag,
force_default=False,
force_dont_change_value=False,
force_default_if_same=False,
only_config=False,
_commit=True):
"""only_config: could be set if you want modify value in all Config included in
this KernelMetaConfig
"""
@ -994,23 +1047,24 @@ class KernelMixConfig(KernelGroupConfig):
raise ValueError(_('force_default, force_default_if_same or '
'force_dont_change_value cannot be set with'
' only_config'))
return super().set_value(path,
index,
value,
config_bag,
only_config=only_config,
_commit=_commit)
return await super().set_value(path,
index,
value,
config_bag,
only_config=only_config,
_commit=_commit)
ret = []
subconfig, name = self.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().get_child(name,
config_bag,
self.cfgimpl_get_path())
subconfig, name = await self.cfgimpl_get_home_by_path(path,
config_bag)
option = await subconfig.cfgimpl_get_description().get_child(name,
config_bag,
self.cfgimpl_get_path())
option_bag = OptionBag()
option_bag.set_option(option,
path,
index,
config_bag)
option_bag.properties = await self.cfgimpl_get_settings().getproperties(option_bag)
if force_default or force_default_if_same or force_dont_change_value:
if force_default and force_dont_change_value:
raise ValueError(_('force_default and force_dont_change_value'
@ -1018,40 +1072,48 @@ class KernelMixConfig(KernelGroupConfig):
for child in self._impl_children:
cconfig_bag = config_bag.copy()
cconfig_bag.context = child
settings = child.cfgimpl_get_settings()
properties = await settings.get_context_properties(child._impl_properties_cache)
permissives = await settings.get_context_permissives()
cconfig_bag.properties = properties
cconfig_bag.permissives = permissives
try:
subconfig2, name = child.cfgimpl_get_home_by_path(path,
cconfig_bag)
subconfig2, name = await child.cfgimpl_get_home_by_path(path,
cconfig_bag)
if self.impl_type == 'meta':
moption_bag = option_bag
moption_bag = option_bag.copy()
del moption_bag.properties
del moption_bag.permissives
moption_bag.config_bag = cconfig_bag
moption_bag.properties = await settings.getproperties(moption_bag)
else:
option = subconfig2.cfgimpl_get_description().get_child(name,
cconfig_bag,
child.cfgimpl_get_path())
option = await subconfig2.cfgimpl_get_description().get_child(name,
cconfig_bag,
child.cfgimpl_get_path())
moption_bag = OptionBag()
moption_bag.set_option(option,
path,
index,
cconfig_bag)
moption_bag.properties = await settings.getproperties(moption_bag)
if force_default_if_same:
if not child.cfgimpl_get_values()._p_.hasvalue(path):
if not await child.cfgimpl_get_values()._p_.hasvalue(path):
child_value = undefined
else:
child_value = subconfig2.getattr(name,
moption_bag)
child_value = await subconfig2.getattr(name,
moption_bag)
if force_default or (force_default_if_same and value == child_value):
child.cfgimpl_get_values().reset(moption_bag,
_commit=False)
await child.cfgimpl_get_values().reset(moption_bag,
_commit=False)
continue
if force_dont_change_value:
child_value = child.getattr(name,
moption_bag)
child_value = await child.getattr(name,
moption_bag)
if value != child_value:
subconfig2.setattr(child_value,
moption_bag,
_commit=False)
await subconfig2.setattr(child_value,
moption_bag,
_commit=False)
except PropertiesOptionError as err:
ret.append(PropertiesOptionError(err._option_bag,
err.proptype,
@ -1064,46 +1126,52 @@ class KernelMixConfig(KernelGroupConfig):
try:
if self.impl_type == 'meta':
del option_bag.properties
del option_bag.permissives
option_bag.config_bag = config_bag
subconfig.setattr(value,
option_bag,
_commit=False)
moption_bag = option_bag.copy()
#del option_bag.properties
#del option_bag.permissives
moption_bag.config_bag = config_bag
moption_bag.properties = await config_bag.context.cfgimpl_get_settings().getproperties(moption_bag)
else:
moption_bag = option_bag
await subconfig.setattr(value,
moption_bag,
_commit=False)
except (PropertiesOptionError, ValueError, LeadershipError) as err:
ret.append(err)
return ret
def reset(self,
path,
only_children,
config_bag,
commit=True):
async def reset(self,
path,
only_children,
config_bag,
commit=True):
rconfig_bag = config_bag.copy()
rconfig_bag.remove_validation()
if self.impl_type == 'meta':
subconfig, name = self.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().get_child(name,
config_bag,
subconfig.cfgimpl_get_path())
subconfig, name = await self.cfgimpl_get_home_by_path(path,
config_bag)
option = await subconfig.cfgimpl_get_description().get_child(name,
config_bag,
subconfig.cfgimpl_get_path())
option_bag = OptionBag()
option_bag.set_option(option,
path,
None,
rconfig_bag)
option_bag.properties = await self.cfgimpl_get_settings().getproperties(option_bag)
elif not only_children:
try:
subconfig, name = self.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().get_child(name,
config_bag,
subconfig.cfgimpl_get_path())
subconfig, name = await self.cfgimpl_get_home_by_path(path,
config_bag)
option = await subconfig.cfgimpl_get_description().get_child(name,
config_bag,
subconfig.cfgimpl_get_path())
option_bag = OptionBag()
option_bag.set_option(option,
path,
None,
rconfig_bag)
option_bag.properties = await self.cfgimpl_get_settings().getproperties(option_bag)
except AttributeError:
only_children = True
for child in self._impl_children:
@ -1113,34 +1181,35 @@ class KernelMixConfig(KernelGroupConfig):
moption_bag = option_bag
moption_bag.config_bag = rconfig_bag
else:
subconfig, name = child.cfgimpl_get_home_by_path(path,
rconfig_bag)
option = subconfig.cfgimpl_get_description().get_child(name,
rconfig_bag,
child.cfgimpl_get_path())
subconfig, name = await child.cfgimpl_get_home_by_path(path,
rconfig_bag)
option = await subconfig.cfgimpl_get_description().get_child(name,
rconfig_bag,
child.cfgimpl_get_path())
moption_bag = OptionBag()
moption_bag.set_option(option,
path,
None,
rconfig_bag)
child.cfgimpl_get_values().reset(moption_bag,
_commit=False)
moption_bag.properties = await self.cfgimpl_get_settings().getproperties(moption_bag)
await child.cfgimpl_get_values().reset(moption_bag,
_commit=False)
except AttributeError:
pass
if isinstance(child, KernelMixConfig):
child.reset(path,
False,
rconfig_bag,
commit=False)
await child.reset(path,
False,
rconfig_bag,
commit=False)
if not only_children:
option_bag.config_bag = config_bag
self.cfgimpl_get_values().reset(option_bag,
_commit=False)
await self.cfgimpl_get_values().reset(option_bag,
_commit=False)
if commit:
self.cfgimpl_get_values()._p_.commit()
await self.cfgimpl_get_values()._p_.commit()
def add_config(self,
apiconfig):
async def add_config(self,
apiconfig):
config = apiconfig._config_bag.context
if config.impl_getname() in [child.impl_getname() for child in self._impl_children]:
raise ConflictError(_('config name must be uniq in '
@ -1148,15 +1217,15 @@ class KernelMixConfig(KernelGroupConfig):
config.parents.append(weakref.ref(self))
self._impl_children.append(config)
config.cfgimpl_reset_cache(None, None)
await config.cfgimpl_reset_cache(None, None)
def pop_config(self,
session_id,
config):
async def pop_config(self,
session_id,
config):
if session_id is not None:
for idx, child in enumerate(self._impl_children):
if session_id == child.impl_getname():
child.cfgimpl_reset_cache(None, None)
await child.cfgimpl_reset_cache(None, None)
self._impl_children.pop(idx)
break
else:
@ -1173,18 +1242,19 @@ class KernelMixConfig(KernelGroupConfig):
return child
@asyncinit
class KernelMetaConfig(KernelMixConfig):
__slots__ = tuple()
impl_type = 'meta'
def __init__(self,
children,
session_id=None,
persistent=False,
optiondescription=None,
storage=None,
display_name=None,
_duplicate=False):
async def __init__(self,
children,
session_id=None,
persistent=False,
optiondescription=None,
storage=None,
display_name=None,
_duplicate=False):
descr = None
self._display_name = display_name
if optiondescription is not None:
@ -1194,10 +1264,10 @@ class KernelMetaConfig(KernelMixConfig):
assert isinstance(child_session_id, str), _('MetaConfig with optiondescription'
' must have string has child, '
'not {}').format(child_session_id)
new_children.append(KernelConfig(optiondescription,
persistent=persistent,
session_id=child_session_id,
display_name=self._display_name))
new_children.append(await KernelConfig(optiondescription,
persistent=persistent,
session_id=child_session_id,
display_name=self._display_name))
children = new_children
descr = optiondescription
for child in children:
@ -1209,59 +1279,61 @@ class KernelMetaConfig(KernelMixConfig):
elif descr is not child.cfgimpl_get_description():
raise ValueError(_('all config in metaconfig must '
'have the same optiondescription'))
super().__init__(descr,
children,
persistent=persistent,
storage=storage,
session_id=session_id)
await super().__init__(descr,
children,
persistent=persistent,
storage=storage,
session_id=session_id)
def new_config(self,
session_id,
type_='config',
persistent=False,
storage=None):
async def new_config(self,
session_id,
type_='config',
persistent=False,
storage=None):
if session_id in [child.impl_getname() for child in self._impl_children]:
raise ConflictError(_('config name must be uniq in '
'groupconfig for {0}').format(session_id))
assert type_ in ('config', 'metaconfig', 'mixconfig'), _('unknown type {}').format(type_)
new = not persistent or session_id not in list_sessions()
if type_ == 'config':
config = KernelConfig(self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
config = await KernelConfig(self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
elif type_ == 'metaconfig':
config = KernelMetaConfig([],
optiondescription=self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
config = await KernelMetaConfig([],
optiondescription=self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
elif type_ == 'mixconfig':
config = KernelMixConfig(children=[],
optiondescription=self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
config = await KernelMixConfig(children=[],
optiondescription=self._impl_descr,
session_id=session_id,
persistent=persistent,
storage=storage,
display_name=self._display_name)
# Copy context properties/permissives
if new:
config.cfgimpl_get_settings().set_context_properties(self.cfgimpl_get_settings().get_context_properties(config._impl_properties_cache), config)
config.cfgimpl_get_settings().set_context_permissives(self.cfgimpl_get_settings().get_context_permissives())
config.cfgimpl_get_settings().ro_append = self.cfgimpl_get_settings().ro_append
config.cfgimpl_get_settings().rw_append = self.cfgimpl_get_settings().rw_append
config.cfgimpl_get_settings().ro_remove = self.cfgimpl_get_settings().ro_remove
config.cfgimpl_get_settings().rw_remove = self.cfgimpl_get_settings().rw_remove
config.cfgimpl_get_settings().default_properties = self.cfgimpl_get_settings().default_properties
settings = config.cfgimpl_get_settings()
properties = await self.cfgimpl_get_settings().get_context_properties(config._impl_properties_cache)
await settings.set_context_properties(properties, config)
await settings.set_context_permissives(await self.cfgimpl_get_settings().get_context_permissives())
settings.ro_append = self.cfgimpl_get_settings().ro_append
settings.rw_append = self.cfgimpl_get_settings().rw_append
settings.ro_remove = self.cfgimpl_get_settings().ro_remove
settings.rw_remove = self.cfgimpl_get_settings().rw_remove
settings.default_properties = self.cfgimpl_get_settings().default_properties
config.parents.append(weakref.ref(self))
self._impl_children.append(config)
return config
def add_config(self,
apiconfig):
async def add_config(self,
apiconfig):
if self._impl_descr is not apiconfig._config_bag.context.cfgimpl_get_description():
raise ValueError(_('metaconfig must '
'have the same optiondescription'))
super().add_config(apiconfig)
await super().add_config(apiconfig)

View File

@ -84,16 +84,12 @@ class PropertiesOptionError(AttributeError):
return self.msg
if self._settings is None:
return 'error'
properties = list(self._settings.calc_raises_properties(self._option_bag,
apply_requires=False))
for property_ in self._settings.get_calculated_properties(self._option_bag):
prop = property_.help(self._option_bag)
if prop is not None:
properties.append(prop)
#for property_ in self._settings.get_calculated_properties(self._option_bag):
# prop = property_.help(self._option_bag)
# if prop is not None:
# properties.append(prop)
if not properties:
# if proptype == ['mandatory']
properties = self.proptype
properties = list(self.proptype)
only_one = len(properties) == 1
properties_msg = display_list(properties, add_quote=True)
if only_one:

View File

@ -29,7 +29,7 @@ from ..i18n import _
from ..setting import undefined, Settings
from ..value import Values
from ..error import ConfigError, display_list
from ..autolib import Calculation, Params, ParamContext, ParamOption, ParamIndex
from ..autolib import Calculation, Params, ParamOption, ParamIndex
STATIC_TUPLE = frozenset()
@ -55,7 +55,6 @@ class Base:
'_properties',
'_has_dependency',
'_dependencies',
'_has_calc_context',
'__weakref__'
)

View File

@ -50,15 +50,15 @@ class ChoiceOption(Option):
raise TypeError(_('values must be a tuple or a calculation for {0}'
).format(name))
self._choice_values = values
super(ChoiceOption, self).__init__(name,
doc,
*args,
**kwargs)
super().__init__(name,
doc,
*args,
**kwargs)
def impl_get_values(self,
option_bag):
async def impl_get_values(self,
option_bag):
if isinstance(self._choice_values, Calculation):
values = self._choice_values.execute(option_bag)
values = await self._choice_values.execute(option_bag)
if values is not undefined and not isinstance(values, list):
raise ConfigError(_('calculated values for {0} is not a list'
'').format(self.impl_getname()))
@ -70,10 +70,23 @@ class ChoiceOption(Option):
value: Any) -> None:
pass
def validate_with_option(self,
value: Any,
option_bag: OptionBag) -> None:
values = self.impl_get_values(option_bag)
def sync_validate_with_option(self,
value: Any,
option_bag: OptionBag) -> None:
if isinstance(self._choice_values, Calculation):
return
values = self._choice_values
if values is not undefined and value not in values:
if len(values) == 1:
raise ValueError(_('only "{0}" is allowed'
'').format(values[0]))
raise ValueError(_('only {0} are allowed'
'').format(display_list(values, add_quote=True)))
async def validate_with_option(self,
value: Any,
option_bag: OptionBag) -> None:
values = await self.impl_get_values(option_bag)
if values is not undefined and value not in values:
if len(values) == 1:
raise ValueError(_('only "{0}" is allowed'

View File

@ -83,6 +83,10 @@ class DomainnameOption(StrOption):
if allow_ip:
msg = _('could be a IP, otherwise {}').format(msg)
msg_warning = _('could be a IP, otherwise {}').format(msg_warning)
if not allow_cidr_network:
regexp = r'(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))'.format(regexp)
else:
regexp = r'(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9][0-9]))'.format(regexp)
regexp = r'^{0}$'.format(regexp)
extra['_domain_re'] = re.compile(regexp)
extra['_domain_re_message'] = msg

View File

@ -27,7 +27,7 @@ from .optiondescription import OptionDescription
from .baseoption import BaseOption
from ..setting import OptionBag, ConfigBag, groups, undefined
from ..error import ConfigError
from ..autolib import carry_out_calculation, Calculation
from ..autolib import Calculation
NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
@ -53,7 +53,7 @@ class DynOptionDescription(OptionDescription):
if __debug__ and child.impl_get_group_type() != groups.leadership:
raise ConfigError(_('cannot set optiondescription in a '
'dynoptiondescription'))
for chld in child.get_children(config_bag=undefined):
for chld in child._children[1]:
chld._setsubdyn(self)
if __debug__ and child.impl_is_symlinkoption():
raise ConfigError(_('cannot set symlinkoption in a '
@ -67,15 +67,14 @@ class DynOptionDescription(OptionDescription):
suffix):
return suffix
def get_suffixes(self,
config_bag: ConfigBag) -> List[str]:
async def get_suffixes(self,
config_bag: ConfigBag) -> List[str]:
option_bag = OptionBag()
option_bag.set_option(self,
self.impl_getpath(),
None,
config_bag)
values = self._suffixes.execute(option_bag)
values = await self._suffixes.execute(option_bag)
if __debug__:
if not isinstance(values, list):
raise ValueError(_('DynOptionDescription suffixes for option "{}", is not a list ({})'

View File

@ -111,10 +111,10 @@ class Leadership(OptionDescription):
opt = opt.opt
return opt in self._children[1]
def reset(self,
values: Values,
option_bag: OptionBag,
_commit: bool=True) -> None:
async def reset(self,
values: Values,
option_bag: OptionBag,
_commit: bool=True) -> None:
config_bag = option_bag.config_bag.copy()
config_bag.remove_validation()
for follower in self.get_followers():
@ -124,41 +124,43 @@ class Leadership(OptionDescription):
follower_path,
None,
config_bag)
values.reset(soption_bag,
_commit=_commit)
soption_bag.properties = await config_bag.context.cfgimpl_get_settings().getproperties(soption_bag)
await values.reset(soption_bag,
_commit=_commit)
def follower_force_store_value(self,
values,
value,
option_bag,
owner,
_commit) -> None:
async def follower_force_store_value(self,
values,
value,
option_bag,
owner,
_commit) -> None:
settings = option_bag.config_bag.context.cfgimpl_get_settings()
if value:
rgevalue = range(len(value))
for follower in self.get_children(option_bag.config_bag):
for follower in await self.get_children(option_bag.config_bag):
foption_bag = OptionBag()
foption_bag.set_option(follower,
follower.impl_getpath(),
None,
option_bag.config_bag)
if 'force_store_value' in settings.getproperties(foption_bag):
if 'force_store_value' in await settings.getproperties(foption_bag):
for index in rgevalue:
foption_bag = OptionBag()
foption_bag.set_option(follower,
follower.impl_getpath(),
index,
option_bag.config_bag)
values._setvalue(foption_bag,
values.getvalue(foption_bag),
owner,
commit=False)
foption_bag.properties = await settings.getproperties(foption_bag)
await values._setvalue(foption_bag,
await values.getvalue(foption_bag),
owner,
commit=False)
def pop(self,
values: Values,
index: int,
option_bag: OptionBag,
followers: Optional[List[Option]]=undefined) -> None:
async def pop(self,
values: Values,
index: int,
option_bag: OptionBag,
followers: Optional[List[Option]]=undefined) -> None:
if followers is undefined:
# followers are not undefined only in SynDynLeadership
followers = self.get_followers()
@ -166,7 +168,7 @@ class Leadership(OptionDescription):
config_bag.remove_validation()
for follower in followers:
follower_path = follower.impl_getpath()
followerlen = values._p_.get_max_length(follower_path)
followerlen = await values._p_.get_max_length(follower_path)
soption_bag = OptionBag()
soption_bag.set_option(follower,
follower_path,
@ -174,16 +176,17 @@ class Leadership(OptionDescription):
config_bag)
# do not check force_default_on_freeze or force_metaconfig_on_freeze
soption_bag.properties = set()
if not values.is_default_owner(soption_bag,
validate_meta=False) and followerlen > index:
values._p_.resetvalue_index(follower_path,
index,
True)
is_default = await values.is_default_owner(soption_bag,
validate_meta=False)
if not is_default and followerlen > index:
await values._p_.resetvalue_index(follower_path,
index,
True)
if followerlen > index + 1:
for idx in range(index + 1, followerlen):
if values._p_.hasvalue(follower_path, idx):
values._p_.reduce_index(follower_path,
idx)
if await values._p_.hasvalue(follower_path, idx):
await values._p_.reduce_index(follower_path,
idx)
def reset_cache(self,
path: str,
@ -212,7 +215,8 @@ class Leadership(OptionDescription):
follower.reset_cache(spath,
config_bag,
None)
resetted_opts.append(spath)
# do not reset dependencies option
# resetted_opts.append(spath)
def impl_is_leadership(self) -> None:
return True

View File

@ -27,7 +27,7 @@ from itertools import chain
from .baseoption import BaseOption, submulti, STATIC_TUPLE
from ..i18n import _
from ..setting import undefined, OptionBag, Undefined
from ..autolib import Calculation, Params, ParamValue, ParamContext, ParamOption
from ..autolib import Calculation, Params, ParamValue, ParamOption
from ..error import (ConfigError, ValueWarning, ValueErrorWarning, PropertiesOptionError,
ValueOptionError, display_list)
from .syndynoption import SynDynOption
@ -101,9 +101,7 @@ class Option(BaseOption):
if not isinstance(validator, Calculation):
raise ValueError(_('validators must be a Calculation for "{}"').format(name))
for param in chain(validator.params.args, validator.params.kwargs.values()):
if isinstance(param, ParamContext):
self._has_calc_context = True
elif isinstance(param, ParamOption):
if isinstance(param, ParamOption):
param.option._add_dependency(self)
self._has_dependency = True
@ -123,8 +121,8 @@ class Option(BaseOption):
undefined)
try:
self.validate(value)
self.validate_with_option(value,
option_bag)
self.sync_validate_with_option(value,
option_bag)
except ValueError as err:
str_err = str(err)
if not str_err:
@ -153,11 +151,11 @@ class Option(BaseOption):
undefined,
None,
undefined)
self.impl_validate(default,
option_bag)
self.impl_validate(default,
option_bag,
check_error=False)
self.sync_impl_validate(default,
option_bag)
self.sync_impl_validate(default,
option_bag,
check_error=False)
self.value_dependencies(default)
if (is_multi and default != []) or \
(not is_multi and default is not None):
@ -179,9 +177,7 @@ class Option(BaseOption):
def value_dependency(self,
value: Any) -> Any:
for param in chain(value.params.args, value.params.kwargs.values()):
if isinstance(param, ParamContext):
self._has_calc_context = True
elif isinstance(param, ParamOption):
if isinstance(param, ParamOption):
param.option._add_dependency(self)
#__________________________________________________________________________
@ -237,11 +233,82 @@ class Option(BaseOption):
#__________________________________________________________________________
# validator
def sync_impl_validate(self,
value: Any,
option_bag: OptionBag,
check_error: bool=True) -> None:
"""
"""
is_warnings_only = getattr(self, '_warnings_only', False)
def impl_validate(self,
value: Any,
option_bag: OptionBag,
check_error: bool=True) -> None:
def do_validation(_value,
_index):
if isinstance(_value, list):
raise ValueError(_('which must not be a list').format(_value,
self.impl_get_display_name()))
if _value is not None:
if check_error:
# option validation
self.validate(_value)
self.sync_validate_with_option(_value,
option_bag)
if ((check_error and not is_warnings_only) or
(not check_error and is_warnings_only)):
try:
self.second_level_validation(_value,
is_warnings_only)
except ValueError as err:
if is_warnings_only:
warnings.warn_explicit(ValueWarning(_value,
self._display_name,
self,
'{0}'.format(err),
_index),
ValueWarning,
self.__class__.__name__, 0)
else:
raise err
try:
if isinstance(value, Calculation):
pass
elif not self.impl_is_multi():
val = value
err_index = None
do_validation(val, None)
elif self.impl_is_submulti():
if not isinstance(value, list):
raise ValueError(_('which must be a list'))
for err_index, lval in enumerate(value):
if isinstance(lval, Calculation):
continue
if not isinstance(lval, list):
raise ValueError(_('which "{}" must be a list of list'
'').format(lval))
for val in lval:
if isinstance(val, Calculation):
continue
do_validation(val,
err_index)
else:
# it's a multi
if not isinstance(value, list):
raise ValueError(_('which must be a list'))
for err_index, val in enumerate(value):
if isinstance(val, Calculation):
continue
do_validation(val,
err_index)
except ValueError as err:
raise ValueOptionError(val,
self._display_name,
option_bag.ori_option,
'{0}'.format(err),
err_index)
async def impl_validate(self,
value: Any,
option_bag: OptionBag,
check_error: bool=True) -> None:
"""
"""
config_bag = option_bag.config_bag
@ -264,8 +331,8 @@ class Option(BaseOption):
raise ValueError(_('the value "{}" is not unique'
'').format(val))
def calculation_validator(val,
_index):
async def calculation_validator(val,
_index):
for validator in getattr(self, '_validators', []):
calc_is_warnings_only = hasattr(validator, 'warnings_only') and validator.warnings_only
if ((check_error and not calc_is_warnings_only) or
@ -279,9 +346,9 @@ class Option(BaseOption):
soption_bag.index = _index
kwargs['orig_value'] = value
validator.execute(soption_bag,
leadership_must_have_index=True,
**kwargs)
await validator.execute(soption_bag,
leadership_must_have_index=True,
**kwargs)
except ValueError as err:
if calc_is_warnings_only:
warnings.warn_explicit(ValueWarning(val,
@ -302,8 +369,8 @@ class Option(BaseOption):
ValueWarning,
self.__class__.__name__, 316)
def do_validation(_value,
_index):
async def do_validation(_value,
_index):
if isinstance(_value, list):
raise ValueError(_('which must not be a list').format(_value,
self.impl_get_display_name()))
@ -313,8 +380,8 @@ class Option(BaseOption):
if check_error:
# option validation
self.validate(_value)
self.validate_with_option(_value,
option_bag)
await self.validate_with_option(_value,
option_bag)
if ((check_error and not is_warnings_only) or
(not check_error and is_warnings_only)):
try:
@ -331,24 +398,24 @@ class Option(BaseOption):
self.__class__.__name__, 0)
else:
raise err
calculation_validator(_value,
_index)
await calculation_validator(_value,
_index)
try:
val = value
err_index = force_index
if not self.impl_is_multi():
do_validation(val, None)
await do_validation(val, None)
elif force_index is not None:
if self.impl_is_submulti():
if not isinstance(value, list):
raise ValueError(_('which must be a list'))
_is_not_unique(value, option_bag)
for val in value:
do_validation(val,
force_index)
await do_validation(val,
force_index)
else:
do_validation(val,
force_index)
await do_validation(val,
force_index)
elif isinstance(value, Calculation) and config_bag is undefined:
pass
elif not isinstance(value, list):
@ -362,14 +429,14 @@ class Option(BaseOption):
raise ValueError(_('which "{}" must be a list of list'
'').format(lval))
for val in lval:
do_validation(val,
err_index)
await do_validation(val,
err_index)
else:
_is_not_unique(value, option_bag)
# FIXME subtimal, not several time is whole=True!
for err_index, val in enumerate(value):
do_validation(val,
err_index)
await do_validation(val,
err_index)
except ValueError as err:
if config_bag is undefined or \
'demoting_error_warning' not in config_bag.properties:
@ -399,9 +466,14 @@ class Option(BaseOption):
raise ValueError(_('default value not allowed if option "{0}" '
'is calculated').format(self.impl_getname()))
def validate_with_option(self,
value: Any,
option_bag: OptionBag) -> None:
def sync_validate_with_option(self,
value: Any,
option_bag: OptionBag) -> None:
pass
async def validate_with_option(self,
value: Any,
option_bag: OptionBag) -> None:
pass
def second_level_validation(self,

View File

@ -35,14 +35,14 @@ class CacheOptionDescription(BaseOption):
def impl_already_build_caches(self) -> bool:
return self.impl_is_readonly()
def _build_cache(self,
path='',
_consistencies=None,
_consistencies_id=0,
currpath: List[str]=None,
cache_option=None,
force_store_values=None,
display_name=None) -> None:
async def _build_cache(self,
path='',
_consistencies=None,
_consistencies_id=0,
currpath: List[str]=None,
cache_option=None,
force_store_values=None,
display_name=None) -> None:
"""validate options and set option has readonly option
"""
# _consistencies is None only when we start to build cache
@ -60,20 +60,20 @@ class CacheOptionDescription(BaseOption):
# cache already set
raise ConfigError(_('option description seems to be part of an other '
'config'))
for option in self.get_children(config_bag=undefined,
dyn=False):
for option in await self.get_children(config_bag=undefined,
dyn=False):
if __debug__:
cache_option.append(option)
sub_currpath = currpath + [option.impl_getname()]
subpath = '.'.join(sub_currpath)
if isinstance(option, OptionDescription):
option._build_cache(subpath,
_consistencies,
_consistencies_id,
sub_currpath,
cache_option,
force_store_values,
display_name)
await option._build_cache(subpath,
_consistencies,
_consistencies_id,
sub_currpath,
cache_option,
force_store_values,
display_name)
else:
is_multi = option.impl_is_multi()
if not option.impl_is_symlinkoption():
@ -94,10 +94,6 @@ class CacheOptionDescription(BaseOption):
'"force_metaconfig_on_freeze" '
'property without "frozen"'
'').format(option.impl_get_display_name()))
# if context is set to callback, must be reset each time a value change
if hasattr(option, '_has_calc_context'):
self._add_dependency(option)
if option.impl_is_readonly():
raise ConflictError(_('duplicate option: {0}').format(option))
if not self.impl_is_readonly() and display_name:
@ -109,17 +105,14 @@ class CacheOptionDescription(BaseOption):
self._path = self._name
self._set_readonly()
def impl_build_force_store_values(self,
config_bag: ConfigBag) -> None:
if not hasattr(self, '_cache_force_store_values'):
raise ConfigError(_('option description seems to be part of an other '
'config'))
async def impl_build_force_store_values(self,
config_bag: ConfigBag) -> None:
if 'force_store_value' not in config_bag.properties:
return
commit = False
values = config_bag.context.cfgimpl_get_values()
for subpath, option in self._cache_force_store_values:
if not values._p_.hasvalue(subpath):
if not await values._p_.hasvalue(subpath):
if option.impl_is_follower():
option_bag = OptionBag()
leader = option.impl_get_leadership().get_leader()
@ -128,7 +121,7 @@ class CacheOptionDescription(BaseOption):
None,
config_bag)
option_bag.properties = frozenset()
follower_len = len(values.getvalue(option_bag))
follower_len = len(await values.getvalue(option_bag))
for index in range(follower_len):
option_bag = OptionBag()
option_bag.set_option(option,
@ -136,11 +129,11 @@ class CacheOptionDescription(BaseOption):
index,
config_bag)
option_bag.properties = frozenset()
values._p_.setvalue(subpath,
values.getvalue(option_bag),
owners.forced,
index,
False)
await values._p_.setvalue(subpath,
await values.getvalue(option_bag),
owners.forced,
index,
False)
else:
option_bag = OptionBag()
option_bag.set_option(option,
@ -148,24 +141,24 @@ class CacheOptionDescription(BaseOption):
None,
config_bag)
option_bag.properties = frozenset()
values._p_.setvalue(subpath,
values.getvalue(option_bag),
owners.forced,
None,
False)
await values._p_.setvalue(subpath,
await values.getvalue(option_bag),
owners.forced,
None,
False)
commit = True
if commit:
values._p_.commit()
await values._p_.commit()
class OptionDescriptionWalk(CacheOptionDescription):
__slots__ = ('_children',)
def get_child(self,
name: str,
config_bag: ConfigBag,
subpath: str) -> Union[BaseOption, SynDynOptionDescription]:
async def get_child(self,
name: str,
config_bag: ConfigBag,
subpath: str) -> Union[BaseOption, SynDynOptionDescription]:
# if not dyn
if name in self._children[0]:
return self._children[1][self._children[0].index(name)]
@ -174,7 +167,7 @@ class OptionDescriptionWalk(CacheOptionDescription):
if child.impl_is_dynoptiondescription():
cname = child.impl_getname()
if name.startswith(cname):
for suffix in child.get_suffixes(config_bag):
for suffix in await child.get_suffixes(config_bag):
if name == cname + child.convert_suffix_to_path(suffix):
return child.to_dynoption(subpath,
suffix,
@ -188,35 +181,37 @@ class OptionDescriptionWalk(CacheOptionDescription):
'in optiondescription "{1}"'
'').format(name, self.impl_get_display_name()))
def get_children(self,
config_bag: Union[ConfigBag, Undefined],
dyn: bool=True) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
async def get_children(self,
config_bag: Union[ConfigBag, Undefined],
dyn: bool=True) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
if not dyn or config_bag is undefined or \
config_bag.context.cfgimpl_get_description() == self:
subpath = ''
else:
subpath = self.impl_getpath()
children = []
for child in self._children[1]:
if dyn and child.impl_is_dynoptiondescription():
for suffix in child.get_suffixes(config_bag):
yield child.to_dynoption(subpath,
suffix,
child)
for suffix in await child.get_suffixes(config_bag):
children.append(child.to_dynoption(subpath,
suffix,
child))
else:
yield child
children.append(child)
return children
def get_children_recursively(self,
bytype: Optional[BaseOption],
byname: Optional[str],
config_bag: ConfigBag,
self_opt: BaseOption=None) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
async def get_children_recursively(self,
bytype: Optional[BaseOption],
byname: Optional[str],
config_bag: ConfigBag,
self_opt: BaseOption=None) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
if self_opt is None:
self_opt = self
for option in self_opt.get_children(config_bag):
for option in await self_opt.get_children(config_bag):
if option.impl_is_optiondescription():
for subopt in option.get_children_recursively(bytype,
byname,
config_bag):
async for subopt in option.get_children_recursively(bytype,
byname,
config_bag):
yield subopt
elif (byname is None or option.impl_getname() == byname) and \
(bytype is None or isinstance(option, bytype)):

View File

@ -39,8 +39,6 @@ class SynDynOptionDescription:
subpath: str,
suffix: str,
ori_dyn) -> None:
if opt.__class__.__name__.startswith('L') and ori_dyn is None:
raise Exception()
self._opt = opt
if subpath is None:
subpath = ''
@ -59,10 +57,10 @@ class SynDynOptionDescription:
def impl_getopt(self) -> BaseOption:
return self._opt
def get_child(self,
name: str,
config_bag: ConfigBag,
subpath: str) -> BaseOption:
async def get_child(self,
name: str,
config_bag: ConfigBag,
subpath: str) -> BaseOption:
if name.endswith(self._suffix):
oname = name[:-len(self._suffix)]
try:
@ -78,43 +76,39 @@ class SynDynOptionDescription:
'in dynamic optiondescription "{1}"'
'').format(name, self.impl_get_display_name()))
def impl_getname(self,
for_path=False) -> str:
if for_path == 'toto':
if self.ori_dyn:
opt = self.ori_dyn
else:
opt = self._opt
return self._opt.impl_getname() + opt.convert_suffix_to_path(self._suffix)
def impl_getname(self) -> str:
return self._opt.impl_getname() + self._suffix
def impl_is_dynoptiondescription(self) -> bool:
return True
def get_children(self,
config_bag: ConfigBag,
dyn: bool=True):
async def get_children(self,
config_bag: ConfigBag,
dyn: bool=True):
subpath = self.impl_getpath()
for child in self._opt.get_children(config_bag):
yield child.to_dynoption(subpath,
self._suffix,
self._opt)
children = []
for child in await self._opt.get_children(config_bag):
children.append(child.to_dynoption(subpath,
self._suffix,
self._opt))
return children
def get_children_recursively(self,
bytype: Optional[BaseOption],
byname: Optional[str],
config_bag: ConfigBag,
self_opt: BaseOption=None) -> BaseOption:
return self._opt.get_children_recursively(bytype,
byname,
config_bag,
self)
async def get_children_recursively(self,
bytype: Optional[BaseOption],
byname: Optional[str],
config_bag: ConfigBag,
self_opt: BaseOption=None) -> BaseOption:
async for option in self._opt.get_children_recursively(bytype,
byname,
config_bag,
self):
yield option
def impl_getpath(self) -> str:
subpath = self._subpath
if subpath != '':
subpath += '.'
return subpath + self.impl_getname(for_path=True)
return subpath + self.impl_getname()
def impl_get_display_name(self) -> str:
return self._opt.impl_get_display_name() + self._suffix
@ -145,9 +139,9 @@ class SynDynLeadership(SynDynOptionDescription):
config_bag,
resetted_opts)
def pop(self,
*args,
**kwargs) -> None:
self._opt.pop(*args,
followers=self.get_followers(),
**kwargs)
async def pop(self,
*args,
**kwargs) -> None:
await self._opt.pop(*args,
followers=self.get_followers(),
**kwargs)

View File

@ -18,6 +18,7 @@
from itertools import chain
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list
from .i18n import _
from .asyncinit import asyncinit
"""If cache and expire is enable, time before cache is expired.
@ -153,18 +154,13 @@ class OptionBag:
self.config_bag = config_bag
def __getattr__(self, key):
if key == 'properties':
settings = self.config_bag.context.cfgimpl_get_settings()
self.properties = settings.getproperties(self,
apply_requires=self.apply_requires)
return self.properties
elif key == 'ori_option':
if key == 'ori_option':
return self.option
elif key == 'apply_requires':
return True
elif key == 'properties_setted':
return False
raise KeyError('unknown key {} for OptionBag'.format(key)) # pragma: no cover
raise KeyError('unknown key "{}" for OptionBag'.format(key)) # pragma: no cover
def __setattr__(self, key, val):
super().__setattr__(key, val)
@ -178,7 +174,7 @@ class OptionBag:
except AttributeError:
pass
return
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
raise KeyError(_('cannot delete key "{}" for OptionBag').format(key)) # pragma: no cover
def copy(self):
option_bag = OptionBag()
@ -199,20 +195,18 @@ class ConfigBag:
'expiration_time' # EXPIRATION_TIME
)
def __init__(self, context, **kwargs):
def __init__(self,
context,
properties: set,
permissives: frozenset,
**kwargs):
self.context = context
self.properties = properties
self.permissives = permissives
for key, value in kwargs.items():
setattr(self, key, value)
def __getattr__(self, key):
if key == 'properties':
settings = self.context.cfgimpl_get_settings()
self.properties = settings.get_context_properties(self.context._impl_properties_cache)
return self.properties
if key == 'permissives':
settings = self.context.cfgimpl_get_settings()
self.permissives = settings.get_context_permissives()
return self.permissives
if key == 'true_properties':
return self.properties
if key == 'expiration_time':
@ -220,7 +214,10 @@ class ConfigBag:
return self.expiration_time
if key == 'is_unrestraint':
return False
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
raise KeyError('unknown key "{}" for ConfigBag'.format(key)) # pragma: no cover
def __setattr__(self, key, value):
super().__setattr__(key, value)
def remove_warnings(self):
self.properties = frozenset(self.properties - {'warnings'})
@ -236,22 +233,9 @@ class ConfigBag:
def set_permissive(self):
self.properties = frozenset(self.properties | {'permissive'})
def __delattr__(self, key):
if key in ['properties', 'permissives']:
try:
super().__delattr__(key)
except AttributeError:
pass
return
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
def copy(self):
kwargs = {}
for key in self.__slots__:
if key in ['properties', 'permissives', 'true_properties'] and \
not hasattr(self.context, '_impl_settings'):
# not for GroupConfig
continue
kwargs[key] = getattr(self, key)
return ConfigBag(**kwargs)
@ -406,8 +390,8 @@ class Settings(object):
# ____________________________________________________________
# get properties and permissive methods
def get_context_properties(self,
cache):
async def get_context_properties(self,
cache):
is_cached, props, validated = cache.getcache(None,
None,
None,
@ -415,9 +399,9 @@ class Settings(object):
{},
'context_props')
if not is_cached:
props = self._p_.getproperties(None,
None,
self.default_properties)
props = await self._p_.getproperties(None,
None,
self.default_properties)
cache.setcache(None,
None,
props,
@ -426,10 +410,10 @@ class Settings(object):
True)
return props
def getproperties(self,
option_bag,
apply_requires=True,
uncalculated=False):
async def getproperties(self,
option_bag,
apply_requires=True,
uncalculated=False):
"""
"""
option = option_bag.option
@ -451,20 +435,20 @@ class Settings(object):
is_cached = False
if not is_cached:
props = set()
p_props = self._p_.getproperties(path,
None,
option.impl_getproperties())
p_props = await self._p_.getproperties(path,
None,
option.impl_getproperties())
if index is not None:
p_props = chain(p_props,
self._p_.getproperties(path,
index,
option.impl_getproperties()))
await self._p_.getproperties(path,
index,
option.impl_getproperties()))
for prop in p_props:
if uncalculated or isinstance(prop, str):
props.add(prop)
elif apply_requires:
new_prop = prop.execute(option_bag,
leadership_must_have_index=True)
new_prop = await prop.execute(option_bag,
leadership_must_have_index=True)
if new_prop is None:
continue
elif not isinstance(new_prop, str):
@ -474,7 +458,7 @@ class Settings(object):
if not option.impl_is_optiondescription() and option.impl_is_leader() and new_prop not in ALLOWED_LEADER_PROPERTIES:
raise LeadershipError(_('leader cannot have "{}" property').format(new_prop))
props.add(new_prop)
props -= self.getpermissives(option_bag)
props -= await self.getpermissives(option_bag)
if not uncalculated and apply_requires and not config_bag.is_unrestraint:
cache.setcache(path,
index,
@ -484,48 +468,48 @@ class Settings(object):
True)
return props
def get_calculated_properties(self,
option_bag):
async def get_calculated_properties(self,
option_bag):
option = option_bag.option
if option.impl_is_symlinkoption():
option = option.impl_getopt()
path = option.impl_getpath()
p_props = self._p_.getproperties(path,
None,
option.impl_getproperties())
p_props = await self._p_.getproperties(path,
None,
option.impl_getproperties())
if option_bag.index is not None:
p_props = chain(p_props,
self._p_.getproperties(path,
option_bag.index,
option.impl_getproperties()))
await self._p_.getproperties(path,
option_bag.index,
option.impl_getproperties()))
for prop in p_props:
if not isinstance(prop, str):
yield prop
def has_properties_index(self,
option_bag):
async def has_properties_index(self,
option_bag):
option = option_bag.option
if option.impl_is_symlinkoption():
option = option.impl_getopt()
path = option.impl_getpath()
p_props = self._p_.getproperties(path,
None,
option.impl_getproperties())
p_props = await self._p_.getproperties(path,
None,
option.impl_getproperties())
if option_bag.index is not None:
p_props = chain(p_props,
self._p_.getproperties(path,
option_bag.index,
option.impl_getproperties()))
await self._p_.getproperties(path,
option_bag.index,
option.impl_getproperties()))
for prop in p_props:
if not isinstance(prop, str) and prop.has_index(option_bag.option):
return True
return False
def get_context_permissives(self):
return self.getpermissives(None)
async def get_context_permissives(self):
return await self.getpermissives(None)
def getpermissives(self,
option_bag):
async def getpermissives(self,
option_bag):
if option_bag is None:
path = None
index = None
@ -537,26 +521,27 @@ class Settings(object):
else:
path = option_bag.path
index = option_bag.index
permissives = self._pp_.getpermissives(path, None)
permissives = await self._pp_.getpermissives(path, None)
if index is not None:
permissives = frozenset(self._pp_.getpermissives(path, index) | permissives)
option_permissives = await self._pp_.getpermissives(path, index)
permissives = frozenset(option_permissives | permissives)
return permissives
#____________________________________________________________
# set methods
def set_context_properties(self,
properties,
context):
self._p_.setproperties(None,
None,
properties)
context.cfgimpl_reset_cache(None)
async def set_context_properties(self,
properties,
context):
await self._p_.setproperties(None,
None,
properties)
await context.cfgimpl_reset_cache(None)
def setproperties(self,
path,
properties,
option_bag,
context):
async def setproperties(self,
path,
properties,
option_bag,
context):
"""save properties for specified path
(never save properties if same has option properties)
"""
@ -576,21 +561,21 @@ class Settings(object):
raise LeadershipError(_('a leader ({0}) cannot have '
'"force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
'').format(opt.impl_get_display_name()))
self._p_.setproperties(path,
option_bag.index,
properties)
await self._p_.setproperties(path,
option_bag.index,
properties)
# values too because of follower values could have a PropertiesOptionError has value
context.cfgimpl_reset_cache(option_bag)
del option_bag.properties
await context.cfgimpl_reset_cache(option_bag)
option_bag.properties = properties
def set_context_permissives(self,
permissives):
self.setpermissives(None,
permissives)
async def set_context_permissives(self,
permissives):
await self.setpermissives(None,
permissives)
def setpermissives(self,
option_bag,
permissives):
async def setpermissives(self,
option_bag,
permissives):
"""
enables us to put the permissives in the storage
@ -616,16 +601,16 @@ class Settings(object):
if forbidden_permissives:
raise ConfigError(_('cannot add those permissives: {0}').format(
' '.join(forbidden_permissives)))
self._pp_.setpermissives(path, index, permissives)
await self._pp_.setpermissives(path, index, permissives)
if option_bag is not None:
option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
await option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
#____________________________________________________________
# reset methods
def reset(self,
option_bag,
context):
async def reset(self,
option_bag,
context):
if option_bag is None:
opt = None
path = None
@ -637,12 +622,12 @@ class Settings(object):
"").format(opt.impl_get_display_name())
path = option_bag.path
index = option_bag.index
self._p_.delproperties(path, index)
context.cfgimpl_reset_cache(option_bag)
await self._p_.delproperties(path, index)
await context.cfgimpl_reset_cache(option_bag)
def reset_permissives(self,
option_bag,
context):
async def reset_permissives(self,
option_bag,
context):
if option_bag is None:
opt = None
path = None
@ -654,19 +639,19 @@ class Settings(object):
"").format(opt.impl_get_display_name())
index = option_bag.index
path = option_bag.path
self._pp_.delpermissive(path, index)
context.cfgimpl_reset_cache(option_bag)
await self._pp_.delpermissive(path, index)
await context.cfgimpl_reset_cache(option_bag)
#____________________________________________________________
# validate properties
def calc_raises_properties(self,
option_bag,
apply_requires=True):
async def calc_raises_properties(self,
option_bag,
apply_requires=True):
if apply_requires and option_bag.properties_setted:
option_properties = option_bag.properties
else:
option_properties = self.getproperties(option_bag,
apply_requires=apply_requires)
option_properties = await self.getproperties(option_bag,
apply_requires=apply_requires)
return self._calc_raises_properties(option_bag.config_bag.properties,
option_bag.config_bag.permissives,
option_properties)
@ -683,8 +668,8 @@ class Settings(object):
# at this point an option should not remain in properties
return properties
def validate_properties(self,
option_bag):
async def validate_properties(self,
option_bag):
"""
validation upon the properties related to `opt`
@ -695,7 +680,7 @@ class Settings(object):
config_bag = option_bag.config_bag
if not config_bag.properties or config_bag.properties == frozenset(['cache']): # pragma: no cover
return
properties = self.calc_raises_properties(option_bag)
properties = await self.calc_raises_properties(option_bag)
if properties != frozenset():
raise PropertiesOptionError(option_bag,
properties,
@ -741,13 +726,13 @@ class Settings(object):
#____________________________________________________________
# read only/read write
def _read(self,
remove,
append,
context):
props = self._p_.getproperties(None,
None,
self.default_properties)
async def _read(self,
remove,
append,
context):
props = await self._p_.getproperties(None,
None,
self.default_properties)
modified = False
if remove & props:
props = props - remove
@ -756,19 +741,19 @@ class Settings(object):
props = props | append
modified = True
if modified:
self.set_context_properties(frozenset(props),
context)
await self.set_context_properties(frozenset(props),
context)
def read_only(self,
context):
async def read_only(self,
context):
"convenience method to freeze, hide and disable"
self._read(self.ro_remove,
self.ro_append,
context)
await self._read(self.ro_remove,
self.ro_append,
context)
def read_write(self,
context):
async def read_write(self,
context):
"convenience method to freeze, hide and disable"
self._read(self.rw_remove,
self.rw_append,
context)
await self._read(self.rw_remove,
self.rw_append,
context)

View File

@ -97,32 +97,34 @@ def gen_storage_id(session_id,
return 'c' + str(id(config)) + str(int(time())) + str(randint(0, 500))
def get_storages(context,
session_id,
persistent,
storage):
async def get_storages(context,
session_id,
persistent,
storage):
session_id = gen_storage_id(session_id,
context)
if storage is None:
storage = default_storage
imp = storage.get()
imp_storage = imp.Storage(session_id,
persistent)
imp_storage = await imp.Storage(session_id,
persistent)
properties = imp.Properties(imp_storage)
permissives = imp.Permissives(imp_storage)
values = imp.Values(imp_storage)
return properties, permissives, values, session_id
def get_default_values_storages():
async def get_default_values_storages():
imp = memory_storage.get()
storage = imp.Storage('__validator_storage', persistent=False, test=True)
storage = await imp.Storage('__validator_storage',
persistent=False,
test=True)
return imp.Values(storage)
def get_default_settings_storages():
async def get_default_settings_storages():
imp = memory_storage.get()
storage = imp.Storage('__validator_storage', persistent=False, test=True)
storage = await imp.Storage('__validator_storage', persistent=False, test=True)
properties = imp.Properties(storage)
permissives = imp.Permissives(storage)
return properties, permissives

View File

@ -30,11 +30,11 @@ class Properties:
self._storage = storage
# properties
def setproperties(self, path, index, properties):
async def setproperties(self, path, index, properties):
log.debug('setproperties %s %s %s', path, index, properties)
self._properties.setdefault(path, {})[index] = properties
def getproperties(self, path, index, default_properties):
async def getproperties(self, path, index, default_properties):
if path not in self._properties:
ret = frozenset(default_properties)
else:
@ -42,19 +42,19 @@ class Properties:
log.debug('getproperties %s %s %s', path, index, ret)
return ret
def delproperties(self, path, index):
async def delproperties(self, path, index):
log.debug('delproperties %s', path)
if path in self._properties and index in self._properties[path]:
del(self._properties[path][index])
def exportation(self):
async def exportation(self):
"""return all modified settings in a dictionary
example: {'path1': set(['prop1', 'prop2'])}
"""
return deepcopy(self._properties)
def importation(self, properties):
async def importation(self, properties):
self._properties = properties
@ -67,11 +67,11 @@ class Permissives:
self._permissives = {}
self._storage = storage
def setpermissives(self, path, index, permissives):
async def setpermissives(self, path, index, permissives):
log.debug('setpermissives %s %s', path, permissives)
self._permissives.setdefault(path, {})[index] = permissives
def getpermissives(self, path, index):
async def getpermissives(self, path, index):
if not path in self._permissives:
ret = frozenset()
else:
@ -79,16 +79,16 @@ class Permissives:
log.debug('getpermissives %s %s', path, ret)
return ret
def delpermissive(self, path, index):
async def delpermissive(self, path, index):
log.debug('delpermissive %s', path)
if path in self._permissives and index in self._permissives[path]:
del(self._permissives[path][index])
def exportation(self):
async def exportation(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
return deepcopy(self._permissives)
def importation(self, permissives):
async def importation(self, permissives):
self._permissives = permissives

View File

@ -16,6 +16,7 @@
# ____________________________________________________________
from ...i18n import _
from ...error import ConflictError
from ...asyncinit import asyncinit
class Setting:
@ -33,13 +34,14 @@ def list_sessions():
return _list_sessions
@asyncinit
class Storage:
__slots__ = ('session_id', 'persistent')
storage = 'dictionary'
# if object could be serializable
serializable = True
def __init__(self, session_id, persistent, test=False):
async def __init__(self, session_id, persistent, test=False):
if not test and session_id in _list_sessions:
raise ConflictError(_('session "{}" already exists').format(session_id))
if persistent:

View File

@ -35,7 +35,7 @@ class Values:
self._informations = {}
self._storage = storage
def commit(self):
async def commit(self):
pass
def _setvalue_info(self, nb, idx, value, index, follower_idx=None):
@ -72,12 +72,12 @@ class Values:
self._values[nb].append([value])
# value
def setvalue(self,
path,
value,
owner,
index,
commit):
async def setvalue(self,
path,
value,
owner,
index,
commit):
"""set value for a path
a specified value must be associated to an owner
"""
@ -97,7 +97,7 @@ class Values:
self._add_new_value(index, 2, value)
self._add_new_value(index, 3, owner)
def hasvalue(self, path, index=None):
async def hasvalue(self, path, index=None):
"""if path has a value
return: boolean
"""
@ -111,7 +111,7 @@ class Values:
return index in indexes
return False
def reduce_index(self, path, index):
async def reduce_index(self, path, index):
"""
_values == ((path1, path2), ((idx1_1, idx1_2), None), ((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2))
"""
@ -122,10 +122,10 @@ class Values:
# reduce to one the index
self._values[1][path_idx][subidx] -= 1
def resetvalue_index(self,
path,
index,
commit):
async def resetvalue_index(self,
path,
index,
commit):
log.debug('resetvalue_index %s %s %s', path, index, id(self))
def _resetvalue(nb):
del self._values[nb][path_idx]
@ -147,9 +147,9 @@ class Values:
_resetvalue_index(2)
_resetvalue_index(3)
def resetvalue(self,
path,
commit):
async def resetvalue(self,
path,
commit):
"""remove value means delete value in storage
"""
log.debug('resetvalue %s %s', path, id(self))
@ -163,10 +163,10 @@ class Values:
_resetvalue(3)
# owner
def setowner(self,
path,
owner,
index=None):
async def setowner(self,
path,
owner,
index=None):
"""change owner for a path
"""
idx = self._values[0].index(path)
@ -176,19 +176,11 @@ class Values:
follower_idx = self._values[1][idx].index(index)
self._setvalue_info(3, idx, owner, index, follower_idx)
def get_max_length(self,
path):
if path in self._values[0]:
idx = self._values[0].index(path)
else:
return 0
return max(self._values[1][idx]) + 1
def getowner(self,
path,
default,
index=None,
with_value=False):
async def getowner(self,
path,
default,
index=None,
with_value=False):
"""get owner for a path
return: owner object
"""
@ -236,7 +228,7 @@ class Values:
value = list(value)
return owner, value
def set_information(self, path, key, value):
async def set_information(self, path, key, value):
"""updates the information's attribute
(which is a dictionary)
@ -246,7 +238,7 @@ class Values:
self._informations.setdefault(path, {})
self._informations[path][key] = value
def get_information(self, path, key, default):
async def get_information(self, path, key, default):
"""retrieves one information's item
:param key: the item string (ex: "help")
@ -257,28 +249,36 @@ class Values:
" not found: {0}").format(key))
return value
def del_information(self, path, key, raises):
async def del_information(self, path, key, raises):
if path in self._informations and key in self._informations[path]:
del self._informations[path][key]
else:
if raises:
raise ValueError(_("information's item not found {0}").format(key))
def list_information(self, path):
async def list_information(self, path):
if path in self._informations:
return self._informations[path].keys()
else:
return []
def del_informations(self):
async def del_informations(self):
self._informations = {}
def exportation(self):
async def exportation(self):
return deepcopy(self._values)
def importation(self, export):
async def importation(self, export):
self._values = deepcopy(export)
async def get_max_length(self,
path):
if path in self._values[0]:
idx = self._values[0].index(path)
else:
return 0
return max(self._values[1][idx]) + 1
def delete_session(session_id):
raise ValueError(_('cannot delete none persistent session'))

View File

@ -26,18 +26,15 @@ class Properties(Sqlite3DB):
super(Properties, self).__init__(storage)
# properties
def setproperties(self, path, index, properties):
self.exportation()
self.delproperties(path, index, commit=False)
self.exportation()
self._storage.execute("INSERT INTO property(path, tiram_index, properties, session_id) VALUES "
"(?, ?, ?, ?)", (path,
index,
self._sqlite_encode(properties),
self._session_id))
self.exportation()
async def setproperties(self, path, index, properties):
await self.delproperties(path, index, commit=False)
await self._storage.execute("INSERT INTO property(path, tiram_index, properties, session_id) VALUES "
"(?, ?, ?, ?)", (path,
index,
self._sqlite_encode(properties),
self._session_id))
def getproperties(self, path, index, default_properties):
async def getproperties(self, path, index, default_properties):
sql = 'SELECT properties FROM property WHERE session_id = ? '
params = [self._session_id]
if path is None:
@ -50,13 +47,13 @@ class Properties(Sqlite3DB):
else:
sql += "AND tiram_index = ? LIMIT 1"
params.append(index)
value = self._storage.select(sql, params)
value = await self._storage.select(sql, params)
if value is None:
return set(default_properties)
else:
return set(self._sqlite_decode(value[0]))
def delproperties(self, path, index, commit=True):
async def delproperties(self, path, index, commit=True):
sql = 'DELETE FROM property WHERE session_id = ? '
params = [self._session_id]
if path is None:
@ -69,25 +66,25 @@ class Properties(Sqlite3DB):
else:
params.append(index)
sql += 'AND tiram_index = ?'
self._storage.execute(sql, params, commit)
await self._storage.execute(sql, params, commit)
def exportation(self):
async def exportation(self):
"""return all modified settings in a dictionary
example: {'path1': set(['prop1', 'prop2'])}
"""
ret = {}
for path, tiram_index, properties, _ in self._storage.select("SELECT * FROM property "
for path, tiram_index, properties, _ in await self._storage.select("SELECT * FROM property "
"WHERE session_id = ?",
(self._session_id,),
only_one=False):
ret.setdefault(path, {})[tiram_index] = self._sqlite_decode(properties)
return ret
def importation(self, properties):
self._storage.execute("DELETE FROM property WHERE session_id = ?", (self._session_id,), commit=False)
async def importation(self, properties):
await self._storage.execute("DELETE FROM property WHERE session_id = ?", (self._session_id,), commit=False)
for path, indexed_properties in properties.items():
for index, property_ in indexed_properties.items():
self._storage.execute("INSERT INTO property(path, tiram_index, properties, session_id) "
await self._storage.execute("INSERT INTO property(path, tiram_index, properties, session_id) "
"VALUES (?, ?, ?, ?)", (path,
index,
self._sqlite_encode(property_),
@ -100,16 +97,16 @@ class Permissives(Sqlite3DB):
__slots__ = tuple()
# permissive
def setpermissives(self, path, index, permissive):
async def setpermissives(self, path, index, permissive):
log.debug('setpermissive %s %s %s %s', path, index, permissive, id(self))
self.delpermissive(path, index, commit=False)
self._storage.execute("INSERT INTO permissive(path, tiram_index, permissives, session_id) "
await self.delpermissive(path, index, commit=False)
await self._storage.execute("INSERT INTO permissive(path, tiram_index, permissives, session_id) "
"VALUES (?, ?, ?, ?)", (path,
index,
self._sqlite_encode(permissive),
self._session_id))
def getpermissives(self, path, index):
async def getpermissives(self, path, index):
sql = 'SELECT permissives FROM permissive WHERE session_id = ? '
params = [self._session_id]
if path is None:
@ -122,7 +119,7 @@ class Permissives(Sqlite3DB):
else:
sql += "AND tiram_index = ? LIMIT 1"
params.append(index)
permissives = self._storage.select(sql, params)
permissives = await self._storage.select(sql, params)
if permissives is None:
ret = frozenset()
else:
@ -130,7 +127,7 @@ class Permissives(Sqlite3DB):
log.debug('getpermissive %s %s %s', path, ret, id(self))
return ret
def delpermissive(self, path, index, commit=True):
async def delpermissive(self, path, index, commit=True):
sql = 'DELETE FROM permissive WHERE session_id = ? '
params = [self._session_id]
if path is None:
@ -143,29 +140,29 @@ class Permissives(Sqlite3DB):
else:
params.append(index)
sql += 'AND tiram_index = ?'
self._storage.execute(sql, params, commit)
await self._storage.execute(sql, params, commit)
def exportation(self):
async def exportation(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
ret = {}
for path, index, permissives in self._storage.select("SELECT path, tiram_index, permissives FROM permissive "
"WHERE session_id = ?",
(self._session_id,),
only_one=False):
sql = "SELECT path, tiram_index, permissives FROM permissive WHERE session_id = ?"
for path, index, permissives in await self._storage.select(sql,
(self._session_id,),
only_one=False):
ret.setdefault(path, {})[index] = self._sqlite_decode(permissives)
return ret
def importation(self, permissives):
self._storage.execute("DELETE FROM permissive WHERE session_id = ?", (self._session_id,),
commit=False)
async def importation(self, permissives):
await self._storage.execute("DELETE FROM permissive WHERE session_id = ?", (self._session_id,),
commit=False)
for path, indexed_permissives in permissives.items():
for index, permissive in indexed_permissives.items():
self._storage.execute("INSERT INTO permissive(path, tiram_index, permissives, session_id) "
"VALUES (?, ?, ?, ?)", (path,
index,
self._sqlite_encode(permissive),
self._session_id,
), False)
await self._storage.execute("INSERT INTO permissive(path, tiram_index, permissives, session_id) "
"VALUES (?, ?, ?, ?)", (path,
index,
self._sqlite_encode(permissive),
self._session_id,
), False)
self._storage._conn.commit()

View File

@ -17,10 +17,12 @@
# ____________________________________________________________
import sqlite3
import warnings
from os.path import join
from typing import Optional, Dict
from ...i18n import _
from os.path import join
from ...error import ConflictError
from ...asyncinit import asyncinit
global CONN
@ -86,11 +88,19 @@ def delete_session(session_id,
cursor.close()
@asyncinit
class Storage:
__slots__ = ('_conn', '_cursor', 'persistent', 'session_id', 'session_name', 'created')
__slots__ = ('_conn',
'_cursor',
'persistent',
'session_id',
'session_name',
'created')
storage = 'sqlite3'
def __init__(self, session_id, persistent, test=False):
async def __init__(self,
session_id: str,
persistent: bool):
self.created = False
self.persistent = persistent
global CONN
@ -119,44 +129,56 @@ class Storage:
informations_table += 'value TEXT, session_id INTEGER, path TEXT, '
informations_table += 'PRIMARY KEY (key, session_id), '
informations_table += 'FOREIGN KEY(session_id) REFERENCES session(session_id))'
self.execute(session_table, commit=False)
self.execute(values_table, commit=False)
self.execute(informations_table, commit=False)
self.execute(settings_table, commit=False)
self.execute(permissives_table, commit=False)
self._cursor.execute(session_table)
self._cursor.execute(values_table)
self._cursor.execute(informations_table)
self._cursor.execute(settings_table)
self._cursor.execute(permissives_table)
commit_needed = True
else:
commit_needed = False
self.session_id = None
if self.persistent:
select = self.select("SELECT session_id FROM session WHERE session = ?", (session_id,))
select = await self.select("SELECT session_id FROM session WHERE session = ?", (session_id,))
if select is not None:
self.session_id = select[0]
if self.session_id is None:
try:
self.execute('INSERT INTO session(session, persistent) VALUES (?, ?)',
(session_id, persistent))
self._cursor.execute('INSERT INTO session(session, persistent) VALUES (?, ?)',
(session_id, persistent))
except sqlite3.IntegrityError: # pragma: no cover
raise ConflictError(_('session "{}" already exists').format(session_id))
commit_needed = True
self.session_id = self._cursor.lastrowid
if commit_needed:
self._conn.commit()
self.created = True
def commit(self):
async def commit(self) -> None:
self._conn.commit()
def execute(self, sql, params=None, commit=True):
async def execute(self,
sql: str,
params: Optional[Dict]=None,
commit: bool=True) -> None:
#print(sql, params, commit)
if params is None:
params = tuple()
self._cursor.execute(sql, params)
if commit:
self.commit()
await self.commit()
def select(self, sql, params=None, only_one=True):
self.execute(sql, params=params, commit=False)
async def select(self,
sql: str,
params: Optional[Dict]=None,
only_one: bool=True) -> 'Row':
await self.execute(sql, params=params, commit=False)
if only_one:
return self._cursor.fetchone()
else:
return self._cursor.fetchall()
def __del__(self):
def __del__(self) -> None:
self._cursor.close()
if self.created and not self.persistent:
if delete_session is not None:

View File

@ -32,110 +32,110 @@ class Values(Sqlite3DB):
super(Values, self).__init__(storage)
# sqlite
def _sqlite_select(self, path, index):
async def _sqlite_select(self, path, index):
request = "SELECT value FROM value WHERE path = ? AND session_id = ? "
params = (path, self._session_id)
if index is not None:
request += "and idx = ? "
params = (path, self._session_id, index)
request += "LIMIT 1"
return self._storage.select(request, params)
return await self._storage.select(request, params)
def commit(self):
self._storage.commit()
async def commit(self):
await self._storage.commit()
# value
def setvalue(self,
path,
value,
owner,
index,
commit):
async def setvalue(self,
path,
value,
owner,
index,
commit):
"""set value for an option
a specified value must be associated to an owner
"""
log.debug('setvalue %s %s %s %s %s', path, value, owner, index, commit)
path = self._sqlite_encode_path(path)
if index is not None:
self.resetvalue_index(path,
index,
commit=False)
self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id) VALUES "
"(?, ?, ?, ?, ?)", (path, self._sqlite_encode(value),
str(owner),
index,
self._session_id),
await self.resetvalue_index(path,
index,
commit=False)
await self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id) VALUES "
"(?, ?, ?, ?, ?)", (path, self._sqlite_encode(value),
str(owner),
index,
self._session_id),
commit=commit)
else:
self.resetvalue(path,
commit=False)
self._storage.execute("INSERT INTO value(path, value, owner, session_id) VALUES "
"(?, ?, ?, ?)", (path, self._sqlite_encode(value),
str(owner),
self._session_id),
commit=commit)
await self.resetvalue(path,
commit=False)
await self._storage.execute("INSERT INTO value(path, value, owner, session_id) VALUES "
"(?, ?, ?, ?)", (path, self._sqlite_encode(value),
str(owner),
self._session_id),
commit=commit)
def hasvalue(self,
path,
index=None):
async def hasvalue(self,
path,
index=None):
"""if opt has a value
return: boolean
"""
log.debug('hasvalue %s %s', path, index)
path = self._sqlite_encode_path(path)
return self._sqlite_select(path, index) is not None
return await self._sqlite_select(path, index) is not None
def reduce_index(self, path, index):
async def reduce_index(self, path, index):
"""
_values == ((path1, path2), ((idx1_1, idx1_2), None),
((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2))
"""
log.debug('reduce_index %s %s %s', path, index, id(self))
self._storage.execute("UPDATE value SET idx = ? WHERE path = ? and idx = ? "
"AND session_id = ?",
(index - 1, path, index, self._session_id))
await self._storage.execute("UPDATE value SET idx = ? WHERE path = ? and idx = ? "
"AND session_id = ?",
(index - 1, path, index, self._session_id))
def resetvalue_index(self,
path,
index,
commit=True):
async def resetvalue_index(self,
path,
index,
commit=True):
"""remove value means delete value in storage
"""
log.debug('resetvalue_index %s %s %s', path, index, commit)
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ? AND idx = ?",
(path, self._session_id, index),
commit=commit)
await self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ? AND idx = ?",
(path, self._session_id, index),
commit=commit)
def resetvalue(self,
path,
commit):
async def resetvalue(self,
path,
commit):
"""remove value means delete value in storage
"""
log.debug('resetvalue %s %s', path, commit)
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ?",
(path, self._session_id),
commit=commit)
await self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ?",
(path, self._session_id),
commit=commit)
# owner
def setowner(self,
path,
owner,
index=None):
async def setowner(self,
path,
owner,
index=None):
"""change owner for an option
"""
log.debug('setowner %s %s %s', path, owner, index)
path = self._sqlite_encode_path(path)
if index is None:
self._storage.execute("UPDATE value SET owner = ? WHERE path = ? AND session_id = ?",
(str(owner), path, self._session_id))
await self._storage.execute("UPDATE value SET owner = ? WHERE path = ? AND session_id = ?",
(str(owner), path, self._session_id))
else:
self._storage.execute("UPDATE value SET owner = ? WHERE path = ? and idx = ? AND session_id = ?",
(str(owner), path, index, self._session_id))
await self._storage.execute("UPDATE value SET owner = ? WHERE path = ? and idx = ? AND session_id = ?",
(str(owner), path, index, self._session_id))
def getowner(self,
async def getowner(self,
path,
default,
index=None,
@ -152,7 +152,7 @@ class Values(Sqlite3DB):
else:
params = (path, self._session_id)
request += ' LIMIT 1'
owner = self._storage.select(request, params)
owner = await self._storage.select(request, params)
if owner is None:
if not with_value:
return default
@ -171,7 +171,7 @@ class Values(Sqlite3DB):
value = self._sqlite_decode(owner[1])
return nowner, value
def set_information(self, path, key, value):
async def set_information(self, path, key, value):
"""updates the information's attribute
(which is a dictionary)
@ -180,20 +180,20 @@ class Values(Sqlite3DB):
"""
log.debug('set_information %s %s', key, value)
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ? AND path = ?",
(key, self._session_id, path),
False)
self._storage.execute("INSERT INTO information(key, value, session_id, path) VALUES "
"(?, ?, ?, ?)", (key, self._sqlite_encode(value), self._session_id, path))
await self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ? AND path = ?",
(key, self._session_id, path),
False)
await self._storage.execute("INSERT INTO information(key, value, session_id, path) VALUES "
"(?, ?, ?, ?)", (key, self._sqlite_encode(value), self._session_id, path))
def get_information(self, path, key, default):
async def get_information(self, path, key, default):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
log.debug('get_information %s %s', key, default)
path = self._sqlite_encode_path(path)
value = self._storage.select("SELECT value FROM information WHERE key = ? AND "
value = await self._storage.select("SELECT value FROM information WHERE key = ? AND "
"session_id = ? AND path = ?",
(key, self._session_id, path))
if value is None:
@ -204,32 +204,35 @@ class Values(Sqlite3DB):
else:
return self._sqlite_decode(value[0])
def del_information(self, path, key, raises):
async def del_information(self, path, key, raises):
log.debug('del_information %s %s', key, raises)
path = self._sqlite_encode_path(path)
if raises and self._storage.select("SELECT value FROM information WHERE key = ? "
"AND session_id = ? AND path = ?",
(key, self._session_id, path)) is None:
information = await self._storage.select("SELECT value FROM information WHERE key = ? "
"AND session_id = ? AND path = ?",
(key, self._session_id, path))
if raises and information is None:
raise ValueError(_("information's item not found {0}").format(key))
self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ? AND path = ?",
(key, self._session_id, path))
await self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ? AND path = ?",
(key, self._session_id, path))
def list_information(self, path):
async def list_information(self, path):
path = self._sqlite_encode_path(path)
rows = self._storage.select("SELECT key FROM information WHERE session_id = ? AND path = ?",
(self._session_id, path),
only_one=False)
rows = await self._storage.select("SELECT key FROM information WHERE session_id = ? AND path = ?",
(self._session_id, path),
only_one=False)
ret = []
for row in rows:
yield self._sqlite_decode_path(row[0])
ret.append(self._sqlite_decode_path(row[0]))
return ret
def del_informations(self):
self._storage.execute("DELETE FROM information WHERE session_id = ?",
(self._session_id,))
async def del_informations(self):
await self._storage.execute("DELETE FROM information WHERE session_id = ?",
(self._session_id,))
def exportation(self):
async def exportation(self):
log.debug('exportation')
rows = self._storage.select("SELECT path, value, owner, idx FROM value WHERE "
"session_id = ?;", (self._session_id,), only_one=False)
rows = await self._storage.select("SELECT path, value, owner, idx FROM value WHERE "
"session_id = ?;", (self._session_id,), only_one=False)
ret = [[], [], [], []]
for row in rows:
path = self._sqlite_decode_path(row[0])
@ -255,36 +258,36 @@ class Values(Sqlite3DB):
return ret
def importation(self, export):
async def importation(self, export):
log.debug('importation')
request = "DELETE FROM value WHERE session_id = ?"
self._storage.execute(request, (self._session_id,),
commit=False)
await self._storage.execute(request, (self._session_id,),
commit=False)
for idx, path in enumerate(export[0]):
path = self._sqlite_encode_path(path)
index = export[1][idx]
value = export[2][idx]
owner = export[3][idx]
if index is None:
self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id) VALUES "
"(?, ?, ?, ?, ?)", (path, self._sqlite_encode(value),
str(owner), index,
self._session_id), commit=False)
await self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id) VALUES "
"(?, ?, ?, ?, ?)", (path, self._sqlite_encode(value),
str(owner), index,
self._session_id), commit=False)
else:
for val in zip(index, value, owner):
self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id)"
"VALUES (?, ?, ?, ?, ?)", (path,
self._sqlite_encode(val[1]),
str(val[2]), val[0],
self._session_id),
commit=False)
await self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id)"
"VALUES (?, ?, ?, ?, ?)", (path,
self._sqlite_encode(val[1]),
str(val[2]), val[0],
self._session_id),
commit=False)
self._storage._conn.commit()
def get_max_length(self,
path):
async def get_max_length(self,
path):
log.debug('get_max_length %s', path)
val_max = self._storage.select("SELECT max(idx) FROM value WHERE path = ? AND session_id = ?",
(path, self._session_id), False)
val_max = await self._storage.select("SELECT max(idx) FROM value WHERE path = ? AND session_id = ?",
(path, self._session_id), False)
if val_max[0][0] is None:
return 0
return val_max[0][0] + 1

View File

@ -6,7 +6,7 @@ from copy import copy
from itertools import chain
from .error import ValueWarning, ValueErrorWarning, PropertiesOptionError, ConfigError
from .setting import undefined
from . import SynDynOption, RegexpOption, ChoiceOption, ParamContext, ParamOption
from . import SynDynOption, RegexpOption, ChoiceOption, ParamOption
from .i18n import _
@ -43,38 +43,36 @@ class Callbacks(object):
self.remotable = tiramisu_web.remotable
self.callbacks = []
def add(self,
path,
childapi,
schema,
force_store_value):
if self.remotable == 'all' or childapi.option.isoptiondescription():
async def add(self,
path,
childapi,
schema,
force_store_value):
if self.remotable == 'all' or await childapi.option.isoptiondescription():
return
callback, callback_params = childapi.option.callbacks()
callback, callback_params = await childapi.option.callbacks()
if callback is None: # FIXME ? and force_store_value and self.clearable != 'all':
return
self.callbacks.append((callback, callback_params, path, childapi, schema, force_store_value))
def process_properties(self, form):
async def process_properties(self, form):
for callback, callback_params, path, childapi, schema, force_store_value in self.callbacks:
if childapi.option.isfollower():
self.tiramisu_web.set_remotable(path, form, childapi)
if await childapi.option.isfollower():
await self.tiramisu_web.set_remotable(path, form, childapi)
continue
has_option = False
if callback_params is not None:
for callback_param in chain(callback_params.args, callback_params.kwargs.values()):
if isinstance(callback_param, ParamContext):
raise ValueError(_('context is not supported from now for {}').format(path))
if isinstance(callback_param, ParamOption):
has_option = True
if 'expire' in childapi.option.properties():
self.tiramisu_web.set_remotable(callback_param.option.impl_getpath(), form)
if 'expire' in await childapi.option.properties():
await self.tiramisu_web.set_remotable(callback_param.option.impl_getpath(), form)
if not has_option and form.get(path, {}).get('remote', False) == False:
if 'expire' in childapi.option.properties():
self.tiramisu_web.set_remotable(path, form, childapi)
elif childapi.owner.isdefault():
if 'expire' in await childapi.option.properties():
await self.tiramisu_web.set_remotable(path, form, childapi)
elif await childapi.owner.isdefault():
# get calculated value and set clearable
schema[path]['value'] = childapi.value.get()
schema[path]['value'] = await childapi.value.get()
if self.clearable == 'minimum':
form.setdefault(path, {})['clearable'] = True
@ -89,9 +87,9 @@ class Callbacks(object):
# form.setdefault(opt_path, {})
# form[opt_path].setdefault('copy', []).append(path)
def process(self,
form):
self.process_properties(form)
async def process(self,
form):
await self.process_properties(form)
self.manage_callbacks(form)
@ -100,10 +98,10 @@ class Consistencies(object):
self.not_equal = {}
self.tiramisu_web = tiramisu_web
def add(self, path, childapi, form):
async def add(self, path, childapi, form):
return
if not childapi.option.isoptiondescription():
for consistency in childapi.option.consistencies():
if not await childapi.option.isoptiondescription():
for consistency in await childapi.option.consistencies():
cons_id, func, all_cons_opts, params = consistency
if func == '_cons_not_equal' and params.get('transitive', True) is True:
options_path = []
@ -117,9 +115,9 @@ class Consistencies(object):
self.not_equal.setdefault(option._path, {}).setdefault(warnings_only, []).extend(paths)
else:
for option in all_cons_opts:
self.tiramisu_web.set_remotable(option()._path, form)
await self.tiramisu_web.set_remotable(option()._path, form)
def process(self, form):
async def process(self, form):
for path in self.not_equal:
if self.tiramisu_web.is_remote(path, form):
continue
@ -142,23 +140,23 @@ class Requires(object):
self.tiramisu_web = tiramisu_web
self.action_hide = self.tiramisu_web.config._config_bag.properties
def set_master_remote(self, childapi, path, form):
if childapi.option.isoptiondescription():
async def set_master_remote(self, childapi, path, form):
if await childapi.option.isoptiondescription():
isfollower = False
else:
isfollower = childapi.option.isfollower()
isfollower = await childapi.option.isfollower()
if isfollower:
parent_path = path.rsplit('.', 1)[0]
parent = self.tiramisu_web.config.unrestraint.option(parent_path)
leader = next(parent.list())
self.tiramisu_web.set_remotable(leader.option.path(), form, leader)
parent = await self.tiramisu_web.config.unrestraint.option(parent_path)
leader = await parent.list()[0]
await self.tiramisu_web.set_remotable(await leader.option.path(), form, leader)
def manage_requires(self,
childapi,
path,
form,
current_action):
for requires in childapi.option.properties(uncalculated=True):
async def manage_requires(self,
childapi,
path,
form,
current_action):
for requires in await childapi.option.properties(uncalculated=True):
if not isinstance(requires, str):
option = requires.params.kwargs['condition'].option
expected = [requires.params.kwargs['expected'].value]
@ -180,8 +178,8 @@ class Requires(object):
if isinstance(option, tuple):
for option_param in chain(option[1].args, option[1].kwargs.values()):
if isinstance(option_param, ParamOption):
self.tiramisu_web.set_remotable(option_param.option.impl_getpath(), form)
self.set_master_remote(childapi, path, form)
await self.tiramisu_web.set_remotable(option_param.option.impl_getpath(), form)
await self.set_master_remote(childapi, path, form)
# elif len_to_long:
# self.tiramisu_web.set_remotable(option.impl_getpath(), form)
# self.set_master_remote(childapi, path, form)
@ -193,8 +191,8 @@ class Requires(object):
# transitive to "False" not supported yet for a requirement
# same_action to "False" not supported yet for a requirement
# operator "and" not supported yet for a requirement
self.tiramisu_web.set_remotable(option_path, form, require_option)
self.set_master_remote(childapi, path, form)
await self.tiramisu_web.set_remotable(option_path, form, require_option)
await self.set_master_remote(childapi, path, form)
# if require_option.option.requires():
# for reqs in require_option.option.requires():
# for req in reqs:
@ -210,10 +208,10 @@ class Requires(object):
inv_act = 'show'
if isinstance(option, ChoiceOption):
require_option = self.tiramisu_web.config.unrestraint.option(option_path)
values = self.tiramisu_web.get_enum(require_option,
require_option.option.ismulti(),
option_path,
require_option.option.properties())
values = await self.tiramisu_web.get_enum(require_option,
await require_option.option.ismulti(),
option_path,
await require_option.option.properties())
for value in values:
if value not in expected:
self.requires.setdefault(path,
@ -224,8 +222,8 @@ class Requires(object):
if current_action is None:
current_action = action
elif current_action != action:
self.tiramisu_web.set_remotable(option_path, form)
self.set_master_remote(childapi, path, form)
await self.tiramisu_web.set_remotable(option_path, form)
await self.set_master_remote(childapi, path, form)
for exp in expected:
self.requires.setdefault(path,
{'expected': {}}
@ -234,29 +232,29 @@ class Requires(object):
[]).append(option_path)
self.requires[path].setdefault('default', {}).setdefault(inv_act, []).append(option_path)
else:
self.tiramisu_web.set_remotable(option_path, form)
self.set_master_remote(childapi, path, form)
await self.tiramisu_web.set_remotable(option_path, form)
await self.set_master_remote(childapi, path, form)
def add(self, path, childapi, form):
async def add(self, path, childapi, form):
#collect id of all options
child = childapi.option.get()
child = await childapi.option.get()
if isinstance(child, SynDynOption):
child = child._impl_getopt()
self.options[child] = path
current_action = None
self.manage_requires(childapi,
path,
form,
current_action)
await self.manage_requires(childapi,
path,
form,
current_action)
def process(self, form):
async def process(self, form):
dependencies = {}
for path, values in self.requires.items():
if 'default' in values:
for option in values['default'].get('show', []):
if path == option:
self.tiramisu_web.set_remotable(path, form)
await self.tiramisu_web.set_remotable(path, form)
if not self.tiramisu_web.is_remote(option, form):
dependencies.setdefault(option,
{'default': {}, 'expected': {}}
@ -265,7 +263,7 @@ class Requires(object):
dependencies[option]['default']['show'].append(path)
for option in values['default'].get('hide', []):
if path == option:
self.tiramisu_web.set_remotable(path, form)
await self.tiramisu_web.set_remotable(path, form)
if not self.tiramisu_web.is_remote(option, form):
dependencies.setdefault(option,
{'default': {}, 'expected': {}}
@ -277,7 +275,7 @@ class Requires(object):
expected = ''
for option in actions.get('show', []):
if path == option:
self.tiramisu_web.set_remotable(path, form)
await self.tiramisu_web.set_remotable(path, form)
if not self.tiramisu_web.is_remote(option, form):
dependencies.setdefault(option,
{'expected': {}}
@ -287,7 +285,7 @@ class Requires(object):
dependencies[option]['expected'][expected]['show'].append(path)
for option in actions.get('hide', []):
if path == option:
self.tiramisu_web.set_remotable(path, form)
await self.tiramisu_web.set_remotable(path, form)
if not self.tiramisu_web.is_remote(option, form):
dependencies.setdefault(option,
{'expected': {}}
@ -329,24 +327,24 @@ class TiramisuDict:
self.clearable = clearable
#all, minimum, none
self.remotable = remotable
self.context_properties = self.config.property.get()
self.context_permissives = self.config.permissive.get()
def add_help(self,
obj,
childapi):
hlp = childapi.information.get('help', None)
async def add_help(self,
obj,
childapi):
hlp = await childapi.information.get('help', None)
if hlp is not None:
obj['help'] = hlp
def get_list(self, root, subchildapi):
for childapi in subchildapi.list('all'):
childname = childapi.option.name()
async def get_list(self, root, subchildapi):
ret = []
for childapi in await subchildapi.list('all'):
childname = await childapi.option.name()
if root is None:
path = childname
else:
path = root + '.' + childname
yield path, childapi
ret.append((path, childapi))
return ret
def is_remote(self, path, form):
if self.remotable == 'all':
@ -354,27 +352,27 @@ class TiramisuDict:
else:
return path in form and form[path].get('remote', False) == True
def set_remotable(self, path, form, childapi=None):
async def set_remotable(self, path, form, childapi=None):
if self.remotable == 'none':
raise ValueError(_('option {} only works when remotable is not "none"').format(path))
form.setdefault(path, {})['remote'] = True
if childapi is None:
childapi = self.config.unrestraint.option(path)
if childapi.option.isfollower():
if await childapi.option.isfollower():
parent_path = path.rsplit('.', 1)[0]
parent = self.config.unrestraint.option(parent_path)
leader = next(parent.list())
form.setdefault(leader.option.path(), {})['remote'] = True
parent = await self.config.unrestraint.option(parent_path)
leader = await parent.list()[0]
form.setdefault(await leader.option.path(), {})['remote'] = True
def walk(self,
root,
subchildapi,
schema,
model,
form,
order,
updates_status,
init=False):
async def walk(self,
root,
subchildapi,
schema,
model,
form,
order,
updates_status,
init=False):
error = None
if init:
if form is not None:
@ -391,36 +389,36 @@ class TiramisuDict:
subchildapi = self.config.unrestraint.option(root)
isleadership = False
else:
isleadership = subchildapi.option.isleadership()
isleadership = await subchildapi.option.isleadership()
leader_len = None
for path, childapi in self.get_list(root, subchildapi):
for path, childapi in await self.get_list(root, subchildapi):
if isleadership and leader_len is None:
leader_len = childapi.value.len()
leader_len = await childapi.value.len()
one_is_remote = False
props_no_requires = set(childapi.option.properties())
props_no_requires = set(await childapi.option.properties())
if form is not None:
self.requires.add(path,
childapi,
form)
self.consistencies.add(path,
childapi,
form)
self.callbacks.add(path,
childapi,
schema,
'force_store_value' in props_no_requires)
await self.requires.add(path,
childapi,
form)
await self.consistencies.add(path,
childapi,
form)
await self.callbacks.add(path,
childapi,
schema,
'force_store_value' in props_no_requires)
childapi_option = childapi.option
if model is not None and childapi.option.isoptiondescription() or not childapi_option.issymlinkoption():
self.gen_model(model,
childapi,
path,
leader_len,
updates_status)
if model is not None and await childapi.option.isoptiondescription() or not await childapi_option.issymlinkoption():
await self.gen_model(model,
childapi,
path,
leader_len,
updates_status)
if order is not None:
order.append(path)
if childapi.option.isoptiondescription():
if await childapi.option.isoptiondescription():
web_type = 'optiondescription'
if childapi_option.isleadership():
if await childapi_option.isleadership():
type_ = 'array'
else:
type_ = 'object'
@ -430,60 +428,60 @@ class TiramisuDict:
subschema = schema[path]['properties']
else:
subschema = schema
self.walk(path,
childapi,
subschema,
model,
form,
order,
updates_status)
await self.walk(path,
childapi,
subschema,
model,
form,
order,
updates_status)
else:
child = childapi_option.get()
child = await childapi_option.get()
childtype = child.__class__.__name__
if childtype == 'SynDynOption':
childtype = child._impl_getopt().__class__.__name__
if childapi_option.issymlinkoption():
if await childapi_option.issymlinkoption():
web_type = 'symlink'
value = None
defaultmulti = None
is_multi = False
else:
web_type = childapi_option.type()
value = childapi.option.default()
web_type = await childapi_option.type()
value = await childapi.option.default()
if value == []:
value = None
is_multi = childapi_option.ismulti()
is_multi = await childapi_option.ismulti()
if is_multi:
defaultmulti = childapi_option.defaultmulti()
defaultmulti = await childapi_option.defaultmulti()
if defaultmulti == []:
defaultmulti = None
else:
defaultmulti = None
if schema is not None:
self.gen_schema(schema,
childapi,
childapi_option,
path,
props_no_requires,
value,
defaultmulti,
is_multi,
web_type,
form)
await self.gen_schema(schema,
childapi,
childapi_option,
path,
props_no_requires,
value,
defaultmulti,
is_multi,
web_type,
form)
if form is not None:
self.gen_form(form,
web_type,
path,
child,
childapi_option,
childtype)
await self.gen_form(form,
web_type,
path,
child,
childapi_option,
childtype)
if schema is not None:
if web_type != 'symlink':
schema[path]['title'] = childapi_option.description()
self.add_help(schema[path],
childapi)
schema[path]['title'] = await childapi_option.description()
await self.add_help(schema[path],
childapi)
except Exception as err:
import traceback
traceback.print_exc()
@ -491,9 +489,9 @@ class TiramisuDict:
raise err
error = err
if init and form is not None:
self.callbacks.process(form)
self.requires.process(form)
self.consistencies.process(form)
await self.callbacks.process(form)
await self.requires.process(form)
await self.consistencies.process(form)
del self.requires
del self.consistencies
del self.callbacks
@ -503,20 +501,21 @@ class TiramisuDict:
raise ConfigError(_('unable to transform tiramisu object to dict: {}').format(msg))
def gen_schema(self,
schema,
childapi,
childapi_option,
path,
props_no_requires,
value,
defaultmulti,
is_multi,
web_type,
form):
async def gen_schema(self,
schema,
childapi,
childapi_option,
path,
props_no_requires,
value,
defaultmulti,
is_multi,
web_type,
form):
schema[path] = {'type': web_type}
if childapi_option.issymlinkoption():
schema[path]['opt_path'] = childapi_option.get().impl_getopt().impl_getpath()
if await childapi_option.issymlinkoption():
sym_option = await childapi_option.get()
schema[path]['opt_path'] = sym_option.impl_getopt().impl_getpath()
else:
if defaultmulti is not None:
schema[path]['defaultmulti'] = defaultmulti
@ -524,7 +523,7 @@ class TiramisuDict:
if is_multi:
schema[path]['isMulti'] = is_multi
if childapi_option.issubmulti():
if await childapi_option.issubmulti():
schema[path]['isSubMulti'] = True
if 'auto_freeze' in props_no_requires:
@ -537,58 +536,56 @@ class TiramisuDict:
# if isinstance(values_param, ParamOption):
# self.set_remotable(path, form, childapi)
# return
schema[path]['enum'] = self.get_enum(childapi,
is_multi,
path,
props_no_requires)
schema[path]['enum'] = await self.get_enum(childapi,
is_multi,
path,
props_no_requires)
if value is not None and not self.is_remote(path, form):
schema[path]['value'] = value
def get_enum(self,
childapi,
is_multi,
path,
props_no_requires):
values = childapi.value.list()
empty_is_required = not childapi.option.isfollower() and is_multi
async def get_enum(self,
childapi,
is_multi,
path,
props_no_requires):
values = await childapi.value.list()
empty_is_required = not await childapi.option.isfollower() and is_multi
if '' not in values and ((empty_is_required and not 'empty' in props_no_requires) or \
(not empty_is_required and not 'mandatory' in props_no_requires)):
values = [''] + list(values)
return values
def gen_form(self,
form,
web_type,
path,
child,
childapi_option,
childtype):
async def gen_form(self,
form,
web_type,
path,
child,
childapi_option,
childtype):
obj_form = {}
if path in form:
obj_form.update(form[path])
if not childapi_option.issymlinkoption():
if not await childapi_option.issymlinkoption():
#if childapi_option.validator() != (None, None):
# obj_form['remote'] = True
# params = childapi_option.validator()[1]
# if params is not None:
# for param in chain(params.args, params.kwargs.values()):
# if isinstance(param, ParamContext):
# raise ValueError(_('context is not supported from now for {}').format(path))
# if isinstance(param, ParamOption):
# self.set_remotable(param.option.impl_getpath(), form)
if self.clearable == 'all':
obj_form['clearable'] = True
if self.clearable != 'none':
obj_form['clearable'] = True
if self.remotable == 'all' or childapi_option.has_dependency():
if self.remotable == 'all' or await childapi_option.has_dependency():
obj_form['remote'] = True
if childtype == 'IPOption' and (child.impl_get_extra('_private_only') or not child.impl_get_extra('_allow_reserved') or child.impl_get_extra('_cidr')):
obj_form['remote'] = True
if childtype == 'DateOption':
obj_form['remote'] = True
if not obj_form.get('remote', False):
pattern = childapi_option.pattern()
pattern = await childapi_option.pattern()
if pattern is not None:
obj_form['pattern'] = pattern
if childtype == 'PortOption':
@ -603,42 +600,36 @@ class TiramisuDict:
if obj_form:
form[path] = obj_form
def calc_raises_properties(self,
obj,
childapi):
async def calc_raises_properties(self,
obj,
childapi):
old_properties = childapi._option_bag.config_bag.properties
del childapi._option_bag.config_bag.properties
has_permissive = 'permissive' in childapi._option_bag.config_bag.properties
if not has_permissive:
childapi._option_bag.config_bag.properties = childapi._option_bag.config_bag.properties | {'permissive'}
# 'display=False' means cannot access only without permissive option
config = childapi._option_bag.config_bag.context
settings = config.cfgimpl_get_settings()
childapi._option_bag.config_bag.properties = await settings.get_context_properties(config._impl_properties_cache)
childapi._option_bag.config_bag.properties -= {'permissive'}
properties = await childapi.property.get(only_raises=True)
properties -= await childapi.permissive.get()
# 'hidden=True' means cannot access with or without permissive option
properties = childapi.property.get(only_raises=True)
if has_permissive:
properties -= self.config.permissive.get()
properties -= childapi.permissive.get()
if properties:
obj['hidden'] = True
childapi._option_bag.config_bag.properties = childapi._option_bag.config_bag.properties - {'permissive'}
properties = childapi.property.get(only_raises=True)
if has_permissive:
properties -= self.config.permissive.get()
properties -= childapi.permissive.get()
# 'display=False' means cannot access only without permissive option
if properties:
obj['display'] = False
properties -= await self.config.permissive.get()
if properties:
obj['hidden'] = True
childapi._option_bag.config_bag.properties = old_properties
def _gen_model_properties(self,
childapi,
path,
index):
isfollower = childapi.option.isfollower()
props = set(childapi.property.get())
async def _gen_model_properties(self,
childapi,
path,
index):
isfollower = await childapi.option.isfollower()
props = set(await childapi.property.get())
obj = self.gen_properties(props,
isfollower,
childapi.option.ismulti(),
await childapi.option.ismulti(),
index)
self.calc_raises_properties(obj, childapi)
await self.calc_raises_properties(obj, childapi)
return obj
def gen_properties(self,
@ -674,61 +665,61 @@ class TiramisuDict:
obj['properties'] = lprops
return obj
def gen_model(self,
model,
childapi,
path,
leader_len,
updates_status):
if childapi.option.isoptiondescription():
props = set(childapi.property.get())
async def gen_model(self,
model,
childapi,
path,
leader_len,
updates_status):
if await childapi.option.isoptiondescription():
props = set(await childapi.property.get())
obj = {}
self.calc_raises_properties(obj, childapi)
await self.calc_raises_properties(obj, childapi)
if props:
lprops = list(props)
lprops.sort()
obj['properties'] = lprops
try:
self.config.option(path).option.get()
await self.config.option(path).option.get()
except PropertiesOptionError:
pass
else:
obj = self._gen_model_properties(childapi,
path,
None)
if childapi.option.isfollower():
obj = await self._gen_model_properties(childapi,
path,
None)
if await childapi.option.isfollower():
for index in range(leader_len):
follower_childapi = self.config.unrestraint.option(path, index)
sobj = self._gen_model_properties(follower_childapi,
path,
index)
self._get_model_value(follower_childapi,
path,
sobj,
index,
updates_status)
sobj = await self._gen_model_properties(follower_childapi,
path,
index)
await self._get_model_value(follower_childapi,
path,
sobj,
index,
updates_status)
if sobj:
model.setdefault(path, {})[str(index)] = sobj
else:
self._get_model_value(childapi,
path,
obj,
None,
updates_status)
await self._get_model_value(childapi,
path,
obj,
None,
updates_status)
if obj:
if not childapi.option.isoptiondescription() and childapi.option.isfollower():
if not await childapi.option.isoptiondescription() and await childapi.option.isfollower():
model.setdefault(path, {})['null'] = obj
else:
model[path] = obj
def _get_model_value(self,
childapi,
path,
obj,
index,
updates_status):
async def _get_model_value(self,
childapi,
path,
obj,
index,
updates_status):
if path in updates_status and index in updates_status[path]:
value = childapi.value.get()
value = await childapi.value.get()
self._get_value_with_exception(obj,
childapi,
updates_status[path][index])
@ -736,7 +727,7 @@ class TiramisuDict:
else:
try:
with warnings.catch_warnings(record=True) as warns:
value = self.config.option(path, index=index).value.get()
value = await self.config.option(path, index=index).value.get()
self._get_value_with_exception(obj,
childapi,
warns)
@ -744,7 +735,7 @@ class TiramisuDict:
self._get_value_with_exception(obj,
childapi,
[err])
value = self.config.unrestraint.option(path, index=index).value.get()
value = await self.config.unrestraint.option(path, index=index).value.get()
except PropertiesOptionError as err:
config_bag = self.config._config_bag
settings = config_bag.context.cfgimpl_get_settings()
@ -753,11 +744,11 @@ class TiramisuDict:
set(err.proptype)):
obj['hidden'] = True
obj['display'] = False
value = childapi.value.get()
value = await childapi.value.get()
if value is not None and value != []:
obj['value'] = value
if not childapi.owner.isdefault():
obj['owner'] = childapi.owner.get()
if not await childapi.owner.isdefault():
obj['owner'] = await childapi.owner.get()
def _get_value_with_exception(self,
obj,
@ -785,12 +776,12 @@ class TiramisuDict:
obj['warnings'].append(msg)
obj['hasWarnings'] = True
def gen_global(self):
async def gen_global(self):
ret = {}
ret['owner'] = self.config.owner.get()
ret['properties'] = list(self.config.property.get())
ret['owner'] = await self.config.owner.get()
ret['properties'] = list(await self.config.property.get())
ret['properties'].sort()
ret['permissives'] = list(self.config.permissive.get())
ret['permissives'] = list(await self.config.permissive.get())
ret['permissives'].sort()
return ret
@ -816,36 +807,36 @@ class TiramisuDict:
ret.extend(buttons)
return ret
def del_value(self, childapi, path, index):
if index is not None and childapi.option.isleader():
childapi.value.pop(index)
elif index is None or childapi.option.isfollower():
childapi.value.reset()
async def del_value(self, childapi, path, index):
if index is not None and await childapi.option.isleader():
await childapi.value.pop(index)
elif index is None or await childapi.option.isfollower():
await childapi.value.reset()
else:
multi = childapi.value.get()
multi = await childapi.value.get()
multi.pop(index)
childapi.value.set(multi)
await childapi.value.set(multi)
def add_value(self, childapi, path, value):
multi = childapi.value.get()
async def add_value(self, childapi, path, value):
multi = await childapi.value.get()
multi.append(value)
childapi.value.set(multi)
await childapi.value.set(multi)
def mod_value(self, childapi, path, index, value):
if index is None or childapi.option.isfollower():
childapi.value.set(value)
async def mod_value(self, childapi, path, index, value):
if index is None or await childapi.option.isfollower():
await childapi.value.set(value)
else:
multi = childapi.value.get()
multi = await childapi.value.get()
if len(multi) < index + 1:
multi.append(value)
else:
multi[index] = value
childapi.value.set(multi)
await childapi.value.set(multi)
def apply_updates(self,
oripath,
updates,
model_ori):
async def apply_updates(self,
oripath,
updates,
model_ori):
updates_status = {}
for update in updates:
path = update['name']
@ -854,22 +845,22 @@ class TiramisuDict:
raise ValueError(_('not in current area'))
childapi = self.config.option(path)
childapi_option = childapi.option
if childapi_option.isfollower():
if await childapi_option.isfollower():
childapi = self.config.option(path, index)
with warnings.catch_warnings(record=True) as warns:
try:
if update['action'] == 'modify':
self.mod_value(childapi,
path,
index,
update.get('value', undefined))
await self.mod_value(childapi,
path,
index,
update.get('value', undefined))
elif update['action'] == 'delete':
self.del_value(childapi,
path,
index)
await self.del_value(childapi,
path,
index)
elif update['action'] == 'add':
if childapi_option.ismulti():
self.add_value(childapi, path, update['value'])
if await childapi_option.ismulti():
await self.add_value(childapi, path, update['value'])
else:
raise ValueError(_('only multi option can have action "add", but "{}" is not a multi').format(path))
else:
@ -880,33 +871,33 @@ class TiramisuDict:
updates_status.setdefault(path, {}).setdefault(index, []).extend(warns)
return updates_status
def set_updates(self,
body):
async def set_updates(self,
body):
root_path = self.root
updates = body.get('updates', [])
updates_status = self.apply_updates(root_path,
updates,
body.get('model'))
updates_status = await self.apply_updates(root_path,
updates,
body.get('model'))
if 'model' in body:
order = []
old_model = body['model']
new_model = self.todict(order=order,
build_schema=False,
build_form=False,
updates_status=updates_status)['model']
values = {'updates': list_keys(old_model, new_model, order, updates_status),
'model': new_model}
new_model = await self.todict(order=order,
build_schema=False,
build_form=False,
updates_status=updates_status)
values = {'updates': list_keys(old_model, new_model['model'], order, updates_status),
'model': new_model['model']}
else:
values = updates_status
return values
def todict(self,
custom_form=[],
build_schema=True,
build_model=True,
build_form=True,
order=None,
updates_status={}):
async def todict(self,
custom_form=[],
build_schema=True,
build_model=True,
build_form=True,
order=None,
updates_status={}):
rootpath = self.root
if build_schema:
schema = {}
@ -921,14 +912,14 @@ class TiramisuDict:
buttons = []
else:
form = None
self.walk(rootpath,
None,
schema,
model,
form,
order,
updates_status,
init=True)
await self.walk(rootpath,
None,
schema,
model,
form,
order,
updates_status,
init=True)
if build_form:
for form_ in custom_form:
if 'key' in form_:
@ -944,7 +935,7 @@ class TiramisuDict:
ret['schema'] = schema
if build_model:
ret['model'] = model
ret['global'] = self.gen_global()
ret['global'] = await self.gen_global()
if build_form:
ret['form'] = form
ret['version'] = '1.0'

View File

@ -21,9 +21,11 @@ from .error import ConfigError, PropertiesOptionError
from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag
from .autolib import Calculation, carry_out_calculation, Params
from .i18n import _
from .asyncinit import asyncinit
class Values(object):
@asyncinit
class Values:
"""The `Config`'s root is indeed in charge of the `Option()`'s values,
but the values are physicaly located here, in `Values`, wich is also
responsible of a caching utility.
@ -31,8 +33,8 @@ class Values(object):
__slots__ = ('_p_',
'__weakref__')
def __init__(self,
storage):
async def __init__(self,
storage):
"""
Initializes the values's dict.
@ -42,18 +44,19 @@ class Values(object):
# store the storage
self._p_ = storage
# set default owner
if self._p_.getowner(None, None) is None:
self._p_.setvalue(None,
None,
owners.user,
None,
True)
owner = await self._p_.getowner(None, None)
if owner is None:
await self._p_.setvalue(None,
None,
owners.user,
None,
True)
#______________________________________________________________________
# get value
def get_cached_value(self,
option_bag):
async def get_cached_value(self,
option_bag):
"""get value directly in cache if set
otherwise calculated value and set it in cache
@ -70,11 +73,11 @@ class Values(object):
'value')
if not validated:
# no cached value so get value
value = self.getvalue(option_bag)
value = await self.getvalue(option_bag)
# validate value
option_bag.option.impl_validate(value,
option_bag,
check_error=True)
await option_bag.option.impl_validate(value,
option_bag,
check_error=True)
# store value in cache
validator = 'validator' in setting_properties and 'demoting_error_warning' not in setting_properties
if not is_cached or validator:
@ -85,9 +88,9 @@ class Values(object):
setting_properties,
validator)
if 'warnings' in setting_properties:
option_bag.option.impl_validate(value,
option_bag,
check_error=False)
await option_bag.option.impl_validate(value,
option_bag,
check_error=False)
if isinstance(value, list):
# return a copy, so value cannot be modified
from copy import copy
@ -95,33 +98,35 @@ class Values(object):
# and return it
return value
def force_to_metaconfig(self, option_bag):
async def force_to_metaconfig(self, option_bag):
# force_metaconfig_on_freeze in config => to metaconfig
# force_metaconfig_on_freeze in option + config is kernelconfig => to metaconfig
settings = option_bag.config_bag.context.cfgimpl_get_settings()
if 'force_metaconfig_on_freeze' in option_bag.properties:
settings = option_bag.config_bag.context.cfgimpl_get_settings()
if 'force_metaconfig_on_freeze' in option_bag.option.impl_getproperties() and \
not settings._p_.getproperties(option_bag.path, None, frozenset()):
not await settings._p_.getproperties(option_bag.path, None, frozenset()):
# if force_metaconfig_on_freeze is only in option (not in config)
return option_bag.config_bag.context.impl_type == 'config'
else:
return True
return False
def _do_value_list(self,
value: Any,
option_bag: OptionBag):
async def _do_value_list(self,
value: Any,
option_bag: OptionBag):
ret = []
for val in value:
if isinstance(val, (list, tuple)):
yield list(self._do_value_list(val, option_bag))
ret.append(await self._do_value_list(val, option_bag))
elif isinstance(val, Calculation):
yield val.execute(option_bag)
ret.append(await val.execute(option_bag))
else:
yield val
ret.append(val)
return ret
def getvalue(self,
option_bag):
async def getvalue(self,
option_bag):
"""actually retrieves the value
:param path: the path of the `Option`
@ -138,48 +143,52 @@ class Values(object):
_index = None
else:
_index = index
owner, value = self._p_.getowner(option_bag.path,
owners.default,
index=_index,
with_value=True)
owner, value = await self._p_.getowner(option_bag.path,
owners.default,
index=_index,
with_value=True)
if owner == owners.default or \
('frozen' in option_bag.properties and \
('force_default_on_freeze' in option_bag.properties or self.force_to_metaconfig(option_bag))):
value = self.getdefaultvalue(option_bag)
('force_default_on_freeze' in option_bag.properties or await self.force_to_metaconfig(option_bag))):
value = await self.getdefaultvalue(option_bag)
else:
value = self.calc_value(option_bag, value)
value = await self.calc_value(option_bag, value)
return value
def calc_value(self, option_bag, value, reset_cache=True):
async def calc_value(self,
option_bag,
value,
reset_cache=True):
if isinstance(value, Calculation):
value = value.execute(option_bag, leadership_must_have_index=True)
value = await value.execute(option_bag,
leadership_must_have_index=True)
elif isinstance(value, (list, tuple)):
value = list(self._do_value_list(value, option_bag))
value = await self._do_value_list(value, option_bag)
if reset_cache:
self.calculate_reset_cache(option_bag, value)
await self.calculate_reset_cache(option_bag, value)
return value
def getdefaultvalue(self,
option_bag):
async def getdefaultvalue(self,
option_bag):
"""get default value:
- get parents config value or
- get calculated value or
- get default value
"""
moption_bag = self._get_modified_parent(option_bag)
moption_bag = await self._get_modified_parent(option_bag)
if moption_bag is not None:
# retrieved value from parent config
return moption_bag.config_bag.context.cfgimpl_get_values().get_cached_value(moption_bag)
return await moption_bag.config_bag.context.cfgimpl_get_values().get_cached_value(moption_bag)
if option_bag.option.impl_has_callback():
# default value is a calculated value
value = self.calculate_value(option_bag)
value = await self.calculate_value(option_bag)
if value is not undefined:
return value
# now try to get default value:
value = self.calc_value(option_bag,
option_bag.option.impl_getdefault())
value = await self.calc_value(option_bag,
option_bag.option.impl_getdefault())
if option_bag.option.impl_is_multi() and option_bag.index is not None and isinstance(value, (list, tuple)):
# if index, must return good value for this index
if len(value) > option_bag.index:
@ -187,11 +196,13 @@ class Values(object):
else:
# no value for this index, retrieve default multi value
# default_multi is already a list for submulti
value = self.calc_value(option_bag,
value = await self.calc_value(option_bag,
option_bag.option.impl_getdefault_multi())
return value
def calculate_reset_cache(self, option_bag, value):
async def calculate_reset_cache(self,
option_bag,
value):
if not 'expire' in option_bag.properties:
return
cache = option_bag.config_bag.context._impl_values_cache
@ -206,25 +217,25 @@ class Values(object):
# so do not invalidate cache
return
# calculated value is a new value, so reset cache
option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
await option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
def calculate_value(self,
option_bag: OptionBag) -> Any:
async def calculate_value(self,
option_bag: OptionBag) -> Any:
# if value has callback, calculate value
callback, callback_params = option_bag.option.impl_get_callback()
value = self.carry_out_calculation(option_bag,
callback,
callback_params)
value = await self.carry_out_calculation(option_bag,
callback,
callback_params)
if isinstance(value, list) and option_bag.index is not None:
# if value is a list and index is set
if option_bag.option.impl_is_submulti() and (value == [] or not isinstance(value[0], list)):
# return value only if it's a submulti and not a list of list
self.calculate_reset_cache(option_bag, value)
await self.calculate_reset_cache(option_bag, value)
return value
if len(value) > option_bag.index:
# return the value for specified index if found
self.calculate_reset_cache(option_bag, value[option_bag.index])
await self.calculate_reset_cache(option_bag, value[option_bag.index])
return value[option_bag.index]
# there is no calculate value for this index,
# so return an other default value
@ -244,19 +255,19 @@ class Values(object):
elif option_bag.option.impl_is_multi() and not isinstance(value, list) and option_bag.index is None:
# return a list for a multi
value = [value]
self.calculate_reset_cache(option_bag, value)
await self.calculate_reset_cache(option_bag, value)
return value
return undefined
def carry_out_calculation(self,
option_bag: OptionBag,
callback: Callable,
callback_params: Optional[Params]) -> Any:
return carry_out_calculation(option_bag.option,
callback=callback,
callback_params=callback_params,
index=option_bag.index,
config_bag=option_bag.config_bag)
async def carry_out_calculation(self,
option_bag: OptionBag,
callback: Callable,
callback_params: Optional[Params]) -> Any:
return await carry_out_calculation(option_bag.option,
callback=callback,
callback_params=callback_params,
index=option_bag.index,
config_bag=option_bag.config_bag)
def isempty(self,
opt,
value,
@ -273,23 +284,23 @@ class Values(object):
#______________________________________________________________________
# set value
def setvalue(self,
value,
option_bag,
_commit):
async def setvalue(self,
value,
option_bag,
_commit):
context = option_bag.config_bag.context
owner = self.get_context_owner()
owner = await self.get_context_owner()
if 'validator' in option_bag.config_bag.properties:
self.setvalue_validation(value,
option_bag)
await self.setvalue_validation(value,
option_bag)
if isinstance(value, list):
# copy
value = value.copy()
self._setvalue(option_bag,
value,
owner,
commit=False)
await self._setvalue(option_bag,
value,
owner,
commit=False)
setting_properties = option_bag.config_bag.properties
validator = 'validator' in setting_properties and 'demoting_error_warning' not in setting_properties
if validator:
@ -301,48 +312,48 @@ class Values(object):
setting_properties,
validator)
if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader():
option_bag.option.impl_get_leadership().follower_force_store_value(self,
value,
option_bag,
owners.forced,
_commit=_commit)
await option_bag.option.impl_get_leadership().follower_force_store_value(self,
value,
option_bag,
owners.forced,
_commit=_commit)
if _commit:
self._p_.commit()
await self._p_.commit()
def setvalue_validation(self,
value,
option_bag):
async def setvalue_validation(self,
value,
option_bag):
settings = option_bag.config_bag.context.cfgimpl_get_settings()
# First validate properties with this value
opt = option_bag.option
settings.validate_frozen(option_bag)
val = self.calc_value(option_bag, value, False)
val = await self.calc_value(option_bag, value, False)
settings.validate_mandatory(val,
option_bag)
# Value must be valid for option
opt.impl_validate(val,
option_bag,
check_error=True)
await opt.impl_validate(val,
option_bag,
check_error=True)
if 'warnings' in option_bag.config_bag.properties:
# No error found so emit warnings
opt.impl_validate(value,
option_bag,
check_error=False)
await opt.impl_validate(value,
option_bag,
check_error=False)
def _setvalue(self,
option_bag,
value,
owner,
commit=True):
option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
self._p_.setvalue(option_bag.path,
value,
owner,
option_bag.index,
commit)
async def _setvalue(self,
option_bag,
value,
owner,
commit=True):
await option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
await self._p_.setvalue(option_bag.path,
value,
owner,
option_bag.index,
commit)
def _get_modified_parent(self,
option_bag: OptionBag) -> Optional[OptionBag]:
async def _get_modified_parent(self,
option_bag: OptionBag) -> Optional[OptionBag]:
""" Search in differents parents a Config with a modified value
If not found, return None
For follower option, return the Config where leader is modified
@ -361,13 +372,13 @@ class Values(object):
# remove force_metaconfig_on_freeze only if option in metaconfig
# hasn't force_metaconfig_on_freeze properties
ori_properties = doption_bag.properties
del doption_bag.properties
if not self.force_to_metaconfig(doption_bag):
doption_bag.properties = await doption_bag.config_bag.context.cfgimpl_get_settings().getproperties(doption_bag)
if not await self.force_to_metaconfig(doption_bag):
doption_bag.properties = ori_properties - {'force_metaconfig_on_freeze'}
else:
doption_bag.properties = ori_properties
parent_owner = parent.cfgimpl_get_values().getowner(doption_bag,
only_default=True)
parent_owner = await parent.cfgimpl_get_values().getowner(doption_bag,
only_default=True)
if parent_owner != owners.default:
return doption_bag
@ -377,17 +388,17 @@ class Values(object):
#______________________________________________________________________
# owner
def is_default_owner(self,
option_bag,
validate_meta=True):
return self.getowner(option_bag,
validate_meta=validate_meta,
only_default=True) == owners.default
async def is_default_owner(self,
option_bag,
validate_meta=True):
return await self.getowner(option_bag,
validate_meta=validate_meta,
only_default=True) == owners.default
def getowner(self,
option_bag,
validate_meta=True,
only_default=False):
async def getowner(self,
option_bag,
validate_meta=True,
only_default=False):
"""
retrieves the option's owner
@ -404,33 +415,33 @@ class Values(object):
option_bag.option = opt
option_bag.path = opt.impl_getpath()
settings = context.cfgimpl_get_settings()
settings.validate_properties(option_bag)
await settings.validate_properties(option_bag)
if 'frozen' in option_bag.properties and \
'force_default_on_freeze' in option_bag.properties:
return owners.default
if only_default:
if self._p_.hasvalue(option_bag.path,
option_bag.index):
if await self._p_.hasvalue(option_bag.path,
option_bag.index):
owner = 'not_default'
else:
owner = owners.default
else:
owner = self._p_.getowner(option_bag.path,
owners.default,
index=option_bag.index)
owner = await self._p_.getowner(option_bag.path,
owners.default,
index=option_bag.index)
if validate_meta is not False and (owner is owners.default or \
'frozen' in option_bag.properties and 'force_metaconfig_on_freeze' in option_bag.properties):
moption_bag = self._get_modified_parent(option_bag)
moption_bag = await self._get_modified_parent(option_bag)
if moption_bag is not None:
owner = moption_bag.config_bag.context.cfgimpl_get_values().getowner(moption_bag,
only_default=only_default)
owner = await moption_bag.config_bag.context.cfgimpl_get_values().getowner(moption_bag,
only_default=only_default)
elif 'force_metaconfig_on_freeze' in option_bag.properties:
return owners.default
return owner
def setowner(self,
owner,
option_bag):
async def setowner(self,
owner,
option_bag):
"""
sets a owner to an option
@ -444,103 +455,101 @@ class Values(object):
if owner in forbidden_owners:
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
if not self._p_.hasvalue(option_bag.path):
if not await self._p_.hasvalue(option_bag.path):
raise ConfigError(_('no value for {0} cannot change owner to {1}'
'').format(option_bag.path, owner))
option_bag.config_bag.context.cfgimpl_get_settings().validate_frozen(option_bag)
self._p_.setowner(option_bag.path,
await self._p_.setowner(option_bag.path,
owner,
index=option_bag.index)
#______________________________________________________________________
# reset
def reset(self,
option_bag,
_commit=True):
async def reset(self,
option_bag,
_commit=True):
context = option_bag.config_bag.context
hasvalue = self._p_.hasvalue(option_bag.path)
hasvalue = await self._p_.hasvalue(option_bag.path)
setting_properties = option_bag.config_bag.properties
if hasvalue and 'validator' in option_bag.config_bag.properties:
fake_context = context._gen_fake_values()
fake_context = await context._gen_fake_values()
config_bag = option_bag.config_bag.copy()
config_bag.remove_validation()
config_bag.context = fake_context
soption_bag = option_bag.copy()
soption_bag.config_bag = config_bag
fake_value = fake_context.cfgimpl_get_values()
fake_value.reset(soption_bag)
await fake_value.reset(soption_bag)
soption_bag.config_bag.properties = option_bag.config_bag.properties
value = fake_value.getdefaultvalue(soption_bag)
fake_value.setvalue_validation(value,
soption_bag)
value = await fake_value.getdefaultvalue(soption_bag)
await fake_value.setvalue_validation(value,
soption_bag)
opt = option_bag.option
if opt.impl_is_leader():
opt.impl_get_leadership().reset(self,
option_bag,
_commit=_commit)
await opt.impl_get_leadership().reset(self,
option_bag,
_commit=_commit)
if hasvalue:
if 'force_store_value' in option_bag.config_bag.properties and 'force_store_value' in option_bag.properties:
value = self.getdefaultvalue(option_bag)
value = await self.getdefaultvalue(option_bag)
self._setvalue(option_bag,
value,
owners.forced,
commit=_commit)
await self._setvalue(option_bag,
value,
owners.forced,
commit=_commit)
else:
# for leader only
value = None
self._p_.resetvalue(option_bag.path,
_commit)
context.cfgimpl_reset_cache(option_bag)
await self._p_.resetvalue(option_bag.path,
_commit)
await context.cfgimpl_reset_cache(option_bag)
if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader():
if value is None:
value = self.getdefaultvalue(option_bag)
option_bag.option.impl_get_leadership().follower_force_store_value(self,
value,
option_bag,
owners.forced,
_commit=_commit)
value = await self.getdefaultvalue(option_bag)
await option_bag.option.impl_get_leadership().follower_force_store_value(self,
value,
option_bag,
owners.forced,
_commit=_commit)
def reset_follower(self,
option_bag,
_commit=True):
if self._p_.hasvalue(option_bag.path, index=option_bag.index):
async def reset_follower(self,
option_bag,
_commit=True):
if await self._p_.hasvalue(option_bag.path, index=option_bag.index):
context = option_bag.config_bag.context
setting_properties = option_bag.config_bag.properties
if 'validator' in setting_properties:
fake_context = context._gen_fake_values()
fake_context = await context._gen_fake_values()
fake_value = fake_context.cfgimpl_get_values()
config_bag = option_bag.config_bag.copy()
config_bag.remove_validation()
config_bag.context = fake_context
soption_bag = option_bag.copy()
soption_bag.config_bag = config_bag
fake_value.reset_follower(soption_bag)
value = fake_value.getdefaultvalue(soption_bag)
fake_value.setvalue_validation(value,
soption_bag)
await fake_value.reset_follower(soption_bag)
value = await fake_value.getdefaultvalue(soption_bag)
await fake_value.setvalue_validation(value,
soption_bag)
if 'force_store_value' in setting_properties and 'force_store_value' in option_bag.properties:
value = self.getdefaultvalue(option_bag)
value = await self.getdefaultvalue(option_bag)
self._setvalue(option_bag,
value,
owners.forced,
commit=_commit)
await self._setvalue(option_bag,
value,
owners.forced,
commit=_commit)
else:
self._p_.resetvalue_index(option_bag.path,
option_bag.index,
_commit)
context.cfgimpl_reset_cache(option_bag)
await self._p_.resetvalue_index(option_bag.path,
option_bag.index,
_commit)
await context.cfgimpl_reset_cache(option_bag)
def reset_leadership(self,
index,
option_bag,
subconfig):
current_value = self.get_cached_value(option_bag)
async def reset_leadership(self,
index,
option_bag,
subconfig):
current_value = await self.get_cached_value(option_bag)
length = len(current_value)
if index >= length:
raise IndexError(_('index {} is greater than the length {} '
@ -548,48 +557,64 @@ class Values(object):
length,
option_bag.option.impl_get_display_name()))
current_value.pop(index)
subconfig.cfgimpl_get_description().pop(self,
index,
option_bag)
self.setvalue(current_value,
option_bag,
_commit=True)
await subconfig.cfgimpl_get_description().pop(self,
index,
option_bag)
await self.setvalue(current_value,
option_bag,
_commit=True)
#______________________________________________________________________
# information
def set_information(self, key, value, path=None):
async def set_information(self,
key,
value,
path=None):
"""updates the information's attribute
:param key: information's key (ex: "help", "doc"
:param value: information's value (ex: "the help string")
"""
self._p_.set_information(path, key, value)
await self._p_.set_information(path,
key,
value)
def get_information(self, key, default=undefined, path=None):
async def get_information(self,
key,
default=undefined,
path=None):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
return self._p_.get_information(path, key, default)
return await self._p_.get_information(path,
key,
default)
def del_information(self, key, raises=True, path=None):
self._p_.del_information(path, key, raises)
async def del_information(self,
key,
raises=True,
path=None):
await self._p_.del_information(path,
key,
raises)
def list_information(self, path=None):
return self._p_.list_information(path)
async def list_information(self,
path=None):
return await self._p_.list_information(path)
#______________________________________________________________________
# mandatory warnings
def _mandatory_warnings(self,
context,
config_bag,
description,
currpath,
subconfig,
od_config_bag):
async def _mandatory_warnings(self,
context,
config_bag,
description,
currpath,
subconfig,
od_config_bag):
settings = context.cfgimpl_get_settings()
for option in description.get_children(config_bag):
for option in await description.get_children(config_bag):
name = option.impl_getname()
path = '.'.join(currpath + [name])
@ -600,16 +625,19 @@ class Values(object):
path,
None,
od_config_bag)
subsubconfig = subconfig.get_subconfig(option_bag)
option_bag.properties = await settings.getproperties(option_bag)
subsubconfig = await subconfig.get_subconfig(option_bag)
except PropertiesOptionError as err:
pass
else:
yield from self._mandatory_warnings(context,
config_bag,
option,
currpath + [name],
subsubconfig,
od_config_bag)
async for option in self._mandatory_warnings(context,
config_bag,
option,
currpath + [name],
subsubconfig,
od_config_bag):
yield option
elif not option.impl_is_symlinkoption():
# don't verifying symlink
try:
@ -619,9 +647,10 @@ class Values(object):
path,
None,
config_bag)
option_bag.properties = await settings.getproperties(option_bag)
if 'mandatory' in option_bag.properties or 'empty' in option_bag.properties:
subconfig.getattr(name,
option_bag)
await subconfig.getattr(name,
option_bag)
else:
for index in range(subconfig.cfgimpl_get_length()):
option_bag = OptionBag()
@ -629,17 +658,18 @@ class Values(object):
path,
index,
config_bag)
option_bag.properties = await settings.getproperties(option_bag)
if 'mandatory' in option_bag.properties or 'empty' in option_bag.properties:
subconfig.getattr(name,
option_bag)
await subconfig.getattr(name,
option_bag)
except PropertiesOptionError as err:
if err.proptype in (['mandatory'], ['empty']):
yield path
except ConfigError:
pass
def mandatory_warnings(self,
config_bag):
async def mandatory_warnings(self,
config_bag):
"""convenience function to trace Options that are mandatory and
where no value has been set
@ -650,33 +680,36 @@ class Values(object):
od_setting_properties = config_bag.properties - {'mandatory', 'empty'}
setting_properties = set(config_bag.properties) - {'warnings'}
setting_properties.update(['mandatory', 'empty'])
config_bag = ConfigBag(context=config_bag.context)
config_bag.properties = frozenset(setting_properties)
config_bag = ConfigBag(context=config_bag.context,
properties=frozenset(setting_properties),
permissives=config_bag.permissives)
config_bag.set_permissive()
od_config_bag = ConfigBag(context=config_bag.context)
od_config_bag.properties = frozenset(od_setting_properties)
od_config_bag = ConfigBag(context=config_bag.context,
properties=frozenset(od_setting_properties),
permissives=config_bag.permissives)
od_config_bag.set_permissive()
descr = context.cfgimpl_get_description()
return self._mandatory_warnings(context,
config_bag,
descr,
[],
context,
od_config_bag)
async for option in self._mandatory_warnings(context,
config_bag,
descr,
[],
context,
od_config_bag):
yield option
#____________________________________________________________
# default owner methods
def set_context_owner(self,
owner):
async def set_context_owner(self,
owner):
":param owner: sets the default value for owner at the Config level"
if owner in forbidden_owners:
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
self._p_.setowner(None,
owner,
index=None)
await self._p_.setowner(None,
owner,
index=None)
def get_context_owner(self):
return self._p_.getowner(None,
None)
async def get_context_owner(self):
return await self._p_.getowner(None,
None)