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