1
Plainbox Configuration System
1
PlainBox Configuration System
2
2
=============================
4
Plainbox has a modular configuration system. The system allows one to define
4
PlainBox has a modular configuration system. The system allows one to define
5
5
static configuration models that are composed of variables. This is all
6
implemented in :mod:`plainbox.impl.secure.config` as two classes
7
:class:`plainbox.impl.secure.config.Config` and
8
:class:`plainbox.impl.secure.config.Variable`::
6
implemented in :mod:`plainbox.impl.config` as two classes
7
:class:`plainbox.impl.config.Config` and
8
:class:`plainbox.impl.config.Variable`::
10
>>> from plainbox.impl.secure.config import Config, Variable
10
>>> from plainbox.impl.config import Config, Variable
12
12
Configuration models
13
13
^^^^^^^^^^^^^^^^^^^^
15
Each subclass of :class:`plainbox.impl.secure.config.Config` defines a new
15
Each subclass of :class:`plainbox.impl.config.Config` defines a new
16
16
configuration model. The model is composed of named variables and sections
17
17
defined as members of the class using a quasi-declarative syntax::
40
40
if missing, pick the default from the variable declaration. By default values
41
41
are not constrained in any way.
46
Apart from handling arbitrary values, variables can store the ``Unset`` value,
47
which is of the special ``UnsetType``. Unset variables are used as the implicit
48
default values so understanding them is important.
50
The ``Unset`` value is always false in a boolean context. This makes it easier
51
to accommodate but applications are still expected to handle it correctly. One
52
way to do that is to provide a default value for **every** variable used.
53
Another is to use the :class:`~plainbox.impl.secure.config.NotUnsetValidator`
54
to prevent such values from reaching the application.
56
43
Using Variable with custom default values
57
44
-----------------------------------------
59
46
Each variable has a default value that is used when variable is accessed but
60
47
was not assigned or loaded from a config file before. By default that value is
61
a special :class:`~plainbox.impl.secure.config.Unset` object, but it can be
62
changed using the ``default`` keyword argument::
48
a special :class:`~plainbox.impl.config.Unset` object, but it can be changed
49
using the ``default`` keyword argument::
64
51
>>> class AppConfig(Config):
65
52
... log_level = Variable(default='INFO')
139
126
... if value not in self.choices:
140
127
... return "unspported value"
142
Each time the called validator returns None, it is assumed that everything is
129
Each time the check() method returns None, it is assumed that everything is
143
130
okay. Otherwise the returned string is used as a message and
144
:class:`plainbox.impl.secure.config.ValidationError` is raised.
131
:class:`plainbox.impl.config.ValidationError` is raised.
146
133
To use the new validator simply pass it to the ``validator_list`` keyword
161
148
... debug = Variable(default=False, kind=bool)
166
Validators that want to see the ``Unset`` value need to be explicitly
167
tagged, otherwise they will never see that value (they will not be called)
168
but can assume that the value is of correct type (bool, int, float or str).
170
If you need to write a validator that understands and somehow handles the
171
Unset value, decorate it with the
172
:func:`~plainbox.impl.secure.config.understands_Unset` decorator.
174
150
Using Section objects
175
151
---------------------
177
153
Sometimes there is a necessity to allow the user to add arbitrary key=value
178
154
data to the configuration file. This is possible using the
179
:class:`plainbox.impl.secure.config.Section` class. Consider this example::
155
:class:`plainbox.impl.section.Section` class. Consider this example::
181
157
>>> class AppConfig(Config):
182
158
... log_level = Variable(
204
180
Accessing Section objects returns a dictionary of the key-value pairs that
205
181
were defined in that section.
207
Using Parametric Section objects
208
--------------------------------
210
Parametric section is a special section that is automatically grouped with
211
other sections beginning with the same prefix.
212
The group name and the param name is seperated by ':' (colon) character.
215
class AppConfig(Config):
216
reports = ParametricSection(name='report')
218
Now, if the config file contains sections beginning with ``report:`` they are
219
grouped together and assigned to the ``reports`` variable. E.g. for a config
227
Will make ``report`` field of the class AppConfig contain following
230
{'bar': {'somevar': someval}, 'baz': {'othervar': 'otherval'}}
232
183
Loading configuration from file
233
184
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
235
186
Configuration objects are not of much use without being able to load data from
236
187
actual files. This is fully supported using just one call to
237
:meth:`plainbox.impl.secure.config.Config.read()`. Read takes a list of files
238
to read as argument and tries to parse and load data from each existing file.
239
Missing files are silently ignored.
188
:meth:`plainbox.impl.config.Config.read()`. Read takes a list of files to read
189
as argument and tries to parse and load data from each existing file. Missing
190
files are silently ignored.
241
192
Because configuration files may be corrupted, have typos, incorrectly specified
242
193
values or other human-caused mistakes. The read() operation never fails as the
243
194
application probably does not want to block on errors unconditionally. Instead
244
195
after calling read() the application may inspect two instance attributes:
245
:attr:`plainbox.impl.secure.config.Config.problem_list` and
246
:attr:`plainbox.impl.secure.config.Config.filename_list`. They contain the list
247
of exceptions raised while trying to load and use the configuration files and
248
the list of files that were actually loaded, respectively.
250
.. note:: The only supported delimiter is ``=``.
196
:attr:`plainbox.impl.config.Config.problem_list` and
197
:attr:`plainbox.impl.config.Config.filename_list`. They contain the list of
198
exceptions raised while trying to load and use the configuration files and the
199
list of files that were actually loaded, respectively.
252
201
The Config.Meta class
253
202
^^^^^^^^^^^^^^^^^^^^^
277
226
This attribute is an empty list by default. The intent is to hold a list of all
278
227
the possible pathnames that the configuration should be loaded from. This field
279
is used by :func:`plainbox.impl.secure.config.Config.get()` method.
228
is used by :func:`plainbox.impl.config.Config.get()` method.
281
230
Typically this field is specified in a custom version of the Meta class to
282
231
encode where the configuration files are typically stored.
287
236
A Config sub-class can define a custom Meta class with any attributes that may
288
237
be desired. That class will be merged with an internal
289
:class:`plainbox.impl.secure.config.ConfigMetaData` class. In effect the actual
290
Meta attribute will be a new type that inherits from both the custom class that
291
was specified in the source code and the standard ConfigMetaData class.
238
:class:`plainbox.impl.config.ConfigMetaData` class. In effect the actual Meta
239
attribute will be a new type that inherits from both the custom class that was
240
specified in the source code and the standard ConfigMetaData class.
293
242
This mechanism is fully transparent to the user. There is no need to explicitly
294
243
inherit from ConfigMetaData directly.
299
The config system uses a special value :obj:`plainbox.impl.secure.config.Unset`
300
which is the only instance of :class:`plainbox.impl.secure.config.UnsetType`.
301
Unset is used instead of ``None`` as an implicit default for each ``Variable``
248
The config system uses a special value :obj:`plainbox.impl.config.Unset` which
249
is the only instance of :class:`plainbox.impl.config.UnsetType`. Unset is used
250
instead of ``None`` as an implicit default for each ``Variable``
303
252
The only thing that ``Unset`` is special for is that it evaluates to false in a