Enforce strict config schema and clean examples

This commit is contained in:
Thales Maciel 2026-02-26 16:31:00 -03:00
parent 0df8c356af
commit 67fc8d1701
4 changed files with 61 additions and 46 deletions

View file

@ -119,47 +119,57 @@ def validate(cfg: Config) -> None:
cfg.vocabulary.terms = _validate_terms(cfg.vocabulary.terms)
def _from_dict(data: dict[str, Any], cfg: Config) -> Config:
has_sections = any(
key in data
for key in (
"daemon",
"recording",
"stt",
"injection",
"vocabulary",
)
_reject_unknown_keys(
data,
{"daemon", "recording", "stt", "injection", "vocabulary"},
parent="",
)
if has_sections:
daemon = _ensure_dict(data.get("daemon"), "daemon")
recording = _ensure_dict(data.get("recording"), "recording")
stt = _ensure_dict(data.get("stt"), "stt")
injection = _ensure_dict(data.get("injection"), "injection")
vocabulary = _ensure_dict(data.get("vocabulary"), "vocabulary")
daemon = _ensure_dict(data.get("daemon"), "daemon")
recording = _ensure_dict(data.get("recording"), "recording")
stt = _ensure_dict(data.get("stt"), "stt")
injection = _ensure_dict(data.get("injection"), "injection")
vocabulary = _ensure_dict(data.get("vocabulary"), "vocabulary")
if "hotkey" in daemon:
cfg.daemon.hotkey = _as_nonempty_str(daemon["hotkey"], "daemon.hotkey")
if "input" in recording:
cfg.recording.input = _as_recording_input(recording["input"])
if "model" in stt:
cfg.stt.model = _as_nonempty_str(stt["model"], "stt.model")
if "device" in stt:
cfg.stt.device = _as_nonempty_str(stt["device"], "stt.device")
if "backend" in injection:
cfg.injection.backend = _as_nonempty_str(injection["backend"], "injection.backend")
if "remove_transcription_from_clipboard" in injection:
cfg.injection.remove_transcription_from_clipboard = _as_bool(
injection["remove_transcription_from_clipboard"],
"injection.remove_transcription_from_clipboard",
)
if "replacements" in vocabulary:
cfg.vocabulary.replacements = _as_replacements(vocabulary["replacements"])
if "terms" in vocabulary:
cfg.vocabulary.terms = _as_terms(vocabulary["terms"])
return cfg
_reject_unknown_keys(daemon, {"hotkey"}, parent="daemon")
_reject_unknown_keys(recording, {"input"}, parent="recording")
_reject_unknown_keys(stt, {"model", "device"}, parent="stt")
_reject_unknown_keys(
injection,
{"backend", "remove_transcription_from_clipboard"},
parent="injection",
)
_reject_unknown_keys(vocabulary, {"replacements", "terms"}, parent="vocabulary")
if "hotkey" in daemon:
cfg.daemon.hotkey = _as_nonempty_str(daemon["hotkey"], "daemon.hotkey")
if "input" in recording:
cfg.recording.input = _as_recording_input(recording["input"])
if "model" in stt:
cfg.stt.model = _as_nonempty_str(stt["model"], "stt.model")
if "device" in stt:
cfg.stt.device = _as_nonempty_str(stt["device"], "stt.device")
if "backend" in injection:
cfg.injection.backend = _as_nonempty_str(injection["backend"], "injection.backend")
if "remove_transcription_from_clipboard" in injection:
cfg.injection.remove_transcription_from_clipboard = _as_bool(
injection["remove_transcription_from_clipboard"],
"injection.remove_transcription_from_clipboard",
)
if "replacements" in vocabulary:
cfg.vocabulary.replacements = _as_replacements(vocabulary["replacements"])
if "terms" in vocabulary:
cfg.vocabulary.terms = _as_terms(vocabulary["terms"])
return cfg
def _reject_unknown_keys(value: dict[str, Any], allowed: set[str], *, parent: str) -> None:
for key in value.keys():
if key in allowed:
continue
field = f"{parent}.{key}" if parent else key
raise ValueError(f"unknown config field: {field}")
def _ensure_dict(value: Any, field_name: str) -> dict[str, Any]:
if value is None:
return {}