Lesson 7 — add configuration¶
What you will build¶
One setting, read from three places, to show which one wins. Nothing is hard-coded and nothing is global: configuration is read once, by the application, and reached through it.
What you need¶
The setup from lesson 1. This lesson uses nothing beyond the core package.
Where settings come from¶
Four sources, and the highest one in this list wins:
- explicit arguments passed in code,
- environment variables starting with
XYBEROS_, - the file
xyberos.toml, - defaults.
The code¶
"""Lesson 7 — settings from a file, the environment, and arguments.
Run it with:
python -m learn_fundamentals.fundamentals07_configuration
"""
from __future__ import annotations
import tempfile
from pathlib import Path
from xyberos import Settings
CONFIG_FILE = """\
[app]
name = "tutorial"
environment = "staging"
debug = true
"""
def main() -> None:
with tempfile.TemporaryDirectory() as directory:
(Path(directory) / "xyberos.toml").write_text(CONFIG_FILE, encoding="utf-8")
settings = Settings.load(environ={}, cwd=Path(directory))
print("from the file:", settings.app.name, settings.app.environment, settings.app.debug)
settings = Settings.load(
environ={"XYBEROS_APP__NAME": "from-the-environment"}, cwd=Path(directory)
)
print("the environment wins:", settings.app.name)
settings = Settings.load(
environ={"XYBEROS_APP__NAME": "from-the-environment"},
overrides={"app": {"name": "from-the-arguments"}},
cwd=Path(directory),
)
print("arguments win:", settings.app.name)
if __name__ == "__main__":
main()
How to run it¶
What it prints¶
from the file: tutorial staging True
the environment wins: from-the-environment
arguments win: from-the-arguments
The same file is loaded three times with different inputs, which is why the module writes its
xyberos.toml into a temporary directory instead of the working directory — a lesson that leaves a
config file behind is a lesson that changes the next one's result.
The lines that matter¶
| You write | You get |
|---|---|
[app] name = "tutorial" |
settings.app.name |
XYBEROS_APP__NAME=tutorial |
the same setting, from the environment |
XYBEROS_CONFIG=/etc/xyberos.toml |
a different file to read |
Settings.load(overrides={"app": {"debug": True}}) |
an explicit argument, the highest precedence |
The double underscore in XYBEROS_APP__NAME is not a typo: a single _ separates words inside a
name, and __ walks into a section. So XYBEROS_APP__SHUTDOWN_TIMEOUT sets [app] shutdown_timeout.
Common mistakes¶
- Looking for a global. There is no module-level settings object and no
app.nameshortcut. Read it through the application:app.settings.app.name. -
Misspelling a key and expecting a default. An unknown key is an error, not silence. The message names the field and the source it came from, and never the value, because a value can be a secret.
-
Editing the file to change a deployment. That is what the precedence order is for: a deployment sets an environment variable and leaves everything under version control alone.
Exercise¶
Set the application name from the environment, without changing the file.
Show the answer
=== "PowerShell" === "POSIX" The file still says `tutorial`, and the first line of output still shows it — but the setting the lesson cares about now comes from the environment, which is how a deployment changes configuration without editing anything under version control.Next¶
Lesson 8 is where the wiring becomes interesting: a service that needs another service, and what the runtime does when one is missing. Until it is published, the roadmap shows where each lesson stands.