Configuration Management: dynaconf¶
Features¶
Inspired by the 12-factor application guide
Settings management (default values, validation, parsing, templating)
Protection of sensitive information (passwords/tokens)
Multiple file formats
toml|yaml|json|ini|py
and also customizable loaders.Full support for environment variables to override existing settings (dotenv support included).
Optional layered system for multi environments
[default, development, testing, production]
(also called multi profiles)Built-in support for Hashicorp Vault and Redis as settings and secrets storage.
Built-in extensions for Django and Flask web frameworks.
CLI for common operations such as
init, list, write, validate, export
.
For more information visit https://www.dynaconf.com/
Installation¶
$ poetry add dynaconf
Initialization¶
$ mkdir configs
$ dynaconf init -p configs -f yaml
This command creates the following files:
.
├── configs/
│ ├── .gitignore
│ ├── .secrets.toml # Sensitive data like passwords and tokens (optional)
│ └── settings.toml # Application setttings (optional)
└── config.py # Where you import your settings object (required)
Fix the paths for your settings files in config.py
settings_files=["configs/settings.yaml", "configs/.secrets.yaml"]
Basic Usage¶
Let us create a broken calculator to see how dynaconf works.
# python_lifecycle_training/calculator/broken.py
import fire
from loguru import logger
from config import settings
from python_lifecycle_training.calculator.complex import Calculator
class BrokenCalculator(Calculator):
offset = settings.offset
logger.info(f"Offset: {offset}")
@classmethod
def add(cls, a, b):
return super(BrokenCalculator, cls).add(a, b) - cls.offset
@classmethod
def sub(cls, a, b):
return super(BrokenCalculator, cls).sub(a, b) - cls.offset
@classmethod
def mul(cls, a, b):
return super(BrokenCalculator, cls).mul(a, b) - cls.offset
@classmethod
def div(cls, a, b):
return super(BrokenCalculator, cls).div(a, b) - cls.offset
def main():
fire.Fire(BrokenCalculator)
Add an offset in settings.yaml
file:
offset: 2
Add an entry point in pyproject.toml
calc-broken = "python_lifecycle_training.calculator.broken:main"
Install your package
$ poetry install
Run the command
$ calc-broken add 2 2
Environment Variables¶
Dynaconf prioritizes environment variables over files as the best recommendation to keep
your settings. You can override any setting key by exporting an environment variable
prefixed by DYNACONF_
(or by the custom prefix)
$ export DYNACONF_OFFSET=1
$ calc-broken add 2 2
Note
To unset the variable run unset DYNACONF_OFFSET
You can customize the prefix for your env vars by changing it in config.py
Advanced Features¶
Switch Work Environment¶
Enable environment switching
settings = Dynaconf(
envvar_prefix="DYNACONF",
settings_files=["configs/settings.yaml", "configs/.secrets.yaml"],
environments=True,
)
Edit settings.yaml
default:
name: ""
offset: 1
development:
name: developer
production:
offset: 0
name: admin
Log the name
of the user running the broken calculator
class BrokenCalculator(Calculator):
offset = settings.offset
logger.info(f"Offset: {offset}")
logger.info(f"Set by: {settings.name}")
Run command
$ calc-broken add 2 2
Dynaconf sets the default environment to development
.
The subsequent workspace inherits the configurations of the upper workspace unless
replaced. Thus, we could access the offset in development
even though we didn’t
specify it explicitly.
Switch Environment using Environment Variable¶
$ export ENV_FOR_DYNACONF=production
$ calc-broken add 2 2
Note
Unset ENV_FOR_DYNACONF using unset ENV_FOR_DYNACONF
Switch Environment using CLI¶
Set environment to development
in your package __init__.py
file
ENV = "development"
Update the broken calculator
import python_lifecycle_training
class BrokenCalculator(Calculator):
with settings.using_env(python_lifecycle_training.ENV):
offset = settings.offset
logger.info(f"Offset: {offset}")
logger.info(f"Set by: {settings.name}")
Create a common CLI
# python_lifecycle_training/calculator/cli.py
import fire
from loguru import logger
import python_lifecycle_training
from python_lifecycle_training.calculator.broken import BrokenCalculator
from python_lifecycle_training.calculator.complex import Calculator
from python_lifecycle_training.calculator.simple import add
class Main:
def __init__(self, env: str = "development"):
self.env = env
logger.info(f"Environment: {self.env}")
python_lifecycle_training.ENV = self.env
self.simp = add
self.complex = Calculator
self.broken = BrokenCalculator
def main():
fire.Fire(Main)
Update entry point scripts
[tool.poetry.scripts]
calc = "python_lifecycle_training.calculator.cli:main"
Install package
$ poetry install
Run command on production
environment from CLI
$ calc broken add 2 2 --env=production
You can switch also between existing environments using:
from_env: Will create a new settings instance pointing to defined env. You can use this when you have to access a lesser number of config variables at once.
settings.from_env("production").name
setenv: (not recommended) Will set the existing instance to defined env. This might seem convenient but may cause problems as the env is not set globally.
setenv("production") settings.name
Other features¶
Next Step¶
To move on to the next step commit or stash your changes then checkout to the branch
setup/test/pytest
$ git stash
$ git checkout setup/test/pytest
Uninstall¶
$ poetry remove dynaconf