diff --git a/doc/consistency.txt b/doc/consistency.txt index c5014b5..47561ff 100644 --- a/doc/consistency.txt +++ b/doc/consistency.txt @@ -50,17 +50,27 @@ Configuration options can specify requirements as parameters at the init time, the specification of some links between options or groups allows to carry out a dependencies calculation. For example, an option can ben hidden if another option has been set with some expected value. This is -just an example, because the possibilities are hudge. +just an example, the possibilities are hudge. -A requirement is specified using a list of triplets. The first element -of the triplet gives the path of the option that is required, the second -element is the value wich is expected to trigger the callback, and the -third one is the callback's action name (`hide`, `show`...):: +A requirement is a list of dictionnaries that have fairly this form:: - stroption = StrOption('str', 'Test string option', default="abc", - requires=[('int', 1, 'hide')]) + [{'option': a, 'expected': False, 'action': 'disabled', 'inverse': True, + 'transitive':True, 'same_action': True}] -Requirements are validated in :class:`setting.Setting`. +Actually a transformation is made to this dictionnary during the validation of +this requires at the :class:`~option.Option()`'s init. The dictionnairy becomes +a tuple, wich is passed to the :meth:`~setting.Settings.apply_requires()` +method. Take a look at the code to fully understand the exact meaning of the +requirements: + +.. automethod:: tiramisu.setting.Settings.apply_requires + + +The path of the option is required, the second element is the value wich is +expected to trigger the callback, it is required too, and the third one is the +callback's action name (`hide`, `show`...), wich is a +:class:`~setting.Property()`. Requirements are validated in +:class:`setting.Setting`. Validation upon a whole configuration object ---------------------------------------------- diff --git a/tiramisu/option.py b/tiramisu/option.py index 691498e..d95998a 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -926,6 +926,11 @@ class OptionDescription(BaseInformation): def validate_requires_arg(requires, name): """check malformed requirements and tranform dict to internal tuple + + :param requires: have a look at the + :meth:`tiramisu.setting.Settings.apply_requires` method to + know more about + the description of the requires dictionnary """ if requires is None: return None @@ -934,7 +939,6 @@ def validate_requires_arg(requires, name): for require in requires: if not type(require) == dict: - print require raise ValueError(_("malformed requirements type for option:" " {0}, must be a dict").format(name)) valid_keys = ('option', 'expected', 'action', 'inverse', 'transitive', diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 7417662..13176de 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -242,7 +242,8 @@ class Settings(object): props = self._p_.getproperties(path, default_properties) else: if path is None: - raise ValueError(_('if opt is not None, path should not be None in _getproperties')) + raise ValueError(_('if opt is not None, path should not be' + ' None in _getproperties')) ntime = None if self._p_.hascache('property', path): ntime = time() @@ -287,13 +288,15 @@ class Settings(object): 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 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 there + just because the mandatory property + doesn't exist here :param is_write: in the validation process, an option is to be modified, - the behavior can be different (typically with the `frozen` - property) + the behavior can be different + (typically with the `frozen` property) """ # opt properties properties = copy(self._getproperties(opt_or_descr, path)) @@ -374,12 +377,55 @@ class Settings(object): self._p_.reset_all_cache('property') def apply_requires(self, opt, path): - "carries out the jit (just in time requirements between options" + """carries out the jit (just in time) requirements between options + + a requirement is a tuple of this form that comes from the option's + 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 + 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 + 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 + 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 + exception :exc:`~error.RequirementError` is raised. + + 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 # filters the callbacks - setting = Property(self, self._getproperties(opt, path, False), opt, path=path) + setting = Property(self, + self._getproperties(opt, path, False), + opt, path=path) for requires in opt._requires: matches = False for require in requires: @@ -392,7 +438,8 @@ class Settings(object): " '{0}' with requirement on: " "'{1}'").format(path, reqpath)) try: - value = self.context._getattr(reqpath, force_permissive=True) + value = self.context._getattr(reqpath, + force_permissive=True) except PropertiesOptionError, err: if not transitive: continue