Getting StartedΒΆ

First we install the library:

pip install clac

Next, we need to prepare each of our layers:

from clac import CLAC, DictLayer, DictStructure, EnvLayer

# Get the dicts for each of the layers

# rc-style files are usually flat keys, which could have dots in their names.
# Google .pylintrc or .coveragerc for examples of rc-style config files.
rcfile = {
    'lingua': 'franca',
    'salt.pepper': 'oregano',
    'foo': 'bar',
}
# Create the layer with a recognizable name
rc_layer = DictLayer('rcfile', rcfile)

# We can import toml or json directly into nested python dictionaries.
# For this example we will assume that the following dict was imported
# earlier.
toml_dict = {
    'foo': 'baz',
    'spam': {
        'ham': 'eggs',
    },
    'salt': {
        'pepper': 'cayenne',
    },
}
# This time, we need to split the names by the dots, since these dicts have
# a nested-dict structure.
toml_layer = DictLayer('tomlfile', toml_dict, dot_strategy=DictStructure.Split)

# For environment variables, we can instatiate a layer directly
env_layer = EnvLayer('env')

# Now we can create the container for all of the layers
config = CLAC(rc_layer, toml_layer, env_layer)

# We could also build the object incrementally, separate from instatiation.
# Adding the rcfile layer first means that values from that rcfile values
# will override competing values from the toml layer.
config = CLAC()
config.add_layers(rc_layer)
# We can still add multiple layers at once.
config.add_layers(toml_layer, env_layer)

Now, we can check the various config entries.

# 'foo' is found in the rcfile first, so we get 'bar' instaed of 'baz'
assert config['foo'] == 'bar'
# But we can double-check the toml file if we want, using the name of the
# layer we want.
assert config.get('foo', layer_name='tomlfile') == 'baz'

# 'spam' is not found in the rcfile, so the CLAC checks the tomlfile
assert config['spam'] == {'ham': 'eggs'}

# Be careful when searching on partial keys, since flat DictLayers cannot
# support partial matching:

# 'salt' would be a partial match for rcfile, so toml file value is used
assert config['salt'] == {'pepper': 'cayenne'}
# 'salt.pepper' has an exact match in the rcfile, so we get that value
# before the toml file.
assert config['salt.pepper'] == 'oregano

# get() supports defaults and post-retrieval processing, but not at the same
# time.  Default values are *not* processed with the callback.

# Here, we set the callback to str, but still get an int, because the value
# was not found, and the callback was never executed.  This return the
# default value as-is.
assert config.get('missing', default=123, callback=str) == 123