Split a config merger only after tests pin three states. Blank, missing, and duplicate keys are not one state. A shorter function can still change caller results.
The listing below is a proposed teaching fixture. It is not a measured trace from a live service. Treat every assertion as the fixture contract, not a benchmark.
What must stay stable
Environment values, file lines, and defaults overlap on purpose. Empty environment strings must not be treated as missing keys. Duplicate file keys currently keep the last written value.
Unknown file keys stay in the merged result. Unknown environment keys stay out of that result. Inner spaces in values stay until a later, separate change.
A missing file is not an error in this fixture. Defaults still load, and known environment keys may override them. A present file with zero matching keys leaves those defaults in place.
Python has guaranteed dict insertion order since 3.7. The environment mapping stores strings, and a missing key is absence. An empty string is a stored value, not a missing key.
See the current os.environ documentation before you rely on that split. See the current dict documentation before you pin key order in a test. Do not cite a locale encoding default without a version check.
Where a cleanup usually drifts
Fewer lines alone are not a behavior contract. A cleanup often strips values and drops unknown keys. It may also treat an empty string as a real override.
A second drift is keeping the first duplicate instead. A third drift is raising when the path is missing. A fourth drift is copying every environment key across.
Comments in the sample file are input, not documentation. Deleting source comments would not protect these rows. The risky edit is a merger that reclassifies blank input.
Proposed fixture
This module is intentionally small and intentionally strict. It is labeled as an unexecuted example for review. Run it yourself before you treat any row as observed.
import os
from pathlib import Path
DEFAULTS = {"timeout": "30", "region": "us", "debug": "false"}
def load_settings(path, env=None):
env = os.environ if env is None else env
text = ""
if path and Path(path).is_file():
text = Path(path).read_text(encoding="utf-8")
parsed = {}
for line in text.splitlines():
stripped = line.strip()
if not stripped or stripped.startswith("#"):
continue
if "=" not in stripped:
continue
key, value = stripped.split("=", 1)
parsed[key.strip()] = value
merged = {}
for key, value in DEFAULTS.items():
merged[key] = value
for key, value in parsed.items():
merged[key] = value
for key, value in env.items():
if key in merged and value != "":
merged[key] = value
return merged
The encoding argument is an explicit pin, not a guessed default. splitlines drops line endings and keeps the value text. The last assignment in parsed is the duplicate rule.
1. Freeze inputs outside the function
Build three tiny files in a temporary directory. Leave one path missing on purpose for the fallback row. Put a blank value and a duplicate key in another file.
Keep production secrets out of that scratch directory. Pass a plain dict as env so the process environment stays untouched. That argument is the seam you will extract later.
2. Lock rows before you rename anything
Write the tests in the next section before any extract. Record last-duplicate wins, even if you dislike that rule. Record that an empty override does not replace a file value.
Add a row that proves DEFAULTS is not mutated. Add a row that proves unknown environment keys are dropped. Add a row that proves unknown file keys are kept.
3. Run one command and store the node list
Use pytest with quiet output and short tracebacks. Repeat that same command after the patch, with no new flags. Stop the review when any previously passing node fails.
python -m pytest tests/test_load_settings.py -q --tb=short
Store the node names from the first green run. A green summary with a renamed test is not the same evidence. The comparison is the gate, not a formatting opinion.
4. Extract only the override rule
Move the environment loop into a function named apply_env_overrides. Keep file parsing inside load_settings for this single commit. Pass a plain dict in, and return a new dict.
Do not extract the line parser in the same commit. Do not extract default filling in the same commit either. Two extracts hide which edit moved a pinned row.
5. Use a free model only as a draft source
Disclosure: This article was prepared as part of MonkeyCode's product outreach. Operator-supplied notes say free model access is available now. Those same notes also say a free server option is available.
They do not name a model, a quota, hardware, or an end date. Treat both options as current availability, not as a permanent promise. This article reports no latency, cost, or quality score.
Paste the fixture, the pinned table, and the extract goal. Ask for one function, not a new configuration framework. Do not merge the draft until the local tests pass.
Use the free server for the scratch copy only. Do not upload customer files, tokens, or live environment dumps. Keep the decision on the machine that runs the suite.
6. Reject any moved row
If blank handling changes, discard the whole draft. If unknown keys appear or disappear, discard it too. Restore the scratch file and ask for a smaller patch.
A failed region assertion is a precedence bug, not a style nit. Read the env value first, then the file value, then the default. If the empty string won, the override guard was dropped.
A failed space assertion means the value was stripped. A failed unknown-key assertion means the membership filter moved. A failed duplicate assertion means the loop kept the first write.
Characterization tests
These tests are part of the proposed fixture. They specify the contract you should see if you run them. They are not a report of a shared CI history.
from settings_loader import DEFAULTS, load_settings
def test_missing_file_uses_defaults(tmp_path):
missing = tmp_path / "absent.cfg"
assert load_settings(missing, env={}) == {
"timeout": "30",
"region": "us",
"debug": "false",
}
def test_empty_env_does_not_override_file(tmp_path):
cfg = tmp_path / "app.cfg"
cfg.write_text("region=eu\n", encoding="utf-8")
assert load_settings(cfg, env={"region": ""})["region"] == "eu"
def test_nonempty_env_overrides_file_and_default(tmp_path):
cfg = tmp_path / "app.cfg"
cfg.write_text("region=eu\ntimeout=5\n", encoding="utf-8")
got = load_settings(cfg, env={"region": "apac", "timeout": "9"})
assert got["region"] == "apac"
assert got["timeout"] == "9"
def test_last_duplicate_wins_and_spaces_stay(tmp_path):
cfg = tmp_path / "app.cfg"
cfg.write_text(
"region=eu\nregion= apac \n# note\n\n",
encoding="utf-8",
)
assert load_settings(cfg, env={})["region"] == " apac "
def test_unknown_file_key_kept_when_env_silent(tmp_path):
cfg = tmp_path / "app.cfg"
cfg.write_text("tenant=acme\n", encoding="utf-8")
assert load_settings(cfg, env={})["tenant"] == "acme"
def test_unknown_env_key_dropped_known_override_kept(tmp_path):
cfg = tmp_path / "app.cfg"
cfg.write_text("tenant=acme\n", encoding="utf-8")
got = load_settings(cfg, env={"tenant": "other", "UNRELATED": "1"})
assert got["tenant"] == "other"
assert "UNRELATED" not in got
def test_blank_file_value_survives_without_env(tmp_path):
cfg = tmp_path / "app.cfg"
cfg.write_text("region=\n", encoding="utf-8")
assert load_settings(cfg, env={})["region"] == ""
def test_defaults_mapping_is_not_mutated(tmp_path):
before = dict(DEFAULTS)
cfg = tmp_path / "app.cfg"
cfg.write_text("region=eu\n", encoding="utf-8")
load_settings(cfg, env={"region": "apac"})
assert DEFAULTS == before
tmp_path is the standard pytest fixture for a temporary directory. Write files with encoding="utf-8" so the test matches the loader. Do not point these tests at a developer home directory.
Smallest safe extract
This extract is a proposed target shape, not a speed result. It copies DEFAULTS and copies merged before writes. File reading stays inside the original function body.
def apply_env_overrides(merged, env):
updated = dict(merged)
for key, value in env.items():
if key in updated and value != "":
updated[key] = value
return updated
def load_settings(path, env=None):
env = os.environ if env is None else env
text = ""
if path and Path(path).is_file():
text = Path(path).read_text(encoding="utf-8")
parsed = {}
for line in text.splitlines():
stripped = line.strip()
if not stripped or stripped.startswith("#"):
continue
if "=" not in stripped:
continue
key, value = stripped.split("=", 1)
parsed[key.strip()] = value
merged = dict(DEFAULTS)
merged.update(parsed)
return apply_env_overrides(merged, env)
dict(DEFAULTS) protects the module-level mapping from later writes. merged.update(parsed) keeps last-duplicate behavior already stored in parsed. The new function must not call Path or open.
Decision table
Use this table when you review a draft diff. A single moved row is enough to reject it. Do not average the rows into a soft score.
| Pinned row | Current result | Reject the draft if |
|---|---|---|
| Blank env value | File value kept | Empty string replaces the file |
| Missing env key | File, else default | Missing key becomes an error |
| Duplicate key | Last value kept | First value kept |
| Inner spaces | Spaces kept | Value is stripped |
| Unknown file key | Key kept | Key dropped |
| Unknown env key | Key absent | Key copied into output |
| Missing file | Defaults returned | Exception raised |
| Comment or blank line | Line ignored | Line parsed as a key |
| Module defaults | Mapping unchanged |
DEFAULTS mutated |
| Boolean-looking text | Stored as text | Value coerced to a bool |
Limitations
These tests freeze today's behavior, including awkward rows. They do not decide whether the format should change later. A later commit may change a row, but only with new tests.
Pin encoding as utf-8 inside the fixture and the tests. Newline handling here is splitlines, which drops endings. Keys are case-sensitive, and this suite does not fold case.
Remote draft hosts are for the scratch copy, not for secrets. Model text stays untrusted until the same local command passes. Availability notes are not a benchmark and not a support contract.
Who should skip this approach
Skip the approach when this commit must change visible behavior. Skip it when the tests cannot run on the machine you trust. Skip it when the open question is the file format itself.
Also skip it if import of the module reads secrets. Import-time reads will leak into the characterization run. Pin that boundary before you invite any model to edit.
Close
Pin blank, missing, and duplicate keys before the split. Keep the first extract smaller than the test module. If a free model session is already open, let it draft that extract only.
Primary references are the current os.environ, dict, and pytest tmp_path docs. Check those pages on publication day, because defaults can move. Do not treat this fixture as a substitute for those pages.
Top comments (0)