comparison docs/introduction.rst @ 215:ab3d0326419c

Doc: Move the "doc" to "docs"
author Franz Glasner <fzglas.hg@dom66.de>
date Wed, 08 May 2019 09:23:37 +0200
parents doc/introduction.rst@fa660f084ceb
children 57ff12610dc5
comparison
equal deleted inserted replaced
214:a35b0ca8b81f 215:ab3d0326419c
1 .. -*- coding: utf-8; indent-tabs-mode: nil; -*-
2
3 .. _introduction:
4
5 Introduction
6 ============
7
8 .. contents::
9 :local:
10
11 The configurations can be read from different types of files:
12
13 - :ref:`YAML files <yaml-files>`
14 - :ref:`JSON files <json-files>`
15 - :ref:`INI files <ini-files>`
16 - :ref:`TOML files <toml-files>`
17 - :ref:`executable Python scripts <executable-python-scripts>`
18
19
20 .. _yaml-files:
21
22 YAML Files
23 ----------
24
25 Need the :mod:`yaml` package (https://github.com/yaml/pyyaml)
26 (e.g. ``pip install pyyaml``)
27
28 .. note:: All strings are returned as Unicode text strings.
29
30 .. note:: The root object must be a *mapping* and therefore decode
31 into a Python :class:`dict` alike. This is checked by the
32 implementation.
33
34 An example is:
35
36 .. literalinclude:: ../tests/data/conf10.yml
37 :language: yaml
38
39
40 .. _json-files:
41
42 JSON files
43 ----------
44
45 Read the JSON file with the help of Python's native :mod:`json` package.
46
47 .. note:: All strings are returned as Unicode text strings.
48
49 .. note:: The root object must be an *object* and therefore decode
50 into a Python :class:`dict` alike. This is checked by the
51 implementation.
52
53 An example is:
54
55 .. literalinclude:: ../tests/data/conf10.json
56 :language: js
57
58 For comments in JSON files see section :ref:`comments`.
59
60
61 .. _ini-files:
62
63 INI Files
64 ---------
65
66 Read the file and all sections named in parameter `extract` are flattened
67 into the resulting dictionary. By default the section named ``config`` is
68 used.
69
70 Normally all values are returned as Unicode text strings.
71 But values can be annotated and therefore interpreted as other types:
72
73 ``:int:``
74 The value is handled in the same way as a Python :class:`int`
75 literal
76
77 ``:float:``
78 The value is interpreted as :class:`float`
79
80 ``:bool:``
81 The resulting value is a :class:`bool` where
82
83 ``1``, ``true``, ``yes``, ``on``
84 yield a Python ``True``
85
86 ``0``, ``false``, ``no``, ``off``
87 yield a Python ``False``
88
89 The evaluation is done *case-insensitively*.
90
91 .. note:: All strings are returned as Unicode text strings.
92
93 .. note:: Contrary to the behaviour of the standard Python :mod:`configparser`
94 module the INI file reader is *case-sensitive*.
95
96 The example INI style configuration below yields an equivalent
97 configuration to the YAML configuration above:
98
99 .. literalinclude:: ../tests/data/conf10.ini
100 :language: ini
101
102 As can be seen in this example -- INI file internal value interpolation
103 is done as in Python's standard :mod:`configparser` module.
104
105 This example also illustrates how INI sections are used to build a
106 tree-ish configuration dictionary.
107
108
109 .. _toml-files:
110
111 TOML Files
112 ----------
113
114 Read the TOML file with the help of the pure Python :mod:`toml`
115 package (https://github.com/uiri/toml) (e.g. ``pip install toml``).
116
117 All TOML features map seamingless to "ConfigMix".
118
119 The example TOML style configuration below yields an equivalent
120 configuration to the YAML configuration above:
121
122
123 .. literalinclude:: ../tests/data/conf10.toml
124 :language: ini
125
126
127 .. _executable-python-scripts:
128
129 Executable Python Scripts
130 -------------------------
131
132 What will be exported:
133
134 1. If loading is done with the `extract` parameter only the given keys are
135 extracted from the script.
136
137 2. Otherwise it is checked if the scripts defines an ``__all__``
138 sequence. If there is one it's contents are the keys to be
139 extracted.
140
141 3. If there is no ``__all__`` object all names not starting with an
142 underscore ``_`` are found.
143
144 This is analogous to as Python modules behave when importing them with
145 ``from module import *``.
146
147 .. note:: The Python configuration files are evaluated with ``exec`` and not
148 imported.
149
150 The example configuration by Python script below yields an equivalent
151 configuration to the YAML configuration above:
152
153 .. literalinclude:: ../tests/data/conf10.py
154 :language: python
155
156
157 .. _loading-and-merging:
158
159 Loading and Merging
160 -------------------
161
162 Basic usage of the API is as follows in this example::
163
164 import configmix
165
166 #
167 # Note: With conf10 merging is rather pointless because the tree
168 # files # are really the same configuration. But is doesn't harm
169 # also here.
170 #
171 config = configmix.load("conf10.yml", "conf10.ini", "conf10.py")
172
173 # Get a -- possibly interpolated -- configuration variable's value
174 value1 = config.getvar_s("key1")
175
176 # Get a -- possibly interpolated -- variable from within the tree
177 value2 = config.getvar_s("tree1.tree2.key4")
178
179
180 By default filenames of the configuration files must have the extensions
181 (case-sensitivety depends on your OS):
182
183 ``.ini``
184 for INI configuration files
185
186 ``.json``
187 for JSON configuration files
188
189 ``.py``
190 for Python configuration files
191
192 ``.toml``
193 for TOML configuration file
194
195 ``.yml`` or ``.yaml``
196 for YAML configuration files
197
198
199 .. _getting-values:
200
201 Getting configuration variables
202 -------------------------------
203
204 Get a -- possibly interpolated -- configuration variable's value with::
205
206 value1 = config.getvar_s("key1")
207
208 Get a raw configuration variable's value with::
209
210 value1_raw = config.getvar("key1")
211
212 Because the configuration is not only a plain list of but a tree of
213 key-value pairs you will want to fetch them by separating the individual
214 level keys with a point ``.``.
215
216 Looking at the example in chapter :ref:`yaml-files` -- when calling
217 ``config.getvar_s("tree1.tree2.key4")`` you will get the value
218 ``get this as `tree1.tree2.key4'``.
219
220 This is true for both methods :py:meth:`.Configuration.getvar` and
221 :py:meth:`.Configuration.getvar_s`.
222
223 Both methods also perform :ref:`variable-interpolation` and handle
224 :ref:`variable-namespaces`. Filtering is not supported. So -- the
225 variable name arguments of :py:meth:`.Configuration.getvar` and
226 :py:meth:`.Configuration.getvar_s` are of the form
227 ``[namespace:]variable``.
228
229
230 .. _comments:
231
232 Comments
233 --------
234
235 By default all keys beginning with ``__comment`` or ``__doc`` are
236 filtered out and not given to the application. This allows comments in
237 JSON files -- but is not restricted to JSON files only.
238
239 For all types of configuration files their respective standard comments
240 are allowed too.
241
242
243 .. _variable-namespaces:
244
245 Variable Namespaces
246 -------------------
247
248 Currently there are 4 namespaces:
249
250 1. The unnamed namespace (which is also default).
251
252 All the configuration variables are part of this namespace.
253
254 2. The namespace ``OS``
255
256 Available functions:
257
258 ``cwd``
259 Contains the current working directory of the process
260
261 3. The namespace ``ENV``
262
263 This namespace contains all the environment variables as they are
264 available from :py:data:`os.environ`.
265
266 4. The namespace ``PY``
267
268 Contains selected values from the running Python:
269
270 ``version``
271 The return value of :py:func:`platform.python_version`
272
273 ``version_maj_min``
274 Just the major and minor version of the running Python
275 (``.`` separated)
276
277 ``version_maj``
278 Just the major version of the running Python
279
280 ``implementation``
281 The return value of :py:func:`platform.python_implementation`
282
283
284 Examples
285 ~~~~~~~~
286
287 ::
288
289 config.getvar("OS:cwd")
290
291 yields the current working directory as :py:func:`os.getcwd` does.
292
293
294 .. _variable-interpolation:
295
296 Variable Interpolation
297 ----------------------
298
299 Configuration variable values that are read with
300 :py:meth:`.Configuration.getvar_s` are subject to variable
301 interpolation. The general syntactic pattern for this is::
302
303 {{[namespace:]variable[|filter[|filter...]]}}
304
305 I.e.: between double curly braces an optional `namespace` name followed by
306 a colon ``:``, the `variable` and then zero or more filters, each one
307 introduced by a pipe symbol ``|``.
308
309 Variables are expanded *lately* at runtime -- exactly when calling
310 :py:meth:`.Configuration.getvar_s`,
311 :py:meth:`.Configuration.substitute_variables_in_obj` or
312 :py:meth:`.Configuration.expand_variable`
313
314
315 Filter functions
316 ~~~~~~~~~~~~~~~~
317
318 Interpolated values can be processed through a series of filter functions::
319
320 {{my.variable|filter1|filter2}}
321
322 Available filter functions are:
323
324 ``urlquote``
325
326 ``saslprep``
327
328 ``normpath``
329
330 ``abspath``
331
332 ``posixpath``
333
334 ``lower``
335
336 ``upper``
337
338
339 Examples
340 ~~~~~~~~
341
342 ::
343
344 {{OS:cwd|posixpath}}
345
346 expands to the current working directory as POSIX path: on Windows all
347 backslashes are replaced by forward slashes.
348
349 ::
350
351 {{ENV:PATH}}
352
353 expands to the current search path from the process environment.
354
355 ::
356
357 {{PY:version}}
358
359 expands to the current running Python version (e.g. ``3.6.4``).
360
361 ::
362
363 {{PY::implementation|upper}}
364
365 expands to something like ``CPYTHON`` when using the standard Python
366 interpreter written in C.
367
368
369 Custom filename extensions and custom loaders
370 ---------------------------------------------
371
372 If you want to have custom configuration file extensions and/or custom loaders
373 for custom configuration files you have various possibilities:
374
375 Associate an additional new extension (e.g. ".conf") with an
376 existing configuration file style (e.g. YAML)::
377
378 configmix.set_assoc("*.conf", configmix.get_assoc("*.yml"))
379
380 Allow only files with extension ".cfg" in INI-style -- using the default
381 loader for INI-files::
382
383 configmix.clear_assoc()
384 configmix.set_assoc("*.cfg", configmix.get_default_assoc("*.ini"))
385
386 Only a new configuration file style::
387
388 def my_custom_loader(filename):
389 ...
390 return some_dict_alike
391
392 configmix.mode_loaders["myconfmode"] = my_custom_loader
393 configmix.clear_assoc()
394 configmix.set_assoc("*.my.configuration", "myconfmode")
395
396 If :py:func:`~configmix.clear_assoc` will not be called then just a *new*
397 configuration file style will be installed.
398
399 To select the loader not by extension but by an Emacs-compatible mode
400 declaration (e.g. ``mode: yaml``) in the first two lines of a file use::
401
402 configmix.set_assoc("*", configmix.try_determine_filemode)