try:
from flask.config import Config
flask_installed = True
except ImportError: # pragma: no cover
flask_installed = False
Config = object
import dynaconf
from importlib import import_module
[docs]class FlaskDynaconf(object):
"""The arguments are.
app = The created app
dynaconf_args = Extra args to be passed to Dynaconf (validator for example)
All other values are stored as config vars specially::
ENVVAR_PREFIX_FOR_DYNACONF = env prefix for your envvars to be loaded
example:
if you set to `MYSITE` then
export MYSITE_SQL_PORT='@int 5445'
with that exported to env you access using:
app.config.SQL_PORT
app.config.get('SQL_PORT')
app.config.get('sql_port')
# get is case insensitive
app.config['SQL_PORT']
Dynaconf uses `@int, @bool, @float, @json` to cast
env vars
SETTINGS_FILE_FOR_DYNACONF = The name of the module or file to use as
default to load settings. If nothing is
passed it will be `settings.*` or value
found in `ENVVAR_FOR_DYNACONF`
Dynaconf supports
.py, .yml, .toml, ini, json
ATTENTION: Take a look at `settings.yml` and `.secrets.yml` to know the
required settings format.
Settings load order in Dynaconf:
- Load all defaults and Flask defaults
- Load all passed variables when applying FlaskDynaconf
- Update with data in settings files
- Update with data in environment vars `ENVVAR_FOR_DYNACONF_`
TOML files are very useful to have `envd` settings, lets say,
`production` and `development`.
You can also achieve the same using multiple `.py` files naming as
`settings.py`, `production_settings.py` and `development_settings.py`
(see examples/validator)
Example::
app = Flask(__name__)
FlaskDynaconf(
app,
ENV_FOR_DYNACONF='MYSITE',
SETTINGS_FILE_FOR_DYNACONF='settings.yml',
EXTRA_VALUE='You can add aditional config vars here'
)
Take a look at examples/flask in Dynaconf repository
"""
def __init__(
self,
app=None,
instance_relative_config=False,
dynaconf_instance=None,
**kwargs
):
"""kwargs holds initial dynaconf configuration"""
if not flask_installed: # pragma: no cover
raise RuntimeError(
"To use this extension Flask must be installed "
"install it with: pip install flask"
)
self.kwargs = kwargs
kwargs.setdefault("ENVVAR_PREFIX_FOR_DYNACONF", "FLASK")
env_prefix = "{0}_ENV".format(
kwargs["ENVVAR_PREFIX_FOR_DYNACONF"]
) # FLASK_ENV
kwargs.setdefault("ENV_SWITCHER_FOR_DYNACONF", env_prefix)
self.dynaconf_instance = dynaconf_instance
self.instance_relative_config = instance_relative_config
if app:
self.init_app(app, **kwargs)
[docs] def init_app(self, app, **kwargs):
"""kwargs holds initial dynaconf configuration"""
self.kwargs.update(kwargs)
self.settings = self.dynaconf_instance or dynaconf.LazySettings(
**self.kwargs
)
dynaconf.settings = self.settings # rebind customized settings
app.config = self.make_config(app)
app.dynaconf = self.settings
[docs] def make_config(self, app):
root_path = app.root_path
if self.instance_relative_config: # pragma: no cover
root_path = app.instance_path
if self.dynaconf_instance:
self.settings.update(self.kwargs)
return DynaconfConfig(
root_path=root_path,
defaults=app.config,
_settings=self.settings,
_app=app,
)
[docs]class DynaconfConfig(Config):
"""
Settings load order in Dynaconf:
- Load all defaults and Flask defaults
- Load all passed variables when applying FlaskDynaconf
- Update with data in settings files
- Update with data in environmente vars `ENV_FOR_DYNACONF_`
"""
def __init__(self, _settings, _app, *args, **kwargs):
"""perform the initial load"""
super(DynaconfConfig, self).__init__(*args, **kwargs)
Config.update(self, _settings.store)
self._settings = _settings
self._app = _app
def __getitem__(self, key):
"""
Flask templates always expects a None when key is not found in config
"""
return self.get(key)
def __setitem__(self, key, value):
"""
Allows app.config['key'] = 'foo'
"""
return self._settings.__setitem__(key, value)
def __getattr__(self, name):
"""
First try to get value from dynaconf then from Flask
"""
try:
return getattr(self._settings, name)
except AttributeError:
return self[name]
def __call__(self, name, *args, **kwargs):
return self.get(name, *args, **kwargs)
[docs] def get(self, key, default=None):
"""Gets config from dynaconf variables
if variables does not exists in dynaconf try getting from
`app.config` to support runtime settings."""
return self._settings.get(key, Config.get(self, key, default))
[docs] def load_extensions(self, key="EXTENSIONS", app=None):
"""Loads flask extensions dynamically."""
app = app or self._app
for extension in app.config[key]:
# Split data in form `extension.path:factory_function`
module_name, factory = extension.split(":")
# Dynamically import extension module.
ext = import_module(module_name)
# Invoke factory passing app.
getattr(ext, factory)(app)