Configuration: settings and options¶
fresco.core.FrescoApp.options
is a dict-like
Options
object that can be used
for your application’s configuration.
Basic usage¶
In the simplest case, fresco.core.FrescoApp.options
can be used like a
regular dict:
from fresco import FrescoApp
app = FrescoApp()
app.options["SMTP_HOST"] = "smtp://localhost"
app.options.update({"DATABASE": "sqlite://"})
Settings are made available globally via context.app.options
:
from fresco import context
db = connect(context.app.options.DATABASE)
Using configuration files¶
Use load()
to load options from configuration
files:
app = FrescoApp()
# Load options from all matching files
app.options.load("conf.d/*")
# A fully loaded example
app.options.load(
"conf.d/*",
# Search for files in this directory
dir="/path/to/config",
# Allow configuration files to add keys not present in the first file
strict=False,
# Use environment variables in preference to values loaded from files
use_environ=True
)
The dir
argument specifies the directory to be searched for configuration
files (defaults to the current directory).
The default behaviour is that the first loaded file must specify all available
configuration keys.
A subsequent file that introduces a new key will raise an exception.
Specify strict=False
to turn off this check.
If use_environ=True
is specified, any
environment variable with the same name as a loaded option key will be used in
preference to the value loaded from the file. Environment variables are subject
to the same parsing and interpolation rules as described in key-value
properties files’
Selecting configuration files based on environment¶
load()
can load files selectively based on
‘tags’ embedded in the file names (tags are embedded in the filename, separated
by dots, eg settings.tag1.tag2.conf
).
For example with these configuration files:
settings.conf # 1
settings.dev.conf # 2
settings.staging.conf # 3
settings.staging.local.conf # 4
settings.local.conf # 5
This is how to load subsets of the available files:
# Load all files
options.load("settings*")
# Load base config file plus those
# tagged 'dev' or 'local' (files #1, #2 and #5)
options.load("settings*", ["dev", "local"])
Files are loaded in the order:
Files not matching any tags, ordered by filename.
Files matching one or more supplied tag, in the order of tags provided to
load()
.
The string {hostname}
in a tag name will be interpolated with the current
hostname (as returned by socket.gethostname
), but with dots replaced by
underscores (eg myserver_example_org
). A common pattern is:
options.load(
"settings*",
[
os.environ.get("FRESCO_PROFILE", "prod"),
"host-{hostname}",
"local"
]
)
This will load:
a base config file (eg
settings.conf
);then any config files tagged with the profile specified in the
FRESCO_PROFILE
environment variable (egsettings.dev.conf
orsettings.prod.conf
)then any host-specific config files (eg
settings.host-myserver_example_org.conf
);finally, any local config files (eg
settings.local.conf
).
Configuration file formats¶
The following formats are supported by load()
:
key-value properties files¶
These are simple newline separated lists of key-value pairs. The format is designed to be easy to parse, and as such does not support features such as multi-line strings or escaping special characters. For more flexibility use one of the other formats.
Example:
# This is a comment
database = postgresql://myserver/mydb
# There are two special variables available:
config_path = $__FILE__
data_dir = $__DIR__/data
# Environment variables may also be interpolated
cache_dir = $HOME/.cache/myapp-cache
# As can configuration keys that have already been loaded
sessions_dir = $data_dir/sessions
# Boolean values: 'true' and 'false' are case-insensitive here
apples_are_green = true
horses_are_green = false
# Integers
x = 1
y = 2
# Values with decimal points are parsed as `decimal.Decimal` objects
z = 11.3
# Everything else is a string
hello = world
# Strings may be quoted if required to disambiguate
# or to preserve whitespace
apikey = "123456"
message = " HELLO $hello "
JSON (.json
)¶
JSON files are loaded using python’s builtin JSON module.
Toml (.toml
)¶
Loading from Toml files is only supported if the toml package is available.
Python files (.py
)¶
The file will be loaded and parsed as a Python module. Module-level variables are loaded into the options dict unless they start with an underscore.
The __all__
variable may be used to specify a list of keys to load.
Example:
# Use leading underscores to avoid creating
# unnecessary entries in the options dict
from os.path import join as _pathjoin
from os import environ as _env
DATABASE = f"sqlite:///{_env['HOME']}/my.db"
Loading settings from environment variables¶
If you also want to load your default settings from files and then update this
from environment variables,
use load()
:
app = FrescoApp()
app.options.load("myapp.conf", use_environ=True)
If you only want to load values from the environment, use
update()
:
app = FrescoApp()
settings_keys = ['DATABASE']
app.options.update({k: os.environ[k] for k in settings_keys})
Onload hooks¶
Register callbacks to be run once
load()
has completed by using
onload()
:
options = fresco.options.Options()
@options.onload
def do_something_with(options):
print("Howdy!")
options.load(".env*")
API reference: fresco.options¶
- class fresco.options.Options(*a, **kw)[source]¶
Options dictionary. An instance of this is attached to each
fresco.core.FrescoApp
instance, as a central store for configuration options.- load(sources: str, tags: Sequence[str] = [], use_environ=False, strict=True, dir=None)[source]¶
Find all files matching glob pattern
sources
and populates the options object from those with matching filenames containingtags
.- Parameters:
sources – glob pattern or glob patterns separated by “;”
tags – a list of tags to look for in file names. If a filename contains multiple tags, all the tags in the filename must match for it to be loaded.
use_environ – if true, environment variables matching previously loaded keys will be loaded into the options object. This happens after all files have been processed.
strict – if true, the first file loaded is assumed to contain all available option keys. Any new key found in a later file will raise an error.
Files may be in python (
.py
), json (.json
), TOML (.toml
) format. Any other files will be interpreted as simple lists of`key=value
pairs.Tags in filenames should be delimited with periods, eg “.env.production.py”. For For example the filename
setttings.dev.local.ini
would be considered to have the tags,('dev', 'local')
The string ‘{hostname}’ can be included as part of a tag name: it will be substituted for the current host’s name with dots replaced by underscores.
Files with the suffix “.sample” are unconditionally excluded.
Files are loaded in the order specified by
tags
, then in filename order. Environment variables, if requested, are loaded last.Example:
opts = Options() opts.load(Options(), ".env*", ["dev", "host-{hostname}", "local"])
Would load options from files named
.env
,.env.json
,.env.dev.py
and.env.local.py.
- onload(fn: Callable) Callable [source]¶
Register a function to be called once
load
has finished populating the options object.
- update_from_dict(d, load_all=False)[source]¶
Update from the given list of key-value pairs.
If
load_all
is True, all key-value pairs will be loaded.Otherwise, if the special key ‘__all__’ is present, only those keys listed in __all__ will be loaded (same semantics as from … import *)
Otherwise only those NOT beginning with
_
will be loaded.