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