documentation on the requirements and docstring updates
This commit is contained in:
parent
1ddd88fc99
commit
747d994762
3 changed files with 78 additions and 17 deletions
|
@ -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
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue