Configurations

In Central, a configuration is a Config object which is responsible to fetch the configuration data from an external source.

Central has many type of Config builtin like FileConfig, UrlConfig, EnvironmentConfig, S3Config and more.

Central configuration keys are case insensitive.

Central treats keys with None value as missing keys.

ChainConfig

This configuration groups multiple Config together to create a single view.

The ChainConfig does not merge the configurations but instead treats them as overrides so that a key existing in a configuration supersedes the same key in a previous configuration in the chain.

The chain works in reverse order, that means the keys from the last configuration in the chain overrides the previous one.

# main.py

from central.config import ChainConfig, MemoryConfig

defaults = MemoryConfig()
defaults.set('host', 'localhost')
defaults.set('port', 12345)

overrides = MemoryConfig()
overrides.set('host', 'dev.example.com')
overrides.set('timeout', 10)

config = ChainConfig(defaults, overrides)
config.load()

print(config.get('host'))
print(config.get('port'))
print(config.get('timeout'))
python main.py
>> dev.example.com
>> 12345

CommandLineConfig

This configuration loads the configuration data from the command line args.

# main.py

from central.config import CommandLineConfig

config = CommandLineConfig()
config.load()

timeout = config.get('timeout', default=10)

print(timeout)
python main.py timeout=100
>> 100

Dashed argument is also supported.

python main.py --timeout 100
>> 100

Default value is used if argument is missing.

python main.py
>> 10

EnvironmentConfig

This configuration loads the configuration data from the environment variables.

# main.py

from central.config import EnvironmentConfig

config = EnvironmentConfig()
config.load()

timeout = config.get('timeout', default=10)

print(timeout)
export TIMEOUT=100
python main.py
>> 100

Default value is used if environment variable is missing.

python main.py
>> 10

FileConfig

This configuration loads the configuration data from a config file. Central supports JSON, TOML, YAML and INI file formats.

TOML requires the external library toml and you must installed it by yourself (pip install toml)
YAML requires the external library PyYAML and you must installed it by yourself (pip install PyYAML)

The content of the file is determined by the file name extension.

# config.yaml

database:
    host: localhost
    port: 1234
# main.py

from central.config.file import FileConfig

config = FileConfig('config.yaml')
config.load()

print(config.get('database.host'))
python main.py
>> localhost

Using a custom reader

By default, FileConfig finds the best reader for the file name using the file name extension, Central has readers for JSON, TOML, JSON and INI.

You can also specific your own reader or you can force one specific reader for a file name.

# app.cfg

database:
    host: localhost
    port: 1234
# main.py

from central.config.file import FileConfig
from central.readers import YamlReader

config = FileConfig('app.cfg', reader=YamlReader())
config.load()

print(config.get('database.host'))
python main.py
>> localhost

Loading cascaded configuration files

A FileConfig supports multiple configuration files, that is also called cascaded configuration files.

For example, you want Central to load an environment specific configuration file config.prod.json to override the default config.json. To do that, you can define this key at the end of the config.json file:

{
    "@next": "config.${ENV}.json"
}

@next is a special key to define next file to load. ENV is a variable that will expand to value returned from environment variables.

Full example:

# config.json

{
    "database": {
        "host": "localhost",
        "port": 1234
    },
    "@next": "config.${ENV}.json"
}
# config.prod.json

{
    "database": {
        "host": "prod.db"
    }
}
# main.py

from central.config.file import FileConfig

config = FileConfig('config.json')
config.load()

print(config.get('database.host'))
print(config.get('database.port'))
export ENV=prod
python main.py
>> prod.db
>> 1234

MemoryConfig

This configuration allows the user to set custom keys at runtime.

# main.py

from central.config import MemoryConfig

config = MemoryConfig()
config.set('timeout', 100)

timeout = config.get('timeout')

print(timeout)
python main.py
>> 100

A MemoryConfig in combination with a ChainConfig can also be used to set default values.

# main.py

from central.config import ChainConfig, FileConfig, MemoryConfig

defaults = MemoryConfig()
defaults.set('host', 'localhost')
defaults.set('port', 12345)

config = ChainConfig(defaults, FileConfig('config.json'))
config.load()

print(config.get('host'))
print(config.get('port'))
# config.json

{
    "host": "dev.example.com",
}
python main.py
>> dev.example.com
>> 12345

MergeConfig

This configuration merge multiple Configinto a single configuration data, in case of key collision last-match wins.

It makes a deep merge so configurations with subtrees are also merged.

# base.json

{
    "database": {
        "host": "localhost",
        "port": 1234
    }
}
# dev.json

{
    "timeout": 100,
    "database": {
        "host": "dev.example.com"
    }
}

Merging both configs, the result will be:

# merged

{
    "timeout": 100,
    "database": {
        "host": "dev.example.com",
        "port": 1234
    }
}
# main.py

from central.config import MergeConfig
from central.config.file import FileConfig

config = MergeConfig(FileConfig('base.json'), FileConfig('dev.json')
config.load()

print(config.get('timeout'))
print(config.get('database'))
python main.py
>> 100
>> {"database": {"host": "dev.example.com", "port": 1234}}

If your configuration is a simple key/value without subtrees, it is recommended to use ChainConfig instead of MergeConfig because ChainConfig consumes less resources.

PrefixedConfig

This configuration allows to view into another Config for keys starting with a specified prefix.

# main.py

from central.config import MemoryConfig, PrefixedConfig

config = MemoryConfig(data={'production.timeout': 100})

config = PrefixedConfig('production', config)

timeout = config.get('timeout')

print(timeout)
python main.py
>> 100

There is also a shortcut to create a PrefixedConfig object based on another Config object.

# main.py

from central.config import MemoryConfig

config = MemoryConfig(data={'production.timeout': 100}).prefixed('production')

timeout = config.get('timeout')

print(timeout)
python main.py
>> 100

ReloadConfig

This configuration reloads its sub-configuration that is triggered by its scheduler, that is useful when you need to update an application's configuration at runtime and you do not want to restart the application to have a config take effect.

Gone are the days of needing to restart a server to have a config take effect, Central can read an update to a configuration source while running.

Optionally you can provide a function to ReloadConfig to run each time a change occurs.

from central.config import ReloadConfig
from central.config.file import FileConfig
from central.schedulers import FixedIntervalScheduler

scheduler = FixedIntervalScheduler(60) # 1 minute in seconds
file_config = FileConfig('config.json')

config = ReloadConfig(file_config, scheduler)
config.load()

@config.on_updated
def config_updated():
    print('Config updated')

The code above may look a bit verbose, you may prefer to use the shortcut reload_every, you can use reload_every on any Config object.

from central.config.file import FileConfig

config = FileConfig('config.json').reload_every(60) # 1 minute in seconds
config.load()

@config.on_updated
def config_updated():
    print('Config updated')

UrlConfig

This configuration loads the configuration data from the response of an URL. The format of the content is determined by the Content-Type header or by a file name extension.

Central supports JSON, TOML, YAML and INI as content formats.

TOML requires the external library toml and you must installed it by yourself (pip install toml)
YAML requires the external library PyYAML and you must installed it by yourself (pip install PyYAML)

from central.config.url import UrlConfig

config = UrlConfig('http://www.example.com/appname/config.json')
config.load()

If the URL does not contain a file name extension, the response must contain a Content-Type header specifying the format of the content.

UrlConfig can understand severals Content-Type values, such as: application/json, application/x-json, text/json, text/vnd.json and so on.

from central.config.url import UrlConfig

config = UrlConfig('http://www.example.com/appname/config')
config.load()

The URL supports string interpolation, that means you can use environment variables in it.

from central.config.url import UrlConfig

config = UrlConfig('http://www.example.com/appname/${ENV}/config')
config.load()

Using a custom reader

By default, UrlConfig finds the best reader based on the Content-Type of the response from the URL, Central has readers for JSON, TOML, JSON and INI.

You can also specific your own reader or you can force one specific reader for an URL.

from central.config import UrlConfig
from central.readers import JsonReader

config = UrlConfig('http://example.com/appname/config', reader=JsonReader())
config.load()

Implementing your own Config

If you plan to implement a new Config that holds keys and values, Central provides a base config class called BaseDataConfig that handles most of work for you.

from central.config.core import BaseDataConfig
from central.structures import IgnoreCaseDict

class MyConfig(BaseDataConfig):
    def load(self):
        # you must use an IgnoreCaseDict which is a dict
        # but with case insensitive.
        data = IgnoreCaseDict()

        # here you load the keys/values from 
        # the external source.

        data['key1'] = 'value 1'
        ...
        ...

        self._data = data

results matching ""

    No results matching ""