new api documentation

This commit is contained in:
gwen 2013-05-21 18:42:56 +02:00
parent 480ed190aa
commit 0e6032dd88
10 changed files with 93 additions and 105 deletions

View file

@ -4,11 +4,11 @@
Configuration handling basics
===============================
Tiramisu is designed with three main objects :
Tiramisu is made of almost three main objects :
- :class:`tiramisu.config.Config` witch is the whole configuration entry point
- :class:`tiramisu.option.Option` stands for the option type
- :class:`tiramisu.option.OptionDescription` stands for the description (the schema)
- :class:`tiramisu.option.Option` stands for the option types
- :class:`tiramisu.option.OptionDescription` is the shema, the option's structure
Accessing the configuration `Option`'s
-----------------------------------------
@ -83,6 +83,10 @@ the first one is of course the `__setattr__` method
cfg.name = value
And if you wanna come back to a default value, do it the pythonic way::
del(cfg.name)
.. module:: tiramisu.config
The handling of options is split into two parts: the description of
@ -108,7 +112,7 @@ it is possible to
- `iter` on config, notice that there is an iteration order wich is
the order of the :ref:`optdescr` specification entries,
- compare two configs (equality),
- export the whole config into a `dict` with `config.make_dict()`,
- export the whole config into a `dict` with `config.SubConfig.make_dict()`,
`option.Option()` objects in a config are iterable in the pythonic
way, that is something like `[(name, value) for name, value in config]`.
@ -135,3 +139,10 @@ To iter on groups in the same manner, use the
.. automethod:: find_first
.. automethod:: iter_groups
.. automethod:: __iter__
or a SubConfig, or a MetaConfig :
.. autoclass:: SubConfig
:members:
:special-members:

View file

@ -45,29 +45,6 @@ third one is the callback's action name (`hide`, `show`...)::
Take a look at an example here
`test_option_consistency.test_hidden_if_in()`
Config updates
---------------
New configuration options and groups can be dynamically added.
The configuration has to be *updated* after that the description has been
passed to the Config objet, see:
::
>>> config = Config(descr)
>>> newoption = BoolOption('newoption', 'dummy twoo', default=False)
>>> descr.add_child(newoption)
>>> config.update()
>>> config.newoption
False
in
- `test_option_consistency.test_newoption_add_in_descr()`
- `test_option_consistency.test_newoption_add_in_subdescr()`
- `test_option_consistency.test_newoption_add_in_config()`
Validation upon a whole configuration object
----------------------------------------------
@ -77,10 +54,21 @@ This type of validation is very open. Let's take a use case : an option
has a certain value, and the value of this option can change the owner
of another option or option group... Everything is possible.
For example, the configuration paths have to be unique in the
`glossary#schema`, the validation is carried out at the
`config.Config._cfgimpl_build()` time in the
`config.Config._validate_duplicates()` method.
.. currentmodule:: tiramisu.option
Other hooks are availables to validate upon a whole configuration at any time,
for example the consistency between two options (typically, an
:class:`IPOption` and a :class:`NetworkOption`).
Values that are calculated
--------------------------------
An option that have a callback is considered to have a value that is to be
calculated.
An option's property with a `force_store_value` attribute is considered to be
modified at the first calculation.
.. automodule:: tiramisu.autolib
:members:
Other hook are availables to validate upon a whole configuration at any
time.

19
doc/error.txt Normal file
View file

@ -0,0 +1,19 @@
Errors that may be encountered
==================================
Three builtins exceptions are used :
-----------------------------------------
- **ValueError** : Validation error, parameters error, a list instead
of a Multi, or if the value does not make sense
- **TypeError** : type error in a parameter
- **AttributeError** : wrong path or unknownd option or optiondescription
And five user-defined exceptions :
-----------------------------------
.. automodule:: tiramisu.error
:members:

View file

@ -7,8 +7,6 @@
.. title:: tiramisu
.. |version| replace:: 0.1
The tasting of `Tiramisu`
=========================
@ -36,6 +34,7 @@ configuration handler.
status
consistency
glossary
error
Indices and tables
==================

View file

@ -100,3 +100,5 @@ configuration, that is :
.. autoclass:: ChoiceOption
.. automethod:: __init__

View file

