documentation on the requirements and docstring updates

This commit is contained in:
gwen 2013-08-22 11:08:26 +02:00
parent 1ddd88fc99
commit 747d994762
3 changed files with 78 additions and 17 deletions

View file

@ -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 time, the specification of some links between options or groups allows
to carry out a dependencies calculation. For example, an option can ben 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 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 A requirement is a list of dictionnaries that have fairly this form::
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`...)::
stroption = StrOption('str', 'Test string option', default="abc", [{'option': a, 'expected': False, 'action': 'disabled', 'inverse': True,
requires=[('int', 1, 'hide')]) '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 Validation upon a whole configuration object
---------------------------------------------- ----------------------------------------------

View file

@ -926,6 +926,11 @@ class OptionDescription(BaseInformation):
def validate_requires_arg(requires, name): def validate_requires_arg(requires, name):
"""check malformed requirements """check malformed requirements
and tranform dict to internal tuple 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: if requires is None:
return None return None
@ -934,7 +939,6 @@ def validate_requires_arg(requires, name):
for require in requires: for require in requires:
if not type(require) == dict: if not type(require) == dict:
print require
raise ValueError(_("malformed requirements type for option:" raise ValueError(_("malformed requirements type for option:"
" {0}, must be a dict").format(name)) " {0}, must be a dict").format(name))
valid_keys = ('option', 'expected', 'action', 'inverse', 'transitive', valid_keys = ('option', 'expected', 'action', 'inverse', 'transitive',

View file

@ -242,7 +242,8 @@ class Settings(object):
props = self._p_.getproperties(path, default_properties) props = self._p_.getproperties(path, default_properties)
else: else:
if path is None: 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 ntime = None
if self._p_.hascache('property', path): if self._p_.hascache('property', path):
ntime = time() ntime = time()
@ -287,13 +288,15 @@ class Settings(object):
validation upon the properties related to `opt_or_descr` validation upon the properties related to `opt_or_descr`
:param opt_or_descr: an option or an option description object :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, :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, :param is_write: in the validation process, an option is to be modified,
the behavior can be different (typically with the `frozen` the behavior can be different
property) (typically with the `frozen` property)
""" """
# opt properties # opt properties
properties = copy(self._getproperties(opt_or_descr, path)) properties = copy(self._getproperties(opt_or_descr, path))
@ -374,12 +377,55 @@ class Settings(object):
self._p_.reset_all_cache('property') self._p_.reset_all_cache('property')
def apply_requires(self, opt, path): 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: if opt._requires is None:
return return
# filters the callbacks # 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: for requires in opt._requires:
matches = False matches = False
for require in requires: for require in requires:
@ -392,7 +438,8 @@ class Settings(object):
" '{0}' with requirement on: " " '{0}' with requirement on: "
"'{1}'").format(path, reqpath)) "'{1}'").format(path, reqpath))
try: try:
value = self.context._getattr(reqpath, force_permissive=True) value = self.context._getattr(reqpath,
force_permissive=True)
except PropertiesOptionError, err: except PropertiesOptionError, err:
if not transitive: if not transitive:
continue continue