Python Config Loader with Dataclasses and Validation Prompt
Generate a typed configuration loader that merges defaults, files (YAML/TOML/JSON), and environment variables into validated dataclasses with clear, fail-fast errors.
- Target user
- Python developers who want type-safe, layered application config
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior Python engineer who hates config that fails silently three hours into a job. Build a robust, typed config loader. I will provide: - The settings my app needs (names, types, which are secrets, which are required) - Supported sources (file format, env prefix) and their precedence - Deployment targets (local, CI, container, prod) Deliver a single module that: 1. **Defines config as nested `@dataclass`(es)** with full type hints and sane defaults. No bare dicts floating around the app. 2. **Layers sources with explicit precedence**: defaults < config file < environment variables < explicit CLI/arg overrides. Document the order and make it deterministic. 3. **Reads files safely** — auto-detect or be told the format (prefer `tomllib` for TOML, `yaml.safe_load`, or `json`). Missing optional file is fine; malformed file is a hard error with the file path and line if available. 4. **Maps env vars** with a configurable prefix (e.g. `APP_DB_HOST` -> `db.host`). Coerce strings to the dataclass field type (int, float, bool, list, paths). Reject unknown required-but-empty values. 5. **Validates fail-fast** — after merging, run validation: required fields present, ranges/enums respected, mutually-exclusive options, URL/port sanity. Raise ONE aggregated error listing every problem, not the first one only. 6. **Handles secrets correctly** — never log secret values; provide a `__repr__`/redaction that masks them. Allow secrets to come from a file path (e.g. `*_FILE`) so they aren't baked into env. 7. **Is testable and pure** — `load_config(env: Mapping, argv: list)` takes inputs explicitly so tests don't touch the real environment. 8. **Freezes the result** — return an immutable/frozen config so nothing mutates it at runtime. Output: (a) the dataclass definitions, (b) the loader + coercion helpers, (c) the aggregated validation error class, (d) a `pytest` suite covering precedence, coercion, and a malformed-file case, (e) an example config file and `.env`. Bias toward: explicit over magic, helpful error messages with the offending key, and zero network/global state at import time.