@ -1,10 +1,7 @@
.. default-role:: literal
.. TODO: STATUS and settings explained
The statuses
======================
Local statuses and global setting
=====================================
Available configuration statuses
----------------------------------
@ -67,80 +64,51 @@ see `test_option_default.test_force_default_on_freeze()`
Restricted access to an `Option()`
-----------------------------------
.. currentmodule:: tiramisu.setting
.. autoclass:: Property
The `properties` attribute is in charge of the access rules' option's value.
Configuration options access statuses are defined at configuration level
that corresponds to the `option.Option()`'s `properties` attribute,
for example
for example: hidden, disabled.
**hidden**
Use the pythonic way to know if a property is there::
This means that an option raises an error if we try to access
the value of the option.
'hidden' in c.cfgimpl_get_settings()
'frozen' in c.cfgimpl_get_settings()[opt]
See `hide()` or `show()` in `Option()` that comes from
`option.HiddenBaseType`
To access to the global settings::
corresponding convenience API provided:
cfg.cfgimpl_get_settings()
cfg.cfgimpl_get_settings()[option1]
`hide()`:
set the `hidden` attribute to `True`
to add, or suppress a global property::
`show()`:
set the `hidden` attribute to `False`
cfg.cfgimpl_get_settings()[option1].append('hidden')
cfg.cfgimpl_get_settings()[option1].remove('hidden')
**disabled**
to activate, deactivate properties::
This means that an option *doesn't exists* (doesn't say anything
much more thant an `AttibuteAccess` error)
See in `option.DisabledBaseType` the origins of
`Option.enable()` or `Option.disable()`
corresponding convenience API provided:
`disable()`:
set the `disabled` attribute to `True`
`enable()`:
set the `disabled` attribute to `False`
cfg.cfgimpl_get_settings().append('hidden')
cfg.cfgimpl_get_settings().remove('hidden')
Value owners
-------------
.. method:: tiramisu.config.Config.getowner()
This method can retrieve an Option's owner.
Every configuration option has a **owner**. When the option is
instanciated, the owner is `default` because a default value has been
set (including `None`, take a look at the tests).
The `value_owner` is the man who did it. Yes, the man who changed the value of the
configuration option.
- At the instance of the `Config` object, the value owner is `default` because
- At the instance of the `Config` object, the value owner is `owners.default` because
the default values are set at the instance of the configuration option object,
::
# let's expect there is an option named 'name'
config = Config(descr, bool=False)
# the override method has been called
config._cfgimpl_value_owners['name'] == 'default'
- at the modification of an option, the owner is `default_owner`, (which is `user`)
::
# modification of the value by attribute access
config.gc.dummy = True
assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user'
- the default owner can be set with the `set_owner()` method
::
config.set_owner('spam')
config.set(dummy=True)
assert config.gc._cfgimpl_value_owners['dummy'] == 'spam'
assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'spam'
- at the modification of an option, the owner is `owners.default`, (which is `user`)
Special behaviors for an option
---------------------------------
@ -155,10 +123,7 @@ Special behaviors for an option
This means that it is a calculated value and therefore automatically
protected it cannot be modified by attribute access.
Its inner state is represented by `option.Option.has_callback()`
and `option.Option.hascallback_and_isfrozen()`
**force default**
**force_store_value**
if the configuration option has a default value, the default is
returned, otherwise the value is calculated.
@ -171,4 +136,4 @@ various ways.
If a default value is modified by overriding it, not only the value of
the option resets to the default that is proposed, but the owner is
modified too, it is reseted to `default`.
modified too, it is reseted to `owners.default`.

View file

@ -115,6 +115,7 @@ def calculate(name, callback, params, tcparams):
:param callback: callback name
:param params: in the callback's arity, the unnamed parameters
:params tcparams: in the callback's arity, the named parameters
:param tcparams: in the callback's arity, the named parameters
"""
return callback(*params, **tcparams)

View file

@ -416,7 +416,8 @@ class SubConfig(BaseInformation):
return context_descr.impl_get_path_by_opt(descr)
class ConfigCommon(SubConfig):
class CommonConfig(SubConfig):
"abstract base class for the Config and the MetaConfig"
__slots__ = ('_impl_values', '_impl_settings', '_impl_meta')
def _impl_build_all_paths(self):
@ -457,7 +458,7 @@ class ConfigCommon(SubConfig):
# ____________________________________________________________
class Config(ConfigCommon):
class Config(CommonConfig):
"main configuration management entry"
__slots__ = tuple()
@ -483,7 +484,7 @@ class Config(ConfigCommon):
self.cfgimpl_get_settings().reset_cache(only_expired=only_expired)
class MetaConfig(ConfigCommon):
class MetaConfig(CommonConfig):
__slots__ = ('_impl_children',)
def __init__(self, children, meta=True):
@ -492,7 +493,7 @@ class MetaConfig(ConfigCommon):
self._impl_descr = None
if meta:
for child in children:
if not isinstance(child, ConfigCommon):
if not isinstance(child, CommonConfig):
raise ValueError(_("metaconfig's children must be Config, not {0}"
"".format(type(child))))
if self._impl_descr is None:
@ -575,6 +576,7 @@ def mandatory_warnings(config):
where no value has been set
:returns: generator of mandatory Option's path
"""
#if value in cache, properties are not calculated
config.cfgimpl_reset_cache(only=('values',))

View file

@ -22,7 +22,7 @@
# Exceptions for an Option
class PropertiesOptionError(AttributeError):
"attempt to access to an option with a property that is'nt allowed"
"attempt to access to an option with a property that is not allowed"
def __init__(self, msg, proptype):
self.proptype = proptype
super(PropertiesOptionError, self).__init__(msg)

View file

@ -145,6 +145,7 @@ populate_multitypes()
class Property(object):
"a property is responsible of the option's value access rules"
__slots__ = ('_setting', '_properties', '_opt')
def __init__(self, setting, prop, opt=None):