Configuration Loaders

Loaders are in charge of loading configuration from various sources, like .ini files or environment variables. Loaders are ment to chained, so that prettyconf checks one by one for a given configuration variable.

Prettyconf comes with some loaders already included in prettyconf.loaders.

See also

Some loaders include a var_format callable argument, see Naming conventions for variables to read more about it’s purpose.

Environment

The Environment loader gets configuration from os.environ. Since it is a common pattern to write env variables in caps, the loader accepts a var_format function to pre-format the variable name before the lookup occurs. By default it is str.upper().

from prettyconf import config
from prettyconf.loaders import Environment


config.loaders = [Environment(var_format=str.upper)]
config('debug')  # will look for a `DEBUG` variable

EnvFile

The EnvFile loader gets configuration from .env file. If the file doesn’t exist, this loader will be skipped without raising any errors.

# .env file
DEBUG=1
from prettyconf import config
from prettyconf.loaders import EnvFile


config.loaders = [EnvFile(file='.env', required=True, var_format=str.upper)]
config('debug')  # will look for a `DEBUG` variable

Note

You might want to use dump-env, a utility to create .env files.

IniFile

The IniFile loader gets configuration from .ini or .cfg files. If the file doesn’t exist, this loader will be skipped without raising any errors.

CommandLine

This loader lets you extract configuration variables from parsed CLI arguments. By default it works with argparse parsers.

from prettyconf import Configuration, NOT_SET
from prettyconf.loaders import CommandLine

import argparse


parser = argparse.ArgumentParser(description='Does something useful.')
parser.add_argument('--debug', '-d', dest='debug', default=NOT_SET, help='set debug mode')

config = Configuration(loaders=[CommandLine(parser=parser)])
print(config('debug', default=False, cast=config.boolean))

Something to notice here is the NOT_SET value. CLI parsers often force you to put a default value so that they don’t fail. In that case, to play nice with prettyconf, you must set one. But that would break the discoverability chain that prettyconf encourages. So by setting this special default value, you will allow prettyconf to keep the lookup going.

The get_args function converts the argparse parser’s values to a dict that ignores NOT_SET values.

RecursiveSearch

This loader tries to find .env or *.ini|*.cfg files and load them with the EnvFile and IniFile loaders respectively. It will start at the starting_path directory to look for configuration files.

Warning

It is important to note that this loader uses the glob module internally to discover .env and *.ini|*.cfg files. This could be problematic if the project includes many files that are unrelated, like a pytest.ini file along side with a settings.ini. An unexpected file could be found and be considered as the configuration to use.

Consider the following file structure:

project/
  settings.ini
  app/
    settings.py

When instantiating your RecursiveSearch, if you pass /absolute/path/to/project/app/ as starting_path the loader will start looking for configuration files at project/app.

# Code example in project/app/settings.py
import os

from prettyconf import config
from prettyconf.loaders import RecursiveSearch

app_path = os.path.dirname(__file__)
config.loaders = [RecursiveSearch(starting_path=app_path)]

By default, the loader will try to look for configuration files until it finds valid configuration files or it reaches root_path. The root_path is set to the root directory / initialy.

Consider the following file structure:

/projects/
  any_settings.ini
  project/
    app/
      settings.py

You can change this behaviour by setting any parent directory of the starting_path as the root_path when instantiating RecursiveSearch:

# Code example in project/app/settings.py
import os

from prettyconf import Configuration
from prettyconf.loaders import RecursiveSearch

app_path = os.path.dirname(__file__)
project_path = os.path.realpath(os.path.join(app_path, '..'))
rs = RecursiveSearch(starting_path=app_path, root_path=project_path)
config = Configuration(loaders=[rs])

The example above will start looking for files at project/app/ and will stop looking for configuration files at project/, actually never looking at any_settings.ini and no configuration being loaded at all.

The root_path must be a parent directory of starting_path:

# Code example in project/app/settings.py
from prettyconf.loaders import RecursiveSearch

# /baz is not parent of /foo/bar, so this raises an InvalidPath exception here
rs = RecursiveSearch(starting_path="/foo/bar", root_path="/baz")

AwsParameterStore

The AwsParameterStore loader gets configuration from the AWS Parameter Store, part of AWS Systems Manager. The loader will be skipped if the parameter store is unreachable (connectivity, unavailability, access permissions). The loader respects parameter hierarchies, performing non-recursive discoveries. The loader accepts AWS access secrets and region when instantiated, otherwise, it will use system-wide defaults (if available). The AWS parameter store supports three parameter types: String, StringList and SecureString. All types are read as strings, however, decryption of SecureStrings is not handled by the loader.

from prettyconf import config
from prettyconf.loaders import AwsParameterStore


config.loaders = [AwsParameterStore(path='/api')]
config('debug')  # will look for a parameter named "/api/debug" in the store