This commit is contained in:
Emmanuel Garette 2017-11-20 17:01:36 +01:00
parent 5d1be8a11a
commit 119ca85041
11 changed files with 1141 additions and 1199 deletions

View file

@ -220,16 +220,12 @@ def _autocheck_set_value(api, path, **kwargs):
submulti_ = api.unrestraint.option(path).option.issubmulti()
ismaster = api.unrestraint.option(path).option.ismaster()
isslave = api.unrestraint.option(path).option.isslave()
# empty_value = _getdefault(api, path, multi, isslave, submulti_)
if not multi:
first_value = FIRST_VALUE
# second_value = SECOND_VALUE
elif submulti_ is False:
first_value = LIST_FIRST_VALUE
# second_value = LIST_SECOND_VALUE
else:
first_value = SUBLIST_FIRST_VALUE
# second_value = SUBLIST_SECOND_VALUE
# for slave should have an index and good length
# for master must append, not set
@ -509,7 +505,7 @@ def _getproperties(multi, isslave, kwargs):
if extra_properties:
properties.extend(extra_properties)
default_props.extend(extra_properties)
return default_props, tuple(properties)
return default_props, frozenset(properties)
def _check_default_properties(api, path, kwargs, props_permissive, props):
@ -540,17 +536,6 @@ def _autocheck_property(api, path, **kwargs):
multi = api.unrestraint.option(path).option.ismulti()
isslave = api.unrestraint.option(path).option.isslave()
# define properties
properties = copy(PROPERTIES_LIST)
if multi and not isslave:
default_props = ['empty']
properties.append('empty')
else:
default_props = []
extra_properties = kwargs.get('extra_properties')
if extra_properties:
properties.extend(extra_properties)
default_props.extend(extra_properties)
default_props, properties = _getproperties(multi, isslave, kwargs)
_check_default_properties(api, path, kwargs, default_props, default_props)
@ -863,7 +848,7 @@ def autocheck_permissive(api, path, **kwargs):
def check_all(cfg, path, meta, multi, default, default_multi, **kwargs):
def check_all(cfg, path, meta, multi, default, default_multi, require, consistency, **kwargs):
if DISPLAY:
text = u' {} launch tests for {}'.format(ICON, path)
if multi is True:
@ -882,22 +867,37 @@ def check_all(cfg, path, meta, multi, default, default_multi, **kwargs):
if api.unrestraint.option(path).option.isslave():
master_path = path.rsplit('.', 1)[0] + '.master'
api.option(master_path).value.set(LIST_SECOND_VALUE)
for func in autocheck_registers:
api = getapi(cfg.duplicate())
if DISPLAY:
print(u' {} {}'.format(ICON, func.__name__))
try:
func(api, path, **kwargs)
except Exception as err:
msg = u'error in function {} for {}'.format(func.__name__, path)
if multi is True:
msg += u' as a multi'
elif multi is submulti:
msg += u' as a submulti'
if multi is True:
msg += u' with default value'
print(u'{}: {}'.format(msg, kwargs))
raise err
if not require:
requires = [False]
else:
requires = [False, True]
for req in requires:
for func in autocheck_registers:
api = getapi(cfg.duplicate())
#FIXME devrait etre dans la config ca ...
api.read_write()
ckwargs = copy(kwargs)
if req:
api.option('extraoptrequire').value.set('value')
if 'permissive' in ckwargs and not 'permissive_od' in ckwargs or \
'propertyerror' in ckwargs and not 'propertyerror_od' in ckwargs:
for to_del in ['permissive', 'propertyerror', 'extra_properties']:
if to_del in ckwargs:
del ckwargs[to_del]
if DISPLAY:
print(u' {} {}'.format(ICON, func.__name__))
try:
func(api, path, **ckwargs)
except Exception as err:
msg = u'error in function {} for {}'.format(func.__name__, path)
if multi is True:
msg += u' as a multi'
elif multi is submulti:
msg += u' as a submulti'
if multi is True:
msg += u' with default value'
print(u'{}: {}'.format(msg, ckwargs))
raise err
def check_deref(weakrefs):
@ -907,23 +907,32 @@ def check_deref(weakrefs):
assert wrf() is None
def make_conf(options, meta, multi, default, default_multi):
def make_conf(options, meta, multi, default, default_multi, require, consistency):
weakrefs = []
dyn = []
goptions = []
def make_option(path, option_infos):
#FIXME
option_type = 'str'
option_properties = []
option_requires = []
isslave = False
if option_infos is not None:
for prop in PROPERTIES:
if option_infos.get(prop, False) is True:
option_properties.append(prop)
if not require:
option_properties.append(prop)
else:
option_requires.append({'option': goptions[0], 'expected': None,
'action': prop})
isslave = option_infos.get('slave', False)
args = [path, "{}'s option".format(path)]
kwargs = {}
if option_properties != []:
kwargs['properties'] = tuple(option_properties)
if multi:
if option_requires != []:
kwargs['requires'] = option_requires
if multi and path is not 'extraoptrequire':
kwargs['multi'] = multi
if default and not submulti:
if multi is False:
@ -933,7 +942,7 @@ def make_conf(options, meta, multi, default, default_multi):
else:
value = SUBLIST_EMPTY_VALUE
kwargs['default'] = value
if default_multi:
if default_multi and path is not 'extraoptrequire':
if multi is not submulti:
value = SECOND_VALUE
else:
@ -942,6 +951,12 @@ def make_conf(options, meta, multi, default, default_multi):
tiramisu_option = OPTIONS_TYPE[option_type]['option']
obj = tiramisu_option(*args, **kwargs)
if not 'extraopt' in path and consistency:
if require:
gopt = goptions[1]
else:
gopt = goptions[0]
obj.impl_add_consistency('not_equal', gopt, warnings_only=True)
weakrefs.append(weakref.ref(obj))
return obj
@ -961,6 +976,7 @@ def make_conf(options, meta, multi, default, default_multi):
if infos.get('dyn', False) is True:
optiondescription = DynOptionDescription
kwargs['callback'] = return_list
dyn.append(path)
options = []
if 'options' in collected:
options.extend(collected['options'])
@ -978,7 +994,22 @@ def make_conf(options, meta, multi, default, default_multi):
return obj
collect_options = {}
for path, option in options.items():
if require or consistency:
noptions = OrderedDict()
if require:
noptions['extraoptrequire'] = {}
if consistency:
subpath = list(options.keys())[0]
if '.' in subpath:
subpath = subpath.rsplit('.', 1)[0] + '.'
else:
subpath = ''
noptions[subpath + 'extraoptconsistency'] = {}
noptions.update(options)
else:
noptions = options
for path, option in noptions.items():
if option is None:
continue
local_collect_options = collect_options
@ -987,8 +1018,9 @@ def make_conf(options, meta, multi, default, default_multi):
local_collect_options = local_collect_options[optiondescription]
local_collect_options['properties'].update(option.get(optiondescription, {}))
option_name = path.split('.')[-1]
path = '.'.join(path.split('.')[:-1])
local_collect_options.setdefault('options', []).append(make_option(option_name, option.get(option_name)))
obj = make_option(option_name, option.get(option_name))
goptions.append(obj)
local_collect_options.setdefault('options', []).append(obj)
rootod = make_optiondescriptions('root', collect_options)
if rootod is None:
@ -998,7 +1030,8 @@ def make_conf(options, meta, multi, default, default_multi):
if meta:
cfg = MetaConfig([cfg], session_id='metatest')
weakrefs.append(weakref.ref(cfg))
return cfg, weakrefs
del goptions
return cfg, weakrefs, dyn
DICT_PATHS = [
@ -1091,24 +1124,35 @@ def test_options(paths):
return kwargs
lpaths = list(paths.keys())
for meta in (False, True):
for default_multi in (False, True):
for default in (False, True):
for multi in (False, True, submulti):
if multi is False and default_multi:
continue
cfg, weakrefs = make_conf(paths, meta, multi, default, default_multi)
if cfg is None:
continue
if len(lpaths) == 9:
check_all(cfg, lpaths[3], meta, multi, default, default_multi, **get_kwargs(lpaths[0]))
check_all(cfg, lpaths[4], meta, multi, default, default_multi, **get_kwargs(lpaths[1]))
check_all(cfg, lpaths[5], meta, multi, default, default_multi, **get_kwargs(lpaths[2]))
check_all(cfg, lpaths[6], meta, multi, default, default_multi, **get_kwargs(lpaths[0]))
check_all(cfg, lpaths[7], meta, multi, default, default_multi, **get_kwargs(lpaths[1]))
check_all(cfg, lpaths[8], meta, multi, default, default_multi, **get_kwargs(lpaths[2]))
else:
for lpath in lpaths:
check_all(cfg, lpath, meta, multi, default, default_multi, **get_kwargs(lpath))
del cfg
check_deref(weakrefs)
meta = False
#for meta in (False, True):
for consistency in (False, True):
for require in (False, True):
for default_multi in (False, True):
for default in (False, True):
for multi in (False, True, submulti):
if multi is submulti and consistency:
continue
if multi is False and default_multi:
continue
cfg, weakrefs, dyn = make_conf(paths, meta, multi, default, default_multi, require, consistency)
if cfg is None:
continue
if dyn:
cnt = 0
idx = 0
for index, lpath in enumerate(lpaths):
if paths[lpath]:
cnt += 1
else:
check_all(cfg, lpaths[index], meta, multi, default,
default_multi, require, consistency, **get_kwargs(lpaths[idx]))
idx += 1
if idx == cnt:
idx = 0
else:
for lpath in lpaths:
check_all(cfg, lpath, meta, multi, default,
default_multi, require, consistency, **get_kwargs(lpath))
del cfg
check_deref(weakrefs)

View file

@ -145,6 +145,7 @@ class TiramisuOptionOwner(CommonTiramisuOption):
setting_properties,
force_permissive,
force_unrestraint):
super(TiramisuOptionOwner, self).__init__(opt,
path,
index,
@ -158,12 +159,16 @@ class TiramisuOptionOwner(CommonTiramisuOption):
def get(self):
"""get owner for a specified option"""
return self.values.getowner(self.opt,
self.path,
self.setting_properties,
index=self.index,
force_permissive=self.force_permissive)
def isdefault(self):
"""is option has defaut value"""
return self.values.is_default_owner(self.opt,
self.path,
self.setting_properties,
index=self.index,
force_permissive=self.force_permissive)
@ -174,10 +179,9 @@ class TiramisuOptionOwner(CommonTiramisuOption):
except AttributeError:
owners.addowner(owner)
obj_owner = getattr(owners, owner)
self.values.setowner(self.opt,
self.values.setowner(self.path,
obj_owner,
self.index,
force_permissive=self.force_permissive)
self.index)
class TiramisuOptionProperty(CommonTiramisuOption):
@ -207,14 +211,14 @@ class TiramisuOptionProperty(CommonTiramisuOption):
self._test_slave_index()
return self.settings.getproperties(self.opt,
self.path,
index=self.index,
obj=False)
self.setting_properties,
index=self.index)
def set(self, properties):
"""set properties for a specified option"""
self.settings.setproperties(set(properties),
self.opt,
self.path)
self.settings.setproperties(self.opt,
self.path,
properties)
def reset(self):
"""reset all personalised properties
@ -247,16 +251,17 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
def get(self):
"""get permissive value for a specified path"""
return self.settings.getpermissive(self.setting_properties, self.path)
return self.settings.getpermissive(self.path)
def set(self, permissive):
self.settings.setpermissive(permissive, opt=self.opt, path=self.path)
self.settings.setpermissive(self.opt,
self.path,
permissive)
#def reset(self, path):
# """reset all personalised properties
# """
# self._get_obj_by_path(path)
# self.settings.reset(_path=path)
def reset(self, path):
"""reset all personalised permissive
"""
self.set(tuple())
class TiramisuOptionValue(CommonTiramisuOption):
@ -409,11 +414,6 @@ class TiramisuAPI(object):
self.config = config
self.force_permissive = force_permissive
self.force_unrestraint = force_unrestraint
settings = self.config.cfgimpl_get_settings()
# #FIXME ?
self.config.read_write()
settings.setpermissive(('hidden',))
#/FIXME ?
def option(self, path, index=None):
validate = not self.force_unrestraint
@ -464,6 +464,16 @@ class TiramisuAPI(object):
txt.append(module(None, None).help)
return '\n'.join(txt)
def read_only(self):
self.config.read_write()
def read_write(self):
settings = self.config.cfgimpl_get_settings()
self.config.read_write()
# #FIXME ?
settings.set_context_permissive(frozenset(['hidden']))
#/FIXME ?
def getapi(config):
"""instanciate TiramisuAPI

View file

@ -90,31 +90,39 @@ class SubConfig(object):
def cfgimpl_get_length(self):
return self._impl_length
def reset_one_option_cache(self, values, settings, resetted_opts, opt, only):
if 'values' in only:
tresetted_opts = copy(resetted_opts)
opt.reset_cache(opt, values, 'values', tresetted_opts)
if 'settings' in only:
tresetted_opts = copy(resetted_opts)
opt.reset_cache(opt, settings, 'settings', tresetted_opts)
else:
if 'properties' in only:
tresetted_opts = copy(resetted_opts)
opt.reset_cache(opt, settings, 'properties', tresetted_opts)
if 'permissives' in only:
tresetted_opts = copy(resetted_opts)
opt.reset_cache(opt, settings, 'permissives', tresetted_opts)
def reset_one_option_cache(self,
values,
settings,
resetted_opts,
opt,
path):
tresetted_opts = copy(resetted_opts)
opt.reset_cache(opt,
path,
values,
'values',
tresetted_opts)
tresetted_opts = copy(resetted_opts)
opt.reset_cache(opt,
path,
settings,
'settings',
tresetted_opts)
resetted_opts |= tresetted_opts
for option in opt._get_dependencies(self):
for woption in opt._get_dependencies(self):
option = woption()
if option in resetted_opts:
continue
self.reset_one_option_cache(values, settings, resetted_opts, option(), only)
del(option)
option_path = opt.impl_getpath(self)
self.reset_one_option_cache(values,
settings,
resetted_opts,
option,
option_path)
del option
def cfgimpl_reset_cache(self,
only_expired=False,
only=('values', 'properties', 'permissives', 'settings'),
opt=None,
path=None,
resetted_opts=None):
@ -127,33 +135,19 @@ class SubConfig(object):
def reset_expired_cache():
# reset cache for expired cache value ony
datetime = int(time())
if 'values' in only:
values._p_.reset_expired_cache(datetime)
if 'settings' in only or 'properties' in only:
settings._p_.reset_expired_cache(datetime)
if 'settings' in only or 'permissives' in only:
settings._pp_.reset_expired_cache(datetime)
values._p_.reset_expired_cache(datetime)
settings._p_.reset_expired_cache(datetime)
def reset_all_cache():
if 'values' in only:
values._p_.reset_all_cache()
if 'settings' in only:
settings._p_.reset_all_cache()
settings._pp_.reset_all_cache()
else:
if 'properties' in only:
settings._p_.reset_all_cache()
if 'permissives' in only:
settings._pp_.reset_all_cache()
values._p_.reset_all_cache()
settings._p_.reset_all_cache()
if resetted_opts is None:
resetted_opts = set()
context = self._cfgimpl_get_context()
if 'values' in only:
values = context.cfgimpl_get_values()
if 'settings' in only or 'properties' in only or 'permissives' in only:
settings = context.cfgimpl_get_settings()
values = context.cfgimpl_get_values()
settings = context.cfgimpl_get_settings()
if not None in (opt, path):
if opt not in resetted_opts:
@ -161,7 +155,7 @@ class SubConfig(object):
settings,
resetted_opts,
opt,
only)
path)
elif only_expired:
reset_expired_cache()
@ -308,7 +302,6 @@ class SubConfig(object):
name,
value,
force_permissive=False,
not_raises=False,
index=None,
setting_properties=undefined,
_commit=True):
@ -319,7 +312,7 @@ class SubConfig(object):
value)
context = self._cfgimpl_get_context()
if setting_properties is undefined:
setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=True)
setting_properties = context.cfgimpl_get_settings().get_context_properties()
if '.' in name: # pragma: optional cover
self, name = self.cfgimpl_get_home_by_path(name,
force_permissive=force_permissive,
@ -332,21 +325,17 @@ class SubConfig(object):
not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover
raise TypeError(_("can't assign to a SymlinkOption"))
else:
msg = self.cfgimpl_get_description().impl_validate_value(child, value, self)
if msg is not None:
if not_raises:
return msg
else:
raise msg
self.cfgimpl_get_description().impl_validate_value(child,
value,
self)
subpath = self._get_subpath(name)
return self.cfgimpl_get_values().setitem(child,
value,
subpath,
force_permissive,
not_raises,
index,
setting_properties,
_commit)
return self.cfgimpl_get_values().setvalue(child,
value,
subpath,
force_permissive,
index,
setting_properties,
_commit)
def __delattr__(self, name):
self.delattr(name)
@ -467,12 +456,12 @@ class SubConfig(object):
index=index)
elif option.impl_is_optiondescription():
if setting_properties:
props = self.cfgimpl_get_settings().validate_properties(option,
True,
False,
path=subpath,
force_permissive=force_permissive,
setting_properties=setting_properties)
self.cfgimpl_get_settings().validate_properties(option,
True,
False,
path=subpath,
force_permissive=force_permissive,
setting_properties=setting_properties)
if returns_option is True:
return option
return SubConfig(option,
@ -618,7 +607,7 @@ class SubConfig(object):
fullpath=False):
"""exports the whole config into a `dict`, for example:
>>> print cfg.make_dict()
>>> print(cfg.make_dict())
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None}
@ -626,13 +615,13 @@ class SubConfig(object):
:param flatten: returns a dict(name=value) instead of a dict(path=value)
::
>>> print cfg.make_dict(flatten=True)
>>> print(cfg.make_dict(flatten=True))
{'var5': None, 'var4': None, 'var6': None}
:param withoption: returns the options that are present in the very same
`OptionDescription` than the `withoption` itself::
>>> print cfg.make_dict(withoption='var1')
>>> print(cfg.make_dict(withoption='var1'))
{'od2.var4': None, 'od2.var5': None,
'od2.var6': None,
'od2.var1': u'value',
@ -643,8 +632,8 @@ class SubConfig(object):
:param withvalue: returns the options that have the value `withvalue`
::
>>> print c.make_dict(withoption='var1',
withvalue=u'value')
>>> print(c.make_dict(withoption='var1',
withvalue=u'value'))
{'od2.var4': None,
'od2.var5': None,
'od2.var6': None,
@ -798,14 +787,12 @@ class _CommonConfig(SubConfig):
else:
if index is None and option.impl_is_master_slaves('slave'):
subpath = self._get_subpath(path)
props = self.cfgimpl_get_settings().validate_properties(option,
True,
False,
path=subpath,
force_permissive=force_permissive,
setting_properties=setting_properties)
if props:
raise props
self.cfgimpl_get_settings().validate_properties(option,
True,
False,
path=subpath,
force_permissive=force_permissive,
setting_properties=setting_properties)
return option
else:
return self.getattr(path,
@ -975,19 +962,16 @@ class GroupConfig(_CommonConfig):
def cfgimpl_reset_cache(self,
only_expired=False,
only=('values', 'settings'),
opt=None,
path=None,
resetted_opts=set()):
if isinstance(self, MetaConfig):
super(GroupConfig, self).cfgimpl_reset_cache(only_expired=only_expired,
only=only,
opt=opt,
path=path,
resetted_opts=copy(resetted_opts))
for child in self._impl_children:
child.cfgimpl_reset_cache(only_expired=only_expired,
only=only,
opt=opt,
path=path,
resetted_opts=copy(resetted_opts))

View file

@ -155,7 +155,7 @@ class ValueWarning(UserWarning): # pragma: optional cover
...
>>> w[0].message.opt == s
True
>>> print str(w[0].message)
>>> print(str(w[0].message))
invalid value val for option s: pouet
"""
def __init__(self, msg, opt):

View file

@ -32,7 +32,7 @@ if sys.version_info[0] >= 3: # pragma: no cover
else:
from inspect import getargspec
STATIC_TUPLE = tuple()
STATIC_TUPLE = frozenset()
submulti = 2
@ -145,6 +145,8 @@ class Base(object):
requires = undefined
if properties is None:
properties = tuple()
if is_multi and 'empty' not in properties:
properties = tuple(list(properties) + ['empty'])
if not isinstance(properties, tuple):
raise TypeError(_('invalid properties type {0} for {1},'
' must be a tuple').format(
@ -406,11 +408,15 @@ class BaseOption(Base):
name = name.encode('utf8')
return name
def reset_cache(self, opt, obj, type_, resetted_opts):
def reset_cache(self,
opt,
path,
obj,
type_,
resetted_opts):
if opt in resetted_opts:
return
if not type_ == 'values' or not opt.impl_is_optiondescription():
path = opt.impl_getpath(obj._getcontext())
if type_ != 'permissives':
obj._p_.delcache(path)
if type_ in ['settings', 'permissives']:

View file

@ -21,6 +21,7 @@
# ____________________________________________________________
import warnings
import sys
import weakref
from .baseoption import OnlyOption, submulti, DynSymLinkOption, validate_callback, STATIC_TUPLE
from ..i18n import _
@ -146,9 +147,17 @@ class Option(OnlyOption):
def impl_is_multi(self):
return getattr(self, '_multi', 1) != 1
def _launch_consistency(self, current_opt, func, option, value, context,
index, submulti_index, opts, warnings_only,
transitive):
def _launch_consistency(self,
current_opt,
func,
option,
value,
context,
index,
opts,
warnings_only,
transitive,
setting_properties):
"""Launch consistency now
:param func: function name, this name should start with _cons_
@ -174,7 +183,8 @@ class Option(OnlyOption):
all_cons_vals = []
all_cons_opts = []
val_consistencies = True
for opt in opts:
for wopt in opts:
opt = wopt()
if (isinstance(opt, DynSymLinkOption) and option._dyn == opt._dyn) or \
option == opt:
# option is current option
@ -195,7 +205,9 @@ class Option(OnlyOption):
else:
_index = index
try:
opt_value = context.getattr(path, validate=False,
opt_value = context.getattr(path,
setting_properties,
validate=False,
index=_index,
force_permissive=True)
except PropertiesOptionError as err:
@ -254,7 +266,6 @@ class Option(OnlyOption):
context=undefined,
validate=True,
force_index=None,
force_submulti_index=None,
current_opt=undefined,
is_multi=None,
display_error=True,
@ -270,9 +281,6 @@ class Option(OnlyOption):
:param force_index: if multi, value has to be a list
not if force_index is not None
:type force_index: integer
:param force_submulti_index: if submulti, value has to be a list
not if force_submulti_index is not None
:type force_submulti_index: integer
"""
if not validate:
return
@ -287,10 +295,12 @@ class Option(OnlyOption):
if display_error and self.impl_is_unique() and len(set(value)) != len(value):
for idx, val in enumerate(value):
if val in value[idx+1:]:
return ValueError(_('invalid value "{}", this value is already in "{}"').format(
val, self.impl_get_display_name()))
return ValueError(_('invalid value "{}", this value is already in "{}"'
'').format(val,
self.impl_get_display_name()))
def calculation_validator(val, _index):
def calculation_validator(val,
_index):
validator, validator_params = self.impl_get_validator()
if validator is not None:
if validator_params != {}:
@ -316,9 +326,10 @@ class Option(OnlyOption):
if isinstance(value, Exception):
return value
def do_validation(_value, _index, submulti_index):
def do_validation(_value,
_index):
if _value is None:
error = warning = None
error = None
else:
if display_error:
# option validation
@ -327,35 +338,41 @@ class Option(OnlyOption):
current_opt)
if err:
if debug: # pragma: no cover
log.debug('do_validation: value: {0}, index: {1}, '
'submulti_index: {2}'.format(_value,
_index,
submulti_index),
log.debug('do_validation: value: {0}, index: {1}:'
' {2}'.format(_value,
_index),
exc_info=True)
err_msg = '{0}'.format(err)
if err_msg:
msg = _('"{0}" is an invalid {1} for "{2}", {3}'
'').format(_value, self._display_name,
'').format(_value,
self._display_name,
self.impl_get_display_name(), err_msg)
else:
msg = _('"{0}" is an invalid {1} for "{2}"'
'').format(_value, self._display_name,
'').format(_value,
self._display_name,
self.impl_get_display_name())
return ValueError(msg)
error = None
is_warnings_only = getattr(self, '_warnings_only', False)
if ((display_error and not is_warnings_only) or
(display_warnings and is_warnings_only)):
error = calculation_validator(_value, _index)
error = calculation_validator(_value,
_index)
if not error:
error = self._second_level_validation(_value, is_warnings_only)
error = self._second_level_validation(_value,
is_warnings_only)
if error:
if debug: # pragma: no cover
log.debug(_('do_validation for {0}: error in value').format(
self.impl_getname()), exc_info=True)
if is_warnings_only:
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format(
_value, self._display_name, self.impl_get_display_name(), error)
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}'
'').format(_value,
self._display_name,
self.impl_get_display_name(),
error)
warnings.warn_explicit(ValueWarning(msg, self),
ValueWarning,
self.__class__.__name__, 0)
@ -367,9 +384,9 @@ class Option(OnlyOption):
_value,
context,
_index,
submulti_index,
display_warnings,
display_error)
display_error,
setting_properties)
if isinstance(ret, ValueError):
error = ret
elif ret:
@ -390,22 +407,22 @@ class Option(OnlyOption):
is_multi = self.impl_is_multi()
if not is_multi:
return do_validation(value, None, None)
return do_validation(value, None)
elif force_index is not None:
if self.impl_is_submulti() and force_submulti_index is None:
if self.impl_is_submulti():
err = _is_not_unique(value)
if err:
return err
if not isinstance(value, list):
return ValueError(_('invalid value "{0}" for "{1}" which'
' must be a list').format(
value, self.impl_get_display_name()))
value, self.impl_get_display_name()))
for idx, val in enumerate(value):
if isinstance(val, list): # pragma: no cover
return ValueError(_('invalid value "{}" for "{}" '
'which must not be a list').format(val,
self.impl_get_display_name()))
err = do_validation(val, force_index, idx)
self.impl_get_display_name()))
err = do_validation(val, force_index)
if err:
return err
else:
@ -419,12 +436,12 @@ class Option(OnlyOption):
return ValueError(_('invalid value "{}", this value is already'
' in "{}"').format(value,
self.impl_get_display_name()))
return do_validation(value, force_index, force_submulti_index)
return do_validation(value, force_index)
elif not isinstance(value, list):
return ValueError(_('invalid value "{0}" for "{1}" which '
'must be a list').format(value,
self.impl_getname()))
elif self.impl_is_submulti() and force_submulti_index is None:
elif self.impl_is_submulti():
for idx, val in enumerate(value):
err = _is_not_unique(val)
if err:
@ -434,8 +451,9 @@ class Option(OnlyOption):
'which must be a list of list'
'').format(val,
self.impl_getname()))
for slave_idx, slave_val in enumerate(val):
err = do_validation(slave_val, idx, slave_idx)
for slave_val in val:
err = do_validation(slave_val,
idx)
if err:
return err
else:
@ -443,16 +461,17 @@ class Option(OnlyOption):
if err:
return err
for idx, val in enumerate(value):
err = do_validation(val, idx, force_submulti_index)
err = do_validation(val,
idx)
if err:
return err
return self._valid_consistency(current_opt,
None,
context,
None,
None,
display_warnings,
display_error)
display_error,
setting_properties)
def impl_is_dynsymlinkoption(self):
return False
@ -480,7 +499,10 @@ class Option(OnlyOption):
"accesses the Option's doc"
return self.impl_get_information('doc')
def _valid_consistencies(self, other_opts, init=True, func=None):
def _valid_consistencies(self,
other_opts,
init=True,
func=None):
if self._is_subdyn():
dynod = self._subdyn()
else:
@ -488,7 +510,11 @@ class Option(OnlyOption):
if self.impl_is_submulti():
raise ConfigError(_('cannot add consistency with submulti option'))
is_multi = self.impl_is_multi()
for opt in other_opts:
for wopt in other_opts:
if isinstance(wopt, weakref.ReferenceType):
opt = wopt()
else:
opt = wopt
if opt.impl_is_submulti():
raise ConfigError(_('cannot add consistency with submulti option'))
if not isinstance(opt, Option):
@ -515,7 +541,10 @@ class Option(OnlyOption):
if func != 'not_equal':
opt._has_dependency = True
def impl_add_consistency(self, func, *other_opts, **params):
def impl_add_consistency(self,
func,
*other_opts,
**params):
"""Add consistency means that value will be validate with other_opts
option's values.
@ -525,39 +554,51 @@ class Option(OnlyOption):
:type other_opts: `list` of `tiramisu.option.Option`
:param params: extra params (warnings_only and transitive are allowed)
"""
if self.impl_is_readonly():
if self.impl_is_readonly():
raise AttributeError(_("'{0}' ({1}) cannot add consistency, option is"
" read-only").format(
self.__class__.__name__,
self.impl_getname()))
self._valid_consistencies(other_opts, func=func)
self._valid_consistencies(other_opts,
func=func)
func = '_cons_{0}'.format(func)
if func not in dir(self):
raise ConfigError(_('consistency {0} not available for this option').format(func))
all_cons_opts = tuple([self] + list(other_opts))
options = [weakref.ref(self)]
for option in other_opts:
options.append(weakref.ref(option))
all_cons_opts = tuple(options)
unknown_params = set(params.keys()) - set(['warnings_only', 'transitive'])
if unknown_params != set():
raise ValueError(_('unknown parameter {0} in consistency').format(unknown_params))
self._add_consistency(func, all_cons_opts, params)
self._add_consistency(func,
all_cons_opts,
params)
#validate default value when add consistency
err = self.impl_validate(self.impl_getdefault())
if err:
self._del_consistency()
raise err
if func in ALLOWED_CONST_LIST:
for opt in all_cons_opts:
if getattr(opt, '_unique', undefined) == undefined:
opt._unique = True
if func != '_cons_not_equal':
#consistency could generate warnings or errors
self._has_dependency = True
for opt in all_cons_opts:
for wopt in all_cons_opts:
opt = wopt()
if func in ALLOWED_CONST_LIST:
if getattr(opt, '_unique', undefined) == undefined:
opt._unique = True
if opt != self:
self._add_dependency(opt)
opt._add_dependency(self)
def _valid_consistency(self, option, value, context, index, submulti_idx,
display_warnings, display_error):
def _valid_consistency(self,
option,
value,
context,
index,
display_warnings,
display_error,
setting_properties):
if context is not undefined:
descr = context.cfgimpl_get_description()
if descr._cache_consistencies is None:
@ -586,10 +627,16 @@ class Option(OnlyOption):
opts.append(opt._impl_to_dyn(name, path))
else:
opts = all_cons_opts
err = opts[0]._launch_consistency(self, func, option, value,
context, index, submulti_idx,
opts, warnings_only,
transitive)
err = opts[0]()._launch_consistency(self,
func,
option,
value,
context,
index,
opts,
warnings_only,
transitive,
setting_properties)
if err:
return err
@ -680,7 +727,10 @@ class Option(OnlyOption):
#____________________________________________________________
# consistency
def _add_consistency(self, func, all_cons_opts, params):
def _add_consistency(self,
func,
all_cons_opts,
params):
cons = (func, all_cons_opts, params)
consistencies = getattr(self, '_consistencies', None)
if consistencies is None:

View file

@ -125,8 +125,8 @@ class CacheOptionDescription(BaseOption):
'must be in same master/slaves for {1}').format(
require_opt.impl_getname(), option.impl_getname()))
else:
raise ValueError(_('malformed requirements option {0} '
'must not be a multi for {1}').format(
raise ValueError(_('malformed requirements option "{0}" '
'must not be a multi for "{1}"').format(
require_opt.impl_getname(), option.impl_getname()))
if init:
if len(cache_option) != len(set(cache_option)):
@ -137,7 +137,7 @@ class CacheOptionDescription(BaseOption):
if _consistencies != {}:
self._cache_consistencies = {}
for opt, cons in _consistencies.items():
if opt not in cache_option: # pragma: optional cover
if opt() not in cache_option: # pragma: optional cover
raise ConfigError(_('consistency with option {0} '
'which is not in Config').format(
opt.impl_getname()))
@ -437,12 +437,12 @@ class OptionDescription(OptionDescriptionWalk):
for child in valid_child:
if child == old: # pragma: optional cover
raise ConflictError(_('duplicate option name: '
'{0}').format(child))
'"{0}"').format(child))
if dynopt_names:
for dynopt in dynopt_names:
if child != dynopt and child.startswith(dynopt):
raise ConflictError(_('option must not start as '
'dynoptiondescription'))
raise ConflictError(_('the option\'s name "{}" start as '
'the dynoptiondescription\'s name "{}"').format(child, dynopt))
old = child
_setattr = object.__setattr__
_setattr(self, '_children', (tuple(child_names), tuple(children)))
@ -623,7 +623,7 @@ class MasterSlaves(OptionDescription):
name))
slaves.append(child)
child._add_dependency(self)
for child in children:
for idx, child in enumerate(children):
if child._is_symlinkoption(): # pragma: optional cover
raise ValueError(_("master group {0} shall not have "
"a symlinkoption").format(self.impl_getname()))
@ -635,6 +635,11 @@ class MasterSlaves(OptionDescription):
"in group {1}"
": this option is not a multi"
"").format(child.impl_getname(), self.impl_getname()))
# no empty property for save
if idx != 0:
properties = list(child._properties)
properties.remove('empty')
child._properties = tuple(properties)
callback, callback_params = master.impl_get_callback()
if callback is not None and callback_params != {}:
for callbacks in callback_params.values():

View file

@ -106,7 +106,8 @@ rw_append = set(['frozen', 'disabled', 'validator', 'hidden'])
rw_remove = set(['permissive', 'everything_frozen', 'mandatory', 'empty'])
forbidden_set_properties = set(['force_store_value'])
forbidden_set_properties = frozenset(['force_store_value'])
forbidden_set_permissives = frozenset(['frozen', 'force_default_on_freeze'])
log = getLogger('tiramisu')
@ -124,15 +125,16 @@ class _NameSpace(object):
when attribute is added, we cannot delete it
"""
def __setattr__(self, name, value):
if name in self.__dict__: # pragma: optional cover
def __setattr__(self,
name,
value):
if name in self.__dict__:
raise ConstError(_("can't rebind {0}").format(name))
self.__dict__[name] = value
def __delattr__(self, name): # pragma: optional cover
if name in self.__dict__:
raise ConstError(_("can't unbind {0}").format(name))
raise ValueError(name)
def __delattr__(self,
name):
raise ConstError(_("can't unbind {0}").format(name))
class GroupModule(_NameSpace):
@ -168,69 +170,44 @@ class OwnerModule(_NameSpace):
"""groups that are default (typically 'default')"""
pass
class MultiTypeModule(_NameSpace):
"namespace for the master/slaves"
class MultiType(str):
pass
class DefaultMultiType(MultiType):
pass
class MasterMultiType(MultiType):
pass
class SlaveMultiType(MultiType):
pass
# ____________________________________________________________
def populate_groups():
"""populates the available groups in the appropriate namespaces
groups.default
default group set when creating a new optiondescription
groups.master
master group is a special optiondescription, all suboptions should be
multi option and all values should have same length, to find master's
option, the optiondescription's name should be same than de master's
option
groups.family
example of group, no special behavior with this group's type
"""
groups.default = groups.DefaultGroupType('default')
groups.master = groups.MasterGroupType('master')
groups.family = groups.GroupType('family')
def populate_owners():
"""populates the available owners in the appropriate namespaces
default
is the config owner after init time
user
is the generic is the generic owner
"""
setattr(owners, 'default', owners.DefaultOwner('default'))
setattr(owners, 'user', owners.Owner('user'))
setattr(owners, 'forced', owners.Owner('forced'))
def addowner(name):
def addowner(self, name):
"""
:param name: the name of the new owner
"""
setattr(owners, name, owners.Owner(name))
setattr(owners, 'addowner', addowner)
# ____________________________________________________________
# populate groups and owners with default attributes
# populate groups
groups = GroupModule()
populate_groups()
"""groups.default
default group set when creating a new optiondescription"""
groups.default = groups.DefaultGroupType('default')
"""groups.master
master group is a special optiondescription, all suboptions should be
multi option and all values should have same length, to find master's
option, the optiondescription's name should be same than de master's
option"""
groups.master = groups.MasterGroupType('master')
""" groups.family
example of group, no special behavior with this group's type"""
groups.family = groups.GroupType('family')
# ____________________________________________________________
# populate owners with default attributes
owners = OwnerModule()
populate_owners()
"""default
is the config owner after init time"""
owners.default = owners.DefaultOwner('default')
"""user
is the generic is the generic owner"""
owners.user = owners.Owner('user')
"""forced
special owner when value is forced"""
owners.forced = owners.Owner('forced')
# ____________________________________________________________
@ -241,73 +218,6 @@ class Undefined(object):
undefined = Undefined()
# ____________________________________________________________
class Property(object):
"a property is responsible of the option's value access rules"
__slots__ = ('_setting', '_properties', '_opt', '_path')
def __init__(self, setting, prop, opt=None, path=None):
self._opt = opt
self._path = path
self._setting = setting
self._properties = prop
def append(self, propname):
"""Appends a property named propname
:param propname: a predefined or user defined property name
:type propname: string
"""
self._append(propname)
def _append(self, propname, save=True):
if self._opt is not None and self._opt.impl_getrequires() is not None \
and propname in getattr(self._opt, '_calc_properties', static_set): # pragma: optional cover
raise ValueError(_('cannot append {0} property for option {1}: '
'this property is calculated').format(
propname, self._opt.impl_getname()))
if propname in forbidden_set_properties:
raise ConfigError(_('cannot add those properties: {0}').format(propname))
self._properties.add(propname)
if save:
self._setting.setproperties(self._properties, self._opt, self._path, force=True)
def remove(self, propname):
"""Removes a property named propname
:param propname: a predefined or user defined property name
:type propname: string
"""
if propname in self._properties:
self._properties.remove(propname)
self._setting.setproperties(self._properties, self._opt, self._path)
def extend(self, propnames):
"""Extends properties to the existing properties
:param propnames: an iterable made of property names
:type propnames: iterable of string
"""
for propname in propnames:
self._append(propname, save=False)
self._setting.setproperties(self._properties, self._opt, self._path)
def reset(self):
"""resets the properties (does not **clear** the properties,
default properties are still present)
"""
self._setting.reset(_path=self._path)
def __contains__(self, propname):
return propname in self._properties
def __repr__(self):
return str(list(self._properties))
def get(self):
return tuple(self._properties)
#____________________________________________________________
class Settings(object):
"``config.Config()``'s configuration options settings"
@ -341,321 +251,89 @@ class Settings(object):
return context
#____________________________________________________________
# properties methods
def __contains__(self, propname):
"enables the pythonic 'in' syntaxic sugar"
return propname in self._getproperties(read_write=False)
# get properties and permissive methods
def __repr__(self):
return str(list(self._getproperties(read_write=False)))
def __getitem__(self, opt):
path = opt.impl_getpath(self._getcontext())
return self.getproperties(opt, path)
def get_context_properties(self):
ntime = int(time())
if self._p_.hascache(None,
None):
is_cached, props = self._p_.getcache(None,
ntime,
None)
else:
is_cached = False
if not is_cached or 'cache' not in props:
meta = self._getcontext().cfgimpl_get_meta()
if meta is None:
props = self._p_.getproperties(None,
default_properties)
else:
props = meta.cfgimpl_get_settings().get_context_properties()
if 'cache' in props:
if 'expire' in props:
ntime = ntime + expires_time
else:
ntime = None
self._p_.setcache(None, props, ntime, None)
return props
def getproperties(self,
opt,
path,
setting_properties=undefined,
setting_properties,
index=None,
obj=True):
"""get properties for a specified option
"""
properties = self._getproperties(opt,
path,
index=index,
setting_properties=setting_properties)
if obj:
return Property(self, properties, opt, path)
return properties
def get_context_properties(self):
return self._getproperties()
def __setitem__(self, opt, value): # pragma: optional cover
raise ValueError(_('you should only append/remove properties'))
def reset(self, opt=None, _path=None, all_properties=False):
if all_properties and (_path or opt): # pragma: optional cover
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())
self._p_.delproperties(_path)
self._getcontext().cfgimpl_reset_cache(opt=opt, path=_path, only=('settings', 'values'))
def _getproperties(self,
opt=None,
path=None,
setting_properties=undefined,
read_write=True,
apply_requires=True,
index=None):
apply_requires=True):
"""
"""
if opt is None:
ntime = int(time())
if self._p_.hascache(path, index):
is_cached, props = self._p_.getcache(path, ntime, None)
else:
is_cached = False
if not is_cached or 'cache' not in props:
meta = self._getcontext().cfgimpl_get_meta()
if meta is None:
props = self._p_.getproperties(path, default_properties)
else:
props = meta.cfgimpl_get_settings()._getproperties()
if 'cache' in props:
if 'expire' in props:
ntime = ntime + expires_time
else:
ntime = None
self._p_.setcache(path, props, ntime, None)
else:
if path is None: # pragma: optional cover
raise ValueError(_('if opt is not None, path should not be'
' None in _getproperties'))
if setting_properties is undefined:
setting_properties = self._getproperties(read_write=False)
is_cached = False
is_cached = False
if apply_requires:
if 'cache' in setting_properties and 'expire' in setting_properties:
ntime = int(time())
else:
ntime = None
if 'cache' in setting_properties and self._p_.hascache(path, index):
is_cached, props = self._p_.getcache(path, ntime, index)
if not is_cached:
props = self._p_.getproperties(path, opt.impl_getproperties())
if not opt.impl_is_optiondescription() and opt.impl_is_multi() and \
not opt.impl_is_master_slaves('slave'):
props.add('empty')
if apply_requires:
requires = self.apply_requires(opt, path, setting_properties, index, False)
if requires != set([]):
props = copy(props)
props |= requires
if 'cache' in setting_properties:
if 'expire' in setting_properties:
ntime = ntime + expires_time
self._p_.setcache(path, props, ntime, index)
if read_write:
props = copy(props)
return props
def append(self, propname):
"puts property propname in the Config's properties attribute"
props = self._p_.getproperties(None, default_properties)
if propname not in props:
props.add(propname)
self.setproperties(props, None, None)
def remove(self, propname):
"deletes property propname in the Config's properties attribute"
props = self._p_.getproperties(None, default_properties)
if propname in props:
props.remove(propname)
self.setproperties(props, None, None)
def extend(self, propnames):
for propname in propnames:
self.append(propname)
def _setproperties(self, properties, opt, path, force=False):
"""just for compatibility
"""
self.setproperties(properties, opt, path, force)
def setproperties(self, properties, opt, path, force=False):
"""save properties for specified path
(never save properties if same has option properties)
"""
if self._getcontext().cfgimpl_get_meta() is not None:
raise ConfigError(_('cannot change global property with metaconfig'))
if not force:
forbidden_properties = forbidden_set_properties & properties
if forbidden_properties:
raise ConfigError(_('cannot add those properties: {0}').format(
' '.join(forbidden_properties)))
self._p_.setproperties(path, properties)
#values too because of slave values could have a PropertiesOptionError has value
self._getcontext().cfgimpl_reset_cache(opt=opt, path=path, only=('values', 'properties',))
def getpermissive(self, setting_properties, path=None):
if 'cache' in setting_properties and 'expire' in setting_properties:
ntime = int(time())
else:
ntime = None
if 'cache' in setting_properties and self._pp_.hascache(path, None):
is_cached, perm = self._pp_.getcache(path, ntime, None)
else:
is_cached = False
if not is_cached:
if path is not None:
perm = self._pp_.getpermissive(path)
else:
perm = self._pp_.getpermissive()
if 'cache' in setting_properties:
if 'expire' in setting_properties:
ntime = ntime + expires_time
self._pp_.setcache(path, perm, ntime, None)
return perm
#____________________________________________________________
def validate_properties(self, opt_or_descr, is_descr, check_frozen, path,
value=None, force_permissive=False,
setting_properties=undefined,
self_properties=undefined,
index=None, debug=False):
"""
validation upon the properties related to `opt_or_descr`
:param opt_or_descr: an option or an option description object
:param force_permissive: behaves as if the permissive property
was present
:param is_descr: we have to know if we are in an option description,
just because the mandatory property
doesn't exist here
:param check_frozen: in the validation process, an option is to be modified,
the behavior can be different
(typically with the `frozen` property)
"""
# opt properties
if setting_properties is undefined:
setting_properties = self._getproperties(read_write=False)
if self_properties is not undefined:
properties = copy(self_properties)
else:
properties = self._getproperties(opt_or_descr, path,
setting_properties=setting_properties,
index=index)
# calc properties
properties &= setting_properties
if not is_descr:
#mandatory
if 'mandatory' in properties and \
not self._getcontext().cfgimpl_get_values()._isempty(
opt_or_descr, value, index=index):
properties.remove('mandatory')
elif 'empty' in properties and \
'empty' in setting_properties and \
self._getcontext().cfgimpl_get_values()._isempty(
opt_or_descr, value, force_allow_empty_list=True, index=index):
properties.add('mandatory')
# should return 'frozen' only when tried to modify a value
if check_frozen and 'everything_frozen' in setting_properties:
properties.add('frozen')
elif 'frozen' in properties and not check_frozen:
properties.remove('frozen')
if 'empty' in properties:
properties.remove('empty')
# remove permissive properties
if properties != frozenset():
# remove opt permissive
# permissive affect option's permission with or without permissive
# global property
properties -= self.getpermissive(setting_properties, path)
# remove global permissive if need
if force_permissive is True or 'permissive' in setting_properties:
properties -= self.getpermissive(setting_properties)
# at this point an option should not remain in properties
if properties != frozenset():
props = list(properties)
datas = {'opt': opt_or_descr, 'path': path, 'setting_properties': setting_properties,
'index': index, 'debug': True}
if is_descr:
opt_type = 'optiondescription'
else:
opt_type = 'option'
if 'frozen' in properties:
raise PropertiesOptionError(_('cannot change the value for '
'option "{0}" this option is'
' frozen').format(
opt_or_descr.impl_getname()),
props,
self,
datas,
opt_type)
else:
if len(props) == 1:
prop_msg = _('property')
else:
prop_msg = _('properties')
raise PropertiesOptionError(_('cannot access to {0} "{1}" '
'because has {2} {3}'
'').format(opt_type,
opt_or_descr.impl_get_display_name(),
prop_msg,
display_list(props)),
props,
self,
datas,
opt_type)
def setpermissive(self, permissive, opt=None, path=None):
"""
enables us to put the permissives in the storage
:param path: the option's path
:param type: str
:param opt: if an option object is set, the path is extracted.
it is better (faster) to set the path parameter
instead of passing a :class:`tiramisu.option.Option()` object.
"""
if opt is not None and path is None:
path = opt.impl_getpath(self._getcontext())
if not isinstance(permissive, tuple): # pragma: optional cover
raise TypeError(_('permissive must be a tuple'))
self._pp_.setpermissive(path, permissive)
setting_properties = self._getproperties(read_write=False)
self._getcontext().cfgimpl_reset_cache(opt=opt, path=path, only=('properties', 'values'))
if 'cache' in setting_properties:
if 'expire' in setting_properties:
ntime = int(time()) + expires_time
if apply_requires:
if 'cache' in setting_properties and 'expire' in setting_properties:
ntime = int(time())
else:
ntime = None
self._pp_.setcache(path, set(permissive), ntime, None)
if 'cache' in setting_properties and self._p_.hascache(path,
index):
is_cached, props = self._p_.getcache(path,
ntime,
index)
if not is_cached:
props = self._p_.getproperties(path,
opt.impl_getproperties())
if apply_requires:
requires = self.apply_requires(opt,
path,
setting_properties,
index,
False)
#FIXME devrait etre un frozenset!
if requires != set([]):
props = copy(props)
props |= requires
#____________________________________________________________
def setowner(self, owner):
":param owner: sets the default value for owner at the Config level"
if not isinstance(owner, owners.Owner): # pragma: optional cover
raise TypeError(_("invalid generic owner {0}").format(str(owner)))
self._owner = owner
#FIXME qu'est ce qui se passe si pas de owner ??
props -= self.getpermissive(path)
if apply_requires and 'cache' in setting_properties:
if 'expire' in setting_properties:
ntime = ntime + expires_time
self._p_.setcache(path,
props,
ntime,
index)
return props
def getowner(self):
return self._owner
def get_context_permissive(self):
return self.getpermissive(None)
#____________________________________________________________
def _read(self, remove, append):
props = self._p_.getproperties(None, default_properties)
modified = False
if remove & props != set([]):
props = props - remove
modified = True
if append & props != append:
props = props | append
modified = True
if modified:
self.setproperties(props, None, None)
def getpermissive(self,
path):
return self._pp_.getpermissive(path)
def read_only(self):
"convenience method to freeze, hide and disable"
self._read(ro_remove, ro_append)
def read_write(self):
"convenience method to freeze, hide and disable"
self._read(rw_remove, rw_append)
def apply_requires(self, opt, path, setting_properties, index, debug):
def apply_requires(self,
opt,
path,
setting_properties,
index,
debug):
"""carries out the jit (just in time) requirements between options
a requirement is a tuple of this form that comes from the option's
@ -735,16 +413,16 @@ class Settings(object):
idx = None
try:
value = context.getattr(reqpath,
setting_properties,
force_permissive=True,
_setting_properties=setting_properties,
index=idx)
except PropertiesOptionError as err:
if not transitive:
if all_properties is None:
all_properties = []
for requires in opt.impl_getrequires():
for require in requires:
all_properties.append(require[1])
for requires_ in opt.impl_getrequires():
for require_ in requires_:
all_properties.append(require_[1])
if not set(err.proptype) - set(all_properties):
continue
properties = err.proptype
@ -794,8 +472,228 @@ class Settings(object):
break
return calc_properties
#____________________________________________________________
# set methods
def set_context_properties(self, properties):
self.setproperties(None, None, properties)
def setproperties(self,
opt,
path,
properties):
# force=False):
"""save properties for specified path
(never save properties if same has option properties)
"""
if self._getcontext().cfgimpl_get_meta() is not None:
raise ConfigError(_('cannot change global property with metaconfig'))
#if not force:
forbidden_properties = forbidden_set_properties & properties
if forbidden_properties:
raise ConfigError(_('cannot add those properties: {0}').format(
' '.join(forbidden_properties)))
if not isinstance(properties, frozenset):
raise TypeError(_('properties must be a frozenset'))
self._p_.setproperties(path,
properties)
#values too because of slave values could have a PropertiesOptionError has value
self._getcontext().cfgimpl_reset_cache(opt=opt,
path=path)
def set_context_permissive(self, permissive):
self.setpermissive(None, None, permissive)
def setpermissive(self,
opt,
path,
permissives):
"""
enables us to put the permissives in the storage
:param path: the option's path
:param type: str
:param opt: if an option object is set, the path is extracted.
it is better (faster) to set the path parameter
instead of passing a :class:`tiramisu.option.Option()` object.
"""
if not isinstance(permissives, frozenset):
raise TypeError(_('permissive must be a frozenset'))
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=opt,
path=path)
#____________________________________________________________
# reset methods
def reset(self, opt=None, _path=None, all_properties=False):
if all_properties and (_path or opt): # pragma: optional cover
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())
self._p_.delproperties(_path)
self._getcontext().cfgimpl_reset_cache(opt=opt,
path=_path)
#____________________________________________________________
# validate properties
def validate_properties(self,
opt_or_descr,
is_descr,
check_frozen,
path,
value=None,
force_permissive=False,
setting_properties=undefined,
self_properties=undefined,
index=None,
debug=False):
"""
validation upon the properties related to `opt_or_descr`
:param opt_or_descr: an option or an option description object
:param force_permissive: behaves as if the permissive property
was present
:param is_descr: we have to know if we are in an option description,
just because the mandatory property
doesn't exist here
:param check_frozen: in the validation process, an option is to be modified,
the behavior can be different
(typically with the `frozen` property)
"""
# opt properties
if self_properties is not undefined:
if not isinstance(self_properties, frozenset):
raise Exception('pouet')
properties = self_properties
else:
properties = self.getproperties(opt_or_descr,
path,
setting_properties=setting_properties,
index=index)
# calc properties
properties &= setting_properties
if not is_descr:
#mandatory
if 'mandatory' in properties and \
not self._getcontext().cfgimpl_get_values().isempty(opt_or_descr,
value,
index=index):
properties.remove('mandatory')
elif 'empty' in properties and \
'empty' in setting_properties and \
self._getcontext().cfgimpl_get_values().isempty(opt_or_descr,
value,
force_allow_empty_list=True,
index=index):
properties.add('mandatory')
# should return 'frozen' only when tried to modify a value
if check_frozen and 'everything_frozen' in setting_properties:
properties.add('frozen')
elif 'frozen' in properties and not check_frozen:
properties.remove('frozen')
if 'empty' in properties:
properties.remove('empty')
# remove permissive properties
if properties != frozenset() and (force_permissive is True or
'permissive' in setting_properties):
# remove global permissive if need
properties -= self.get_context_permissive()
# at this point an option should not remain in properties
if properties != frozenset():
props = list(properties)
datas = {'opt': opt_or_descr,
'path': path,
'setting_properties': setting_properties,
'index': index,
'debug': True}
if is_descr:
opt_type = 'optiondescription'
else:
opt_type = 'option'
if 'frozen' in properties:
raise PropertiesOptionError(_('cannot change the value for '
'option "{0}" this option is'
' frozen').format(
opt_or_descr.impl_getname()),
props,
self,
datas,
opt_type)
else:
if len(props) == 1:
prop_msg = _('property')
else:
prop_msg = _('properties')
raise PropertiesOptionError(_('cannot access to {0} "{1}" '
'because has {2} {3}'
'').format(opt_type,
opt_or_descr.impl_get_display_name(),
prop_msg,
display_list(props)),
props,
self,
datas,
opt_type)
#____________________________________________________________
# read only/read write
def _read(self,
remove,
append):
props = self._p_.getproperties(None,
default_properties)
modified = False
if remove & props != set([]):
props = props - remove
modified = True
if append & props != append:
props = props | append
modified = True
if modified:
self.set_context_properties(frozenset(props))
def read_only(self):
"convenience method to freeze, hide and disable"
self._read(ro_remove,
ro_append)
def read_write(self):
"convenience method to freeze, hide and disable"
self._read(rw_remove,
rw_append)
#____________________________________________________________
# get modified properties/permissives
def get_modified_properties(self):
return self._p_.get_modified_properties()
def get_modified_permissives(self):
return self._pp_.get_modified_permissives()
#____________________________________________________________
# default owner methods
def setowner(self,
owner):
":param owner: sets the default value for owner at the Config level"
if not isinstance(owner,
owners.Owner): # pragma: optional cover
raise TypeError(_("invalid generic owner {0}").format(str(owner)))
self._owner = owner
def getowner(self):
return self._owner

View file

@ -34,7 +34,7 @@ class Properties(Cache):
self._properties[path] = properties
def getproperties(self, path, default_properties):
return self._properties.get(path, set(default_properties))
return self._properties.get(path, frozenset(default_properties))
def reset_all_properties(self):
self._properties.clear()

View file

@ -195,7 +195,11 @@ class Values(Cache):
return 0
return max(self._values[1][idx]) + 1
def getowner(self, path, default, index=None, only_default=False,
def getowner(self,
path,
default,
index=None,
only_default=False,
with_value=False):
"""get owner for a path
return: owner object
@ -207,19 +211,28 @@ class Values(Cache):
else:
owner = default
else:
owner = self._getvalue(path, 3, index)
owner = self._getvalue(path,
3,
index)
if owner is undefined:
owner = default
else:
owner = self._getvalue(path, 3, index)
owner = self._getvalue(path,
3,
index)
if owner is undefined:
owner = default
if with_value:
return owner, self._getvalue(path, 2, index)
return owner, self._getvalue(path,
2,
index)
else:
return owner
def _getvalue(self, path, nb, index):
def _getvalue(self,
path,
nb,
index):
"""
_values == ((path1, path2), ((idx1_1, idx1_2), None), ((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2))
"""

File diff suppressed because it is too large Load diff