.. default-role:: literal

Configuration status
======================

:module: :api:`config.py`
:tests: - :api:`test_option_owner.py`
        - :api:`test_option_type.py` 
        - :api:`test_option_default.py`

Available configuration statuses 
----------------------------------

These configuration statuses corresponds to specific global attributes : 

**read write status**

    The configuration can be accessed by `__get__` and `__set__`
    properties, except for the `hidden` configuration options but, yes, it is
    possible to modify a disabled option.

    To enable read-write status, call
    :api:`config.Config.cfgimpl_read_write()`
    
**read only status**

    The whole configuration is `frozen`, that is modifiying a value is 
    forbidden. We can access to a configuration option only with the 
    `__getattr__` property.
    
    The configuration has not an access to the hidden options
    but can read the disabled options.  

    To enable read only status, call :api:`config.Config.cfgimpl_read_only()`

.. csv-table:: **Configuration's statuses summary**
   :header: " ", "Hidden", "Disabled", "Mandatory"

    "read only status", `False`, `True`, `True`
    "read-write status", `True`, `False`, `False`

Freezing a configuration
---------------------------

It is possible to *freeze* a single `Option` object with 
:api:`option.Option.freeze()`. If you try to modify a frozen option, it 
raises a `TypeError: trying to change a frozen option object`.

At the configuration level, :api:`config.Config.cfgimpl_freeze()` freeze 
the whole configuration options.

- :api:`test_option_type.test_freeze_one_option()`
- :api:`test_option_type.test_frozen_value()`
- :api:`test_option_type.test_freeze()`


Restricted access to an `Option()`
-----------------------------------

Configuration options access statuses are defined at configuration level 
that corresponds to theses :api:`option.Option()`'s attribute: 

**hidden**

    This means that an option raises an `HiddenOptionError` if we try to access 
    the value of the option. 

    See `hide()` or `show()` in `Option()` that comes from 
    :api:`option.HiddenBaseType`

corresponding convenience API provided:

    `hide()`:
        set the `hidden` attribute to `True`

    `show()`:
        set the `hidden` attribute to `False`

**disabled**

    This means that an option *doesn't exists* (doesn't say anything 
    much more thant an `AttibuteAccess` error)

    See in :api:`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`

mode 

    a mode is `normal` or `expert`, just a category of `Option()` or 
    group wich determines if an option is easy to choose or not, 
    available methods are:

    `get_mode()`:
        returns the current mode
        
    `set_mode(mode)`:
        sets a new mode

    see it in :api:`option.ModeBaseType`

Value owners
-------------

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
  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'

Special owners
---------------

If the owner of a configuration option is `auto` or `fill` the behavior of the
access of the value changes. In fact, there is nothing in the value. 
The value comes from somewhere else (typically, it is calculated by the
operation system). 

**auto**

    This means that it is a calculated value and therefore automatically 
    protected it cannot be modified by attribute access once the owner 
    is `auto`.
    
    The configuration option is hidden and a fonction in a specific
    library is called for the computation of the value.

**fill**

    if the configuration option has a default value, the default is
    returned, otherwise the value is calculated

The default values behavior
----------------------------

Configuration options have default values that are stored in the 
`Option()` object itself. Default values, the `default`, can be set in 
various ways.

.. FIXME : ADD DETAILS HERE

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`.

