Embedding configuration in python files

In many cases, it’s desirable to let the end user specify configuration in the same langauge as the rest of the system (Django and Sphinx are examples of frameworks that works this way). LayeredConfig provides the source PyFile that lets the user create configuration using normal python code.

If you create a file like conf.py with the following contents:

from __future__ import unicode_literals

import os
import multiprocessing
from datetime import datetime, date

home = os.getcwd()
name = 'My App'
dostuff = name.istitle()
duedate = date.today()
submodule = Subsection()
submodule.retry = True

Note

The class Subsection will automatically be imported into conf.py and is used to create new subsections. Parameters in subsections are created as normal attributes on the subsection object.

And load it, together with a Defaults source like in previous examples:

from layeredconfig import LayeredConfig, PyFile, Defaults
from datetime import date, datetime

conf = LayeredConfig(Defaults({'home': '/tmp/myapp',
                               'name': 'MyApp',
                               'dostuff': False,
                               'times': 4,
                               'duedate': date(2014, 10, 30),
                               'things': ['Huey', 'Dewey', 'Louie'],
                               'submodule': {
                                   'retry': False,
                                   'lastrun': datetime(2014, 10, 30, 16, 40, 22)
                               }
                           }),
                     PyFile("conf.py"))

The configuration object will act the same as in previous examples, ie. values that are specified in conf.py be used, and values specified in the Defaults object only used if conf.py doesn’t specify them.

Note

The PyFile source is read-only, so it should not be used when it’s desirable to be able to save changed configuration parameters to a file. Use PyFile or one of the other *File sources in these cases.

It’s also possible to keep system defaults in a separate python file, load these with one PyFile instance, and then let the user override parts using a separate PyFile instance. Functionally, this is not very different than loading system defaults using a Defaults source, but it might be preferable in some cases. As an example, if the file defaults.py contains the following code:

from datetime import date, datetime

home =  '/tmp/myapp'
name =  'MyApp'
dostuff = False
times = 4
duedate = date(2014, 10, 30),
things = ['Huey', 'Dewey', 'Louie']
submodule = Subsection()
submodule.retry = False
submodule.lastrun = datetime(2014, 10, 30, 16, 40, 22)

And a LayeredConfig object is initialized in the following way, then the resulting configuration object works identically to the above:

conf = LayeredConfig(PyFile("defaults.py"),
                     PyFile("conf.py"))