Skip to content
← DevOps Foundations

Learning bite

Files and configuration

Read a small configuration file and reject invalid values before acting.

  • Python
Documentation reviewed2026-10-01 · 3 min read
  1. Why
  2. Predict
  3. Try
  4. Inspect
  5. Explain
  6. Save evidence

Predict before you try

Why not accept unknown fields automatically?

Try it: A configuration file is input, not trusted code →
On this page

A configuration file is input, not trusted code

Configuration lets the same program operate on different values without editing its source. A file can be readable yet contain invalid syntax; valid JSON can still have missing fields or impossible values. Check those layers separately so a failure tells the caller what to fix.

In the existing capacity-tool directory, save capacity.json beside capacity.py:

json
{"total": 20, "used": 8}

JSON objects become Python dictionaries, arrays become lists, and JSON null becomes None. Save read_capacity.py:

python
import json
from pathlib import Path
from capacity import remaining_gib

def read_capacity(path: Path) -> int:
    data = json.loads(path.read_text(encoding="utf-8"))
    if not isinstance(data, dict) or set(data) != {"total", "used"}:
        raise ValueError("expected exactly total and used fields")
    return remaining_gib(data["total"], data["used"])

if __name__ == "__main__":
    print(read_capacity(Path("capacity.json")))

Run python read_capacity.py from the project root. Expected output: 12. Path represents a filesystem path. read_text reads bytes and decodes UTF-8; json.loads turns JSON text into Python values. Checking the exact key set catches both missing fields and typos such as uesd. The imported function performs the numeric checks.

Diagnose one layer at a time

Save a copy of the valid fixture before these trials. Restore it between trials.

ChangeExpected failureWhat it tells you
Rename capacity.jsonFileNotFoundErrorThe path does not identify a readable file here.
Remove a closing braceJSONDecodeErrorThe contents are not valid JSON.
Add "extra": 1ValueError from our schema checkValid JSON does not match this tool's fields.
Change used to 25ValueError from remaining_gibThe values violate our capacity rule.
Change used to "8"TypeErrorThe tool requires a number, not numeric text.

The uncaught traceback is useful while learning. The next lesson converts these expected failures into a concise CLI error and a nonzero exit status.

Decide how files are located and values are chosen

Relative paths start from the process's current working directory. Running /somewhere/capacity-tool/read_capacity.py from another folder does not move the process there. An explicit configuration argument makes that choice visible.

Python 3.11 includes tomllib for reading TOML. YAML needs an additional library; use its safe data-loading interface, not an arbitrary object loader. Do not use eval to read configuration. The format changes the parser, but the need to validate types and meaning remains.

If a tool has defaults, a file, environment values, and CLI flags, document a winning order. For example, with default timeout 3, file 5, environment 8, and CLI 10, a defaults→file→environment→CLI rule produces 10. Convert and validate the winning value; environment values arrive as strings. Avoid silently treating an invalid override as a reason to use a default.

Writing deserves its own decision. Directly overwriting a live file can leave partial contents if interrupted. A common approach writes a temporary file in the destination directory, validates it, then replaces the destination. Permissions, concurrent writers, and durability still matter; the reporting tool here does not need to write configuration at all.

Checkpoint

Why not accept unknown fields automatically? A misspelling could quietly change behavior. A more extensible format can allow extras deliberately, but this small format promises exactly two fields. Can a valid parser prove used <= total? No; that is a rule of our program.

Restore the valid fixture and retain both Python modules. Next, expose their behavior through arguments, stdout, stderr, and exit codes.

References: pathlib↗, JSON↗, TOML↗, and os.replace↗.

Prove what you learned

Inspect the result

Record input, returned value/output and expected versus actual failure behaviour.

Explain it in your own words

Explain why your observation supports the stated outcome, and name one thing it does not prove.

Try a small variation

Choose one different valid value and one missing or boundary input; predict both before running.

Your evidence should show

  • Record the context/revision or label the work as a paper or prepared fixture.
  • Compare the prediction with the actual result from “A configuration file is input, not trusted code”.
  • Record input, returned value/output and expected versus actual failure behaviour.
  • Explain the transfer challenge and retain the same verification question.
Hint

Trace the input, returned value or exception, and observable command result.

Answer guide: compare after predicting

A misspelling could quietly change behavior. A more extensible format can allow extras deliberately, but this small format promises exactly two fields. Can a valid parser prove used <= total

Compare this with your actual observation. A paper answer is useful reasoning practice; record execution separately.

Recall shell argument boundaries and exit-status checks. Revisit the previous lesson.

Save the prediction, result and explanation ↓

Your notes and evidence

Record observations, questions, or links to your work. Keep credentials out of your notes.

Loading saved progress…

Back up or restore this path

Progress and notes stay in this browser. A backup contains only this learning path.