never same calculated properties has properties (only in cache)
This commit is contained in:
parent
3a6296f7e0
commit
04aa4e6bf1
|
@ -429,3 +429,13 @@ def test_requires_multi_disabled_inverse_2():
|
|||
except PropertiesOptionError, err:
|
||||
props = err.proptype
|
||||
assert props == ['disabled']
|
||||
|
||||
|
||||
def test_requires_requirement_append():
|
||||
a = BoolOption('activate_service', '', True)
|
||||
b = IPOption('ip_address_service', '',
|
||||
requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
|
||||
od = OptionDescription('service', '', [a, b])
|
||||
c = Config(od)
|
||||
c.read_write()
|
||||
raises(ValueError, 'c.cfgimpl_get_settings()[b].append("disabled")')
|
||||
|
|
|
@ -97,10 +97,9 @@ class Option(BaseInformation):
|
|||
Reminder: an Option object is **not** a container for the value
|
||||
"""
|
||||
__slots__ = ('_name', '_requires', '_multi', '_validator',
|
||||
'_default_multi',
|
||||
'_default',
|
||||
'_properties', '_callback', '_multitype',
|
||||
'_master_slaves', '_consistencies', '_empty')
|
||||
'_default_multi', '_default', '_properties', '_callback',
|
||||
'_multitype', '_master_slaves', '_consistencies', '_empty',
|
||||
'_calc_properties')
|
||||
_empty = ''
|
||||
|
||||
def __init__(self, name, doc, default=None, default_multi=None,
|
||||
|
@ -130,8 +129,8 @@ class Option(BaseInformation):
|
|||
self._name = name
|
||||
self._impl_informations = {}
|
||||
self.impl_set_information('doc', doc)
|
||||
requires = validate_requires_arg(requires, self._name)
|
||||
self._requires = requires
|
||||
self._calc_properties, self._requires = validate_requires_arg(
|
||||
requires, self._name)
|
||||
self._multi = multi
|
||||
self._consistencies = None
|
||||
if validator is not None:
|
||||
|
@ -714,7 +713,8 @@ class OptionDescription(BaseInformation):
|
|||
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
|
||||
"""
|
||||
__slots__ = ('_name', '_requires', '_cache_paths', '_group_type',
|
||||
'_properties', '_children', '_consistencies')
|
||||
'_properties', '_children', '_consistencies',
|
||||
'_calc_properties')
|
||||
|
||||
def __init__(self, name, doc, children, requires=None, properties=None):
|
||||
"""
|
||||
|
@ -738,8 +738,7 @@ class OptionDescription(BaseInformation):
|
|||
'{0}').format(child))
|
||||
old = child
|
||||
self._children = (tuple(child_names), tuple(children))
|
||||
requires = validate_requires_arg(requires, self._name)
|
||||
self._requires = requires
|
||||
self._calc_properties, self._requires = validate_requires_arg(requires, self._name)
|
||||
self._cache_paths = None
|
||||
self._consistencies = None
|
||||
if properties is None:
|
||||
|
@ -933,7 +932,7 @@ def validate_requires_arg(requires, name):
|
|||
the description of the requires dictionnary
|
||||
"""
|
||||
if requires is None:
|
||||
return None
|
||||
return None, None
|
||||
ret_requires = {}
|
||||
config_action = {}
|
||||
|
||||
|
@ -999,7 +998,6 @@ def validate_requires_arg(requires, name):
|
|||
inverse, transitive, same_action)
|
||||
else:
|
||||
ret_requires[action][option][1].append(expected)
|
||||
|
||||
ret = []
|
||||
for opt_requires in ret_requires.values():
|
||||
ret_action = []
|
||||
|
@ -1011,4 +1009,4 @@ def validate_requires_arg(requires, name):
|
|||
require[5])
|
||||
ret_action.append(req)
|
||||
ret.append(tuple(ret_action))
|
||||
return tuple(ret)
|
||||
return tuple(config_action.keys()), tuple(ret)
|
||||
|
|
|
@ -161,6 +161,11 @@ class Property(object):
|
|||
self._properties = prop
|
||||
|
||||
def append(self, propname):
|
||||
if self._opt is not None and self._opt._calc_properties is not None \
|
||||
and propname in self._opt._calc_properties:
|
||||
raise ValueError(_('cannot append {0} property for option {1}: '
|
||||
'this property is calculated').format(
|
||||
propname, self._opt._name))
|
||||
self._properties.add(propname)
|
||||
self._setting._setproperties(self._properties, self._opt, self._path)
|
||||
|
||||
|
@ -250,9 +255,9 @@ class Settings(object):
|
|||
is_cached, props = self._p_.getcache('property', path, ntime)
|
||||
if is_cached:
|
||||
return props
|
||||
if is_apply_req:
|
||||
self.apply_requires(opt, path)
|
||||
props = self._p_.getproperties(path, opt._properties)
|
||||
if is_apply_req:
|
||||
props |= self.apply_requires(opt, path)
|
||||
if 'expire' in self:
|
||||
if ntime is None:
|
||||
ntime = time()
|
||||
|
@ -261,11 +266,16 @@ class Settings(object):
|
|||
|
||||
def append(self, propname):
|
||||
"puts property propname in the Config's properties attribute"
|
||||
Property(self, self._getproperties()).append(propname)
|
||||
props = self._p_.getproperties(None, default_properties)
|
||||
props.add(propname)
|
||||
self._setproperties(props, None, None)
|
||||
|
||||
def remove(self, propname):
|
||||
"deletes property propname in the Config's properties attribute"
|
||||
Property(self, self._getproperties()).remove(propname)
|
||||
props = self._p_.getproperties(None, default_properties)
|
||||
if propname in props:
|
||||
props.remove(propname)
|
||||
self._setproperties(props, None, None)
|
||||
|
||||
def _setproperties(self, properties, opt, path):
|
||||
"""save properties for specified opt
|
||||
|
@ -274,6 +284,8 @@ class Settings(object):
|
|||
if opt is None:
|
||||
self._p_.setproperties(None, properties)
|
||||
else:
|
||||
if opt._calc_properties is not None:
|
||||
properties -= opt._calc_properties
|
||||
if set(opt._properties) == properties:
|
||||
self._p_.reset_properties(path)
|
||||
else:
|
||||
|
@ -378,56 +390,53 @@ class Settings(object):
|
|||
|
||||
def apply_requires(self, opt, path):
|
||||
"""carries out the jit (just in time) requirements between options
|
||||
|
||||
a requirement is a tuple of this form that comes from the option's
|
||||
|
||||
a requirement is a tuple of this form that comes from the option's
|
||||
requirements validation::
|
||||
|
||||
(option, expected, action, inverse, transitive, same_action)
|
||||
|
||||
let's have a look at all the tuple's items:
|
||||
|
||||
|
||||
- **option** is the target option's name or path
|
||||
|
||||
|
||||
- **expected** is the target option's value that is going to trigger an action
|
||||
|
||||
- **action** is the (property) action to be accomplished if the target option
|
||||
|
||||
- **action** is the (property) action to be accomplished if the target option
|
||||
happens to have the expected value
|
||||
|
||||
- if **inverse** is `True` and if the target option's value does not
|
||||
apply, then the property action must be removed from the option's
|
||||
|
||||
- if **inverse** is `True` and if the target option's value does not
|
||||
apply, then the property action must be removed from the option's
|
||||
properties list (wich means that the property is inverted)
|
||||
|
||||
- **transitive**: but what happens if the target option cannot be
|
||||
accessed ? We don't kown the target option's value. Actually if some
|
||||
property in the target option is not present in the permissive, the
|
||||
target option's value cannot be accessed. In this case, the
|
||||
**action** have to be applied to the option. (the **action** property
|
||||
|
||||
- **transitive**: but what happens if the target option cannot be
|
||||
accessed ? We don't kown the target option's value. Actually if some
|
||||
property in the target option is not present in the permissive, the
|
||||
target option's value cannot be accessed. In this case, the
|
||||
**action** have to be applied to the option. (the **action** property
|
||||
is then added to the option).
|
||||
|
||||
- **same_action**: actually, if **same_action** is `True`, the
|
||||
transitivity is not accomplished. The transitivity is accomplished
|
||||
only if the target option **has the same property** that the demanded
|
||||
action. If the target option's value is not accessible because of
|
||||
another reason, because of a property of another type, then an
|
||||
|
||||
- **same_action**: actually, if **same_action** is `True`, the
|
||||
transitivity is not accomplished. The transitivity is accomplished
|
||||
only if the target option **has the same property** that the demanded
|
||||
action. If the target option's value is not accessible because of
|
||||
another reason, because of a property of another type, then an
|
||||
exception :exc:`~error.RequirementError` is raised.
|
||||
|
||||
And at last, if no target option matches the expected values, the
|
||||
And at last, if no target option matches the expected values, the
|
||||
action must be removed from the option's properties list.
|
||||
|
||||
|
||||
:param opt: the option on wich the requirement occurs
|
||||
:type opt: `option.Option()`
|
||||
:param path: the option's path in the config
|
||||
:type path: str
|
||||
"""
|
||||
if opt._requires is None:
|
||||
return
|
||||
return frozenset()
|
||||
|
||||
# filters the callbacks
|
||||
setting = Property(self,
|
||||
self._getproperties(opt, path, False),
|
||||
opt, path=path)
|
||||
calc_properties = set()
|
||||
for requires in opt._requires:
|
||||
matches = False
|
||||
for require in requires:
|
||||
option, expected, action, inverse, \
|
||||
transitive, same_action = require
|
||||
|
@ -460,13 +469,10 @@ class Settings(object):
|
|||
if (not inverse and
|
||||
value in expected or
|
||||
inverse and value not in expected):
|
||||
matches = True
|
||||
setting.append(action)
|
||||
calc_properties.add(action)
|
||||
# the calculation cannot be carried out
|
||||
break
|
||||
# no requirement has been triggered, then just reverse the action
|
||||
if not matches:
|
||||
setting.remove(action)
|
||||
return calc_properties
|
||||
|
||||
def _get_opt_path(self, opt):
|
||||
return self.context.cfgimpl_get_description().impl_get_path_by_opt(opt)
|
||||
|
|
Loading…
Reference in New Issue