2012-07-13 09:40:48 +02:00
|
|
|
.. default-role:: literal
|
|
|
|
|
2012-11-20 17:14:58 +01:00
|
|
|
===============================
|
2013-08-23 11:42:22 +02:00
|
|
|
Options handling basics
|
2012-11-20 17:14:58 +01:00
|
|
|
===============================
|
2012-10-05 16:00:07 +02:00
|
|
|
|
2013-05-21 18:42:56 +02:00
|
|
|
Tiramisu is made of almost three main objects :
|
2013-05-21 11:37:39 +02:00
|
|
|
|
|
|
|
- :class:`tiramisu.config.Config` witch is the whole configuration entry point
|
2013-05-21 18:42:56 +02:00
|
|
|
- :class:`tiramisu.option.Option` stands for the option types
|
|
|
|
- :class:`tiramisu.option.OptionDescription` is the shema, the option's structure
|
2012-07-13 09:40:48 +02:00
|
|
|
|
2013-08-23 11:42:22 +02:00
|
|
|
Accessing the `Option`'s
|
|
|
|
-------------------------
|
2012-07-13 09:40:48 +02:00
|
|
|
|
|
|
|
The `Config` object attribute access notation stands for the value of the
|
|
|
|
configuration's `Option`. That is, the `Config`'s object attribute is the name
|
|
|
|
of the `Option`, and the value is the value accessed by the `__getattr__`
|
2012-10-05 16:00:07 +02:00
|
|
|
attribute access mechanism.
|
2012-07-13 09:40:48 +02:00
|
|
|
|
|
|
|
If the attribute of the `Config` called by `__getattr__` has not been set before
|
|
|
|
(by the classic `__setattr__` mechanism), the default value of the `Option`
|
|
|
|
object is returned, and if no `Option` has been declared in the
|
|
|
|
`OptionDescription` (that is the schema of the configuration), an
|
|
|
|
`AttributeError` is raised.
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
>>> gcdummy = BoolOption('dummy', 'dummy', default=False)
|
|
|
|
>>> gcdummy._name
|
|
|
|
'dummy'
|
|
|
|
>>> gcdummy.getdefault()
|
|
|
|
False
|
|
|
|
>>> descr = OptionDescription('tiramisu', '', [gcdummy])
|
|
|
|
>>> cfg = Config(descr)
|
|
|
|
>>> cfg.dummy
|
|
|
|
False
|
|
|
|
>>> cfg.dummy = True
|
|
|
|
>>> cfg.dummy
|
|
|
|
True
|
|
|
|
>>> cfg.idontexist
|
|
|
|
AttributeError: 'OptionDescription' object has no attribute 'idontexist'
|
|
|
|
|
2013-08-23 11:42:22 +02:00
|
|
|
The `Option` objects (in this case the `BoolOption`), are organized into a tree
|
|
|
|
into nested `OptionDescription` objects. Every option has a name, as does every
|
|
|
|
option group. The parts of the full name of the option are separated by dots:
|
|
|
|
e.g. ``cfg.optgroup.optname``.
|
2012-07-13 09:40:48 +02:00
|
|
|
|
2013-05-17 12:11:14 +02:00
|
|
|
Let's make the protocol of accessing a config's attribute explicit
|
2013-05-21 11:37:39 +02:00
|
|
|
(because explicit is better than implicit):
|
2012-07-13 09:40:48 +02:00
|
|
|
|
|
|
|
1. If the option has not been declared, an `AttributeError` is raised,
|
|
|
|
|
|
|
|
2. If an option is declared, but neither a value nor a default value has
|
|
|
|
been set, the returned value is `None`,
|
|
|
|
|
|
|
|
3. If an option is declared and a default value has been set, but no value
|
|
|
|
has been set, the returned value is the default value of the option,
|
|
|
|
|
|
|
|
4. If an option is declared, and a value has been set, the returned value is
|
|
|
|
the value of the option.
|
|
|
|
|
2013-08-23 11:42:22 +02:00
|
|
|
But there are special exceptions. We will see later on that an option can be a
|
|
|
|
:term:`mandatory option`. A mandatory option is an option that must have a defined value.
|
|
|
|
If no value have been set yet, the value is `None`.
|
|
|
|
When the option is called to retrieve a value, an exception is raised.
|
2013-08-21 17:21:09 +02:00
|
|
|
|
2012-08-13 11:12:08 +02:00
|
|
|
What if a value has been set and `None` is to be returned again ? Don't
|
2012-11-20 17:14:58 +01:00
|
|
|
worry, an option value can be "reseted" with the help of the `option.Option.reset()`
|
2012-11-14 11:30:11 +01:00
|
|
|
method.
|
2012-08-13 11:12:08 +02:00
|
|
|
|
2012-07-13 09:40:48 +02:00
|
|
|
If you know the path:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
>>> config.gc.dummy
|
|
|
|
False
|
|
|
|
|
|
|
|
Setting the values of the options
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
An important part of the setting of the configuration consists of setting the
|
|
|
|
values of the configuration options. There are different ways of setting values,
|
2012-10-05 16:00:07 +02:00
|
|
|
the first one is of course the `__setattr__` method
|
2012-07-13 09:40:48 +02:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
cfg.name = value
|
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
And if you wanna come back to a default value, use the builtin `del()` function::
|
2013-05-21 18:42:56 +02:00
|
|
|
|
|
|
|
del(cfg.name)
|
|
|
|
|
2013-05-17 12:11:14 +02:00
|
|
|
.. module:: tiramisu.config
|
|
|
|
|
2013-08-22 12:17:10 +02:00
|
|
|
.. _`tree`:
|
|
|
|
|
|
|
|
The handling of options
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2013-05-17 12:11:14 +02:00
|
|
|
The handling of options is split into two parts: the description of
|
|
|
|
which options are available, what their possible values and defaults are
|
|
|
|
and how they are organized into a tree. A specific choice of options is
|
|
|
|
bundled into a configuration object which has a reference to its option
|
|
|
|
description (and therefore makes sure that the configuration values
|
|
|
|
adhere to the option description).
|
|
|
|
|
2013-08-23 11:42:22 +02:00
|
|
|
|
|
|
|
Common manipulations
|
|
|
|
------------------------
|
|
|
|
|
|
|
|
Let's perform some common manipulation on some options:
|
|
|
|
|
|
|
|
>>> from tiramisu.config import Config
|
|
|
|
>>> from tiramisu.option import UnicodeOption, OptionDescription
|
|
|
|
>>>
|
|
|
|
>>> var1 = UnicodeOption('var1', 'first variable')
|
|
|
|
>>> var2 = UnicodeOption('var2', '', u'value')
|
|
|
|
>>>
|
|
|
|
>>> od1 = OptionDescription('od1', 'first OD', [var1, var2])
|
|
|
|
>>> rootod = OptionDescription('rootod', '', [od1])
|
|
|
|
|
|
|
|
let's set somme access rules on the main namespace
|
|
|
|
|
|
|
|
>>> c = Config(rootod)
|
|
|
|
>>> c.read_write()
|
|
|
|
|
|
|
|
let's travel the namespaces
|
|
|
|
|
|
|
|
>>> print c
|
|
|
|
[od1]
|
|
|
|
>>> print c.od1
|
|
|
|
var1 = None
|
|
|
|
var2 = value
|
|
|
|
>>> print c.od1.var1
|
|
|
|
None
|
|
|
|
>>> print c.od1.var2
|
|
|
|
value
|
|
|
|
|
|
|
|
let's modify a value (careful to the value's type...)
|
|
|
|
|
|
|
|
>>> c.od1.var1 = 'value'
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
ValueError: invalid value value for option var1
|
|
|
|
>>> c.od1.var1 = u'value'
|
|
|
|
>>> print c.od1.var1
|
|
|
|
value
|
|
|
|
>>> c.od1.var2 = u'value2'
|
|
|
|
>>> print c.od1.var2
|
|
|
|
value2
|
|
|
|
|
|
|
|
let's come back to the default value
|
|
|
|
|
|
|
|
>>> del(c.od1.var2)
|
|
|
|
>>> print c.od1.var2
|
|
|
|
value
|
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
The value is saved in a :class:`~tiramisu.value.Value` object. It is on this
|
|
|
|
object that we have to trigger the `reset`, wich take the option itself
|
|
|
|
(`var2`) as a parameter.
|
2013-08-23 11:42:22 +02:00
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
On the other side, in the `read_only` mode, it is not possible to modify the value::
|
2013-08-23 11:42:22 +02:00
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
>>> c.read_only()
|
|
|
|
>>> c.od1.var2 = u'value2'
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError:
|
|
|
|
cannot change the value to var2
|
|
|
|
for option ['frozen'] this option is frozen
|
|
|
|
|
|
|
|
let's retrieve the option `var1` description
|
2013-08-23 11:42:22 +02:00
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
>>> var1.impl_get_information('doc')
|
|
|
|
'first variable'
|
2013-08-23 11:42:22 +02:00
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
And if the option has been lost, it is possible to retrieve it again:
|
|
|
|
|
|
|
|
>>> c.unwrap_from_path('od1.var1').impl_get_information('doc')
|
|
|
|
'first variable'
|
|
|
|
|
|
|
|
Searching for an option
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
In an application, knowing the path of an option is not always feasible.
|
|
|
|
That's why a tree of options can easily be searched. First, let's build such a tree::
|
|
|
|
|
|
|
|
>>> var1 = UnicodeOption('var1', '')
|
|
|
|
>>> var2 = UnicodeOption('var2', '')
|
|
|
|
>>> var3 = UnicodeOption('var3', '')
|
|
|
|
>>> od1 = OptionDescription('od1', '', [var1, var2, var3])
|
|
|
|
>>> var4 = UnicodeOption('var4', '')
|
|
|
|
>>> var5 = UnicodeOption('var5', '')
|
|
|
|
>>> var6 = UnicodeOption('var6', '')
|
|
|
|
>>> var7 = UnicodeOption('var1', '', u'value')
|
|
|
|
>>> od2 = OptionDescription('od2', '', [var4, var5, var6, var7])
|
|
|
|
>>> rootod = OptionDescription('rootod', '', [od1, od2])
|
|
|
|
>>> c = Config(rootod)
|
|
|
|
>>> c.read_write()
|
|
|
|
|
|
|
|
Second, let's find an option by his name::
|
|
|
|
|
|
|
|
>>> print c.find(byname='var1')
|
|
|
|
[<tiramisu.option.UnicodeOption object at 0x7ff1bf7d6ef0>,
|
|
|
|
<tiramisu.option.UnicodeOption object at 0x7ff1b90c7290>]
|
|
|
|
|
|
|
|
If the option name is unique, the search can be stopped once one matched option
|
|
|
|
has been found:
|
|
|
|
|
|
|
|
>>> print c.find_first(byname='var1')
|
|
|
|
<tiramisu.option.UnicodeOption object at 0x7ff1bf7d6ef0>
|
|
|
|
|
|
|
|
Instead of the option's object, the value or path can be retrieved:
|
|
|
|
|
|
|
|
>>> print c.find(byname='var1', type_='value')
|
|
|
|
[None, u'value']
|
|
|
|
>>> print c.find(byname='var1', type_='path')
|
|
|
|
['od1.var1', 'od2.var1']
|
|
|
|
|
|
|
|
Finaly, a search can be performed on the values, the type or even a combination
|
|
|
|
of all these criteria:
|
|
|
|
|
|
|
|
|
|
|
|
>>> print c.find(byvalue=u'value', type_='path')
|
|
|
|
['od2.var1']
|
|
|
|
>>> print c.find(bytype=UnicodeOption, type_='path')
|
|
|
|
['od1.var1', 'od1.var2', 'od1.var3', 'od2.var4', 'od2.var5', 'od2.var6', 'od2.var1']
|
|
|
|
>>> print c.find(byvalue=u'value', byname='var1', bytype=UnicodeOption, type_='path')
|
|
|
|
['od2.var1']
|
|
|
|
|
|
|
|
The search can be performed in a subtree:
|
|
|
|
|
|
|
|
>>> print c.od1.find(byname='var1', type_='path')
|
|
|
|
['od1.var1']
|
|
|
|
|
|
|
|
In a root tree or in a subtree, all option can be retrieved in a dict container:
|
|
|
|
|
|
|
|
>>> print c.make_dict()
|
|
|
|
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value',
|
|
|
|
'od1.var1': None, 'od1.var3': None, 'od1.var2': None}
|
|
|
|
|
|
|
|
If the organisation in a tree is not important,
|
|
|
|
:meth:`~config.SubConfig.make_dict()` results can be flattened
|
|
|
|
|
|
|
|
>>> print c.make_dict(flatten=True)
|
|
|
|
{'var5': None, 'var4': None, 'var6': None, 'var1': u'value', 'var3': None,
|
|
|
|
'var2': None}
|
|
|
|
|
|
|
|
.. note:: carefull with this `flatten` parameter, here we have just lost
|
|
|
|
two options named `var1`
|
|
|
|
|
|
|
|
One can export only interesting parts of a tree of options into a dict, for
|
|
|
|
example the options that are in the same group that a given `var1` option::
|
|
|
|
|
|
|
|
>>> print c.make_dict(withoption='var1')
|
|
|
|
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value',
|
|
|
|
'od1.var1': None, 'od1.var3': None, 'od1.var2': None}
|
|
|
|
>>> print c.make_dict(withoption='var1', withvalue=u'value')
|
|
|
|
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value'}
|
|
|
|
|
|
|
|
and of course, :meth:`~config.SubConfig.make_dict()` can be called in a subtree:
|
|
|
|
|
|
|
|
>>> print c.od1.make_dict(withoption='var1')
|
|
|
|
{'var1': None, 'var3': None, 'var2': None}
|
|
|
|
|
|
|
|
the owners
|
|
|
|
~~~~~~~~~~~
|
|
|
|
|
|
|
|
When a value is set on an option, an owner is set too, that's why one can know
|
|
|
|
at any time if a value is a default value or not. Let's create a tree::
|
|
|
|
|
|
|
|
>>> var1 = UnicodeOption('var1', '', u'oui')
|
|
|
|
>>> od1 = OptionDescription('od1', '', [var1])
|
|
|
|
>>> rootod = OptionDescription('rootod', '', [od1])
|
|
|
|
>>> c = Config(rootod)
|
|
|
|
>>> c.read_write()
|
|
|
|
|
|
|
|
Then let's retrieve the owner associated to an option::
|
|
|
|
|
|
|
|
>>> print c.getowner('var1')
|
|
|
|
default
|
|
|
|
>>> c.od1.var1 = u'non'
|
|
|
|
>>> print c.getowner('var1')
|
|
|
|
user
|
|
|
|
>>> del(c.var1)
|
|
|
|
>>> print c.getowner('var1')
|
|
|
|
default
|
|
|
|
|
|
|
|
the properties
|
|
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
A property is an information on an option's state.
|
|
|
|
Let's create options with properties::
|
|
|
|
|
|
|
|
>>> var1 = UnicodeOption('var1', '', u'value', properties=('hidden',))
|
|
|
|
>>> var2 = UnicodeOption('var2', '', properties=('mandatory',))
|
|
|
|
>>> var3 = UnicodeOption('var3', '', u'value', properties=('frozen', 'inconnu'))
|
|
|
|
>>> var4 = UnicodeOption('var4', '', u'value')
|
|
|
|
>>> od1 = OptionDescription('od1', '', [var1, var2, var3])
|
|
|
|
>>> od2 = OptionDescription('od2', '', [var4], properties=('hidden',))
|
|
|
|
>>> rootod = OptionDescription('rootod', '', [od1, od2])
|
|
|
|
>>> c = Config(rootod)
|
|
|
|
>>> c.read_write()
|
|
|
|
|
|
|
|
A hidden value is a value that cannot be accessed in read/write mode. This
|
|
|
|
option cannot be modified any more. Let's try to access to an option's value
|
|
|
|
with a hidden option::
|
|
|
|
|
|
|
|
>>> print c.od1.var1
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named: var1
|
|
|
|
with properties ['hidden']
|
|
|
|
>>> c.read_only()
|
|
|
|
>>> print c.od1.var1
|
|
|
|
value
|
|
|
|
|
|
|
|
A mandatory option is an option with a value that shall not be `None`. The
|
|
|
|
value has to be defined. Accessing to such an option is easy in read/write
|
|
|
|
mode. But in read only mode, an error is raised if no value has been defined::
|
|
|
|
|
|
|
|
>>> c.read_write()
|
|
|
|
>>> print c.od1.var2
|
|
|
|
None
|
|
|
|
>>> c.read_only()
|
|
|
|
>>> print c.od1.var2
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named: var2
|
|
|
|
with properties ['mandatory']
|
|
|
|
>>> c.read_write()
|
|
|
|
>>> c.od1.var2 = u'value'
|
|
|
|
>>> c.read_only()
|
|
|
|
>>> print c.od1.var2
|
|
|
|
value
|
|
|
|
|
|
|
|
A frozen option, is an option that cannot be modified by a user.
|
|
|
|
Let's try to modify a frozen option::
|
|
|
|
|
|
|
|
>>> c.read_write()
|
|
|
|
>>> print c.od1.var3
|
|
|
|
value
|
|
|
|
>>> c.od1.var3 = u'value2'
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: cannot change the value for option var3 this option is frozen
|
|
|
|
>>> c.read_only()
|
|
|
|
>>> print c.od1.var3
|
|
|
|
value
|
|
|
|
|
|
|
|
Tiramisu allows us to use user defined properties. Let's define and use one in
|
|
|
|
read/write or read only mode::
|
|
|
|
|
|
|
|
>>> c.cfgimpl_get_settings().append('inconnu')
|
|
|
|
>>> print c.od1.var3
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
|
|
|
var3 with properties ['inconnu']
|
|
|
|
>>> c.cfgimpl_get_settings().remove('inconnu')
|
|
|
|
>>> print c.od1.var3
|
|
|
|
value
|
|
|
|
|
2013-08-27 15:54:10 +02:00
|
|
|
Properties can also be defined on an option group, (that is, on an
|
|
|
|
:term:`option description`), let's hide a group and try to access to it::
|
2013-08-26 17:14:14 +02:00
|
|
|
|
|
|
|
>>> c.read_write()
|
|
|
|
>>> print c.od2.var4
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named: od2
|
|
|
|
with properties ['hidden']
|
|
|
|
>>> c.read_only()
|
|
|
|
>>> print c.od2.var4
|
|
|
|
value
|
|
|
|
|
|
|
|
Furthermore, let's retrieve the properties, delete and add the `hidden` property::
|
|
|
|
|
|
|
|
>>> c.read_write()
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1]
|
|
|
|
['hidden']
|
|
|
|
>>> print c.od1.var1
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
|
|
|
var1 with properties ['hidden']
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1].remove('hidden')
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1]
|
|
|
|
[]
|
|
|
|
>>> print c.od1.var1
|
|
|
|
value
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1].append('hidden')
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1]
|
|
|
|
['hidden']
|
|
|
|
>>> print c.od1.var1
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
|
|
|
var1 with properties ['hidden']
|
|
|
|
|
|
|
|
The requirements
|
|
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Let's create an option wich has requirements::
|
|
|
|
|
2013-08-27 15:54:10 +02:00
|
|
|
>>> from tiramisu.option import *
|
|
|
|
>>> from tiramisu.config import *
|
2013-08-26 17:14:14 +02:00
|
|
|
>>> var2 = UnicodeOption('var2', '', u'oui')
|
2013-08-27 15:54:10 +02:00
|
|
|
>>> var1 = UnicodeOption('var1', '', u'value', requires=[{'option':var2, 'expected':u'non', 'action':'hidden'}])
|
|
|
|
>>> var3 = UnicodeOption('var3', '', u'value', requires=[{'option':var2, 'expected':u'non', 'action':'hidden'}, {'option':var2, 'expected':u'non', 'action':'disabled'}])
|
2013-08-26 17:14:14 +02:00
|
|
|
>>> var4 = UnicodeOption('var4', '', u'oui')
|
|
|
|
>>> od1 = OptionDescription('od1', '', [var1, var2, var3])
|
2013-08-27 15:54:10 +02:00
|
|
|
>>> od2 = OptionDescription('od2', '', [var4], requires=[{'option':od1.var2, 'expected':u'oui', 'action':'hidden', 'inverse':True}])
|
2013-08-26 17:14:14 +02:00
|
|
|
>>> rootod = OptionDescription('rootod', '', [od1, od2])
|
|
|
|
>>> c = Config(rootod)
|
2013-08-27 15:54:10 +02:00
|
|
|
>>> c.read_write()
|
2013-08-26 17:14:14 +02:00
|
|
|
|
2013-08-27 15:54:10 +02:00
|
|
|
The requirement here is the dict `{'option':var2, 'expected':u'non',
|
|
|
|
'action':'hidden'}` wich means that is the option `'od1.var2'` is set to
|
|
|
|
`'non'`, the option `'od1.var1'` is gonna be hidden. On the other hand, if the
|
|
|
|
option `'od1.var2'` is different from `'non'`, the option `'od1.var1'` is not
|
|
|
|
hidden any more::
|
2013-08-26 17:14:14 +02:00
|
|
|
|
|
|
|
>>> print c.cfgimpl_get_settings()[rootod.od1.var1]
|
|
|
|
[]
|
|
|
|
>>> print c.od1.var1
|
|
|
|
value
|
|
|
|
>>> print c.od1.var2
|
|
|
|
oui
|
|
|
|
>>> c.od1.var2 = u'non'
|
|
|
|
>>> print c.cfgimpl_get_settings()[rootod.od1.var1]
|
|
|
|
['hidden']
|
|
|
|
>>> print c.od1.var1
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
|
|
|
var1 with properties ['hidden']
|
|
|
|
>>> c.od1.var2 = u'oui'
|
|
|
|
>>> print c.cfgimpl_get_settings()[rootod.od1.var1]
|
|
|
|
[]
|
|
|
|
>>> print c.od1.var1
|
|
|
|
value
|
|
|
|
|
2013-08-27 15:54:10 +02:00
|
|
|
The requirement on `od2` is `{'option':od1.var2, 'expected':u'oui',
|
|
|
|
'action':'hidden', 'inverse':True}`, which means that if the option `od1.var2`
|
|
|
|
is set to `oui`, the option is not hidden (because of the `True` at the end of
|
|
|
|
the tuple wich means 'inverted', take a look at the :doc:`consistency`
|
|
|
|
document.)::
|
2013-08-26 17:14:14 +02:00
|
|
|
|
|
|
|
>>> print c.od2.var4
|
|
|
|
oui
|
|
|
|
>>> c.od1.var2 = u'non'
|
|
|
|
>>> print c.od2.var4
|
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
tiramisu.error.PropertiesOptionError: trying to access to an option named: od2 with properties ['hidden']
|
|
|
|
>>> c.od1.var2 = u'oui'
|
|
|
|
>>> print c.od2.var4
|
|
|
|
oui
|
|
|
|
|
|
|
|
Requirements can be accumulated
|
|
|
|
|
|
|
|
>>> print c.cfgimpl_get_settings()[rootod.od1.var3]
|
|
|
|
[]
|
|
|
|
>>> c.od1.var2 = u'non'
|
|
|
|
>>> print c.cfgimpl_get_settings()[rootod.od1.var3]
|
|
|
|
['disabled', 'hidden']
|
|
|
|
>>> c.od1.var2 = u'oui'
|
|
|
|
>>> print c.cfgimpl_get_settings()[rootod.od1.var3]
|
|
|
|
[]
|
|
|
|
|
|
|
|
Requirements can be accumulated for different or identical properties (inverted
|
|
|
|
or not)::
|
|
|
|
|
2013-08-27 15:54:10 +02:00
|
|
|
>>> a = UnicodeOption('var3', '', u'value', requires=[{'option':od1.var2,
|
|
|
|
'expected':'non', 'action':'hidden'}, {'option':od1.var1, 'expected':'oui',
|
|
|
|
'action':'hidden'}])
|
|
|
|
>>> a = UnicodeOption('var3', '', u'value', requires=[{'option':od1.var2,
|
|
|
|
'expected':'non', 'action':'hidden'}, {'option':od1.var1, 'excepted':'oui',
|
|
|
|
'action':'disabled', 'inverse':True}])
|
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
But it is not possible to have inverted requirements on the same property.
|
|
|
|
Here is an impossible situation::
|
|
|
|
|
2013-08-27 15:54:10 +02:00
|
|
|
>>> a = UnicodeOption('var3', '', u'value', requires=[{'option':od1.var2,
|
|
|
|
'expected':'non', 'action':'hidden'}, {'option':od1.var1, 'expected':'oui',
|
|
|
|
'hidden', True}])
|
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
Traceback (most recent call last):
|
|
|
|
[...]
|
|
|
|
ValueError: inconsistency in action types for option: var3 action: hidden
|
2013-08-27 15:54:10 +02:00
|
|
|
|
|
|
|
The calculations
|
|
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Let's create four calculation functions::
|
|
|
|
|
|
|
|
def return_calc():
|
|
|
|
#return an unicode value
|
|
|
|
return u'calc'
|
|
|
|
|
|
|
|
def return_value(value):
|
|
|
|
return value
|
|
|
|
|
|
|
|
def return_value_param(param=u''):
|
|
|
|
return param
|
|
|
|
|
|
|
|
def return_no_value_if_non(value):
|
|
|
|
#if value is not u'non' return value
|
|
|
|
if value == u'non':
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return value
|
|
|
|
|
|
|
|
Then we create four options using theses functions::
|
|
|
|
|
|
|
|
>>> var1 = UnicodeOption('var1', '', callback=return_calc)
|
|
|
|
>>> var2 = UnicodeOption('var2', '', callback=return_value, callback_params={'': (u'value',)})
|
|
|
|
>>> var3 = UnicodeOption('var3', '', callback=return_value_param, callback_params={'param': (u'value_param',)})
|
|
|
|
>>> var4 = UnicodeOption('var4', '', callback=return_no_value_if_non, callback_params={'': (('od1.var5', False),)})
|
|
|
|
>>> var5 = UnicodeOption('var5', '', u'oui')
|
|
|
|
>>> od1 = OptionDescription('od1', '', [var1, var2, var3, var4, var5])
|
|
|
|
>>> rootod = OptionDescription('rootod', '', [od1])
|
|
|
|
>>> c = Config(rootod)
|
|
|
|
>>> c.read_write()
|
|
|
|
|
|
|
|
The first option `var1` returns the result of the `return_calc` function, wich
|
|
|
|
is `u'calc'`::
|
|
|
|
|
|
|
|
>>> print c.od1.var1
|
|
|
|
calc
|
|
|
|
|
|
|
|
The second option `var2` returns the result of the `return_value` fucntion,
|
|
|
|
wich is `value`. The parameter `u'value'` is passed to this function::
|
|
|
|
|
|
|
|
>>> print c.od1.var2
|
|
|
|
value
|
|
|
|
|
|
|
|
The third option `var3` returns the result of the function `return_value_param`
|
|
|
|
with the named parameter `param` and the value `u'value_param'`::
|
|
|
|
|
|
|
|
>>> print c.od1.var3
|
|
|
|
value_param
|
2013-08-26 17:14:14 +02:00
|
|
|
|
2013-08-27 15:54:10 +02:00
|
|
|
The fourth option `var4` returns the reslut of the function `return_no_value_if_non`
|
|
|
|
that is the value of `od1.var5` exceptif the value is u`non`::
|
|
|
|
|
|
|
|
>>> print c.od1.var4
|
|
|
|
oui
|
|
|
|
>>> c.od1.var5 = u'new'
|
|
|
|
>>> print c.od1.var4
|
|
|
|
new
|
|
|
|
>>> c.od1.var5 = u'non'
|
|
|
|
>>> print c.od1.var4
|
|
|
|
None
|
|
|
|
|
|
|
|
The calculation replaces the default value.
|
|
|
|
If we modify the value, the calculation is not carried out any more::
|
|
|
|
|
|
|
|
>>> print c.od1.var1
|
|
|
|
calc
|
|
|
|
>>> c.od1.var1 = u'new_value'
|
|
|
|
>>> print c.od1.var1
|
|
|
|
new_value
|
|
|
|
|
|
|
|
To force the calculation to be carried out in some cases, one must add the
|
|
|
|
`frozen` and the `force_default_on_freeze` properties::
|
|
|
|
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1].append('frozen')
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1].append('force_default_on_freeze')
|
|
|
|
>>> print c.od1.var1
|
|
|
|
calc
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1].remove('frozen')
|
|
|
|
>>> c.cfgimpl_get_settings()[rootod.od1.var1].remove('force_default_on_freeze')
|
|
|
|
>>> print c.od1.var1
|
|
|
|
new_value
|
|
|
|
|
|
|
|
|
2013-08-26 17:14:14 +02:00
|
|
|
Configuration's interesting methods
|
2013-05-21 11:37:39 +02:00
|
|
|
------------------------------------------
|
2013-05-17 12:11:14 +02:00
|
|
|
|
|
|
|
A `Config` object is informed by an `option.OptionDescription`
|
|
|
|
instance. The attributes of the ``Config`` objects are the names of the
|
|
|
|
children of the ``OptionDescription``.
|
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
Here are the (useful) methods on ``Config`` (or `SubConfig`).
|
2013-05-17 12:11:14 +02:00
|
|
|
|
2013-05-21 11:37:39 +02:00
|
|
|
.. currentmodule:: tiramisu.config
|
2013-05-17 12:11:14 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
.. class:: Config
|
2013-05-17 12:11:14 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
.. autoclass:: SubConfig
|
|
|
|
:members: find, find_first, __iter__, iter_groups, iter_all, make_dict
|
2013-05-17 12:11:14 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
.. automethod:: __init__
|
2013-08-23 11:42:22 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
.. rubric:: Summary
|
2013-05-17 12:11:14 +02:00
|
|
|
|
|
|
|
.. autosummary::
|
2013-08-23 11:42:22 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
find
|
|
|
|
find_first
|
2013-05-17 12:11:14 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
__iter__
|
|
|
|
iter_groups
|
|
|
|
iter_all
|
2013-05-17 12:11:14 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
make_dict
|
2013-05-21 18:42:56 +02:00
|
|
|
|
2013-05-23 17:51:50 +02:00
|
|
|
.. rubric:: Methods
|
2013-05-21 18:42:56 +02:00
|
|
|
|
2013-08-23 11:42:22 +02:00
|
|
|
|
|
|
|
A :class:`~config.CommonConfig` is a abstract base class. A
|
|
|
|
:class:`~config.SubConfig` is an just in time created objects that wraps an
|
|
|
|
::class:`~option.OptionDescription`. A SubConfig differs from a Config in the
|
|
|
|
::fact that a config is a root object and has an environnement, a context wich
|
|
|
|
::defines the different properties, access rules, vs... There is generally only
|
2013-08-21 17:21:09 +02:00
|
|
|
::one Config, and many SubConfigs.
|