diff --git a/src/instrumentserver/config.py b/src/instrumentserver/config.py index f30d874..92bb950 100644 --- a/src/instrumentserver/config.py +++ b/src/instrumentserver/config.py @@ -47,6 +47,17 @@ def loadConfig( yaml = ruamel.yaml.YAML() rawConfig = yaml.load(configPath) + # ruamel.yaml returns ``None`` for an empty (or comments-only) config + # file. The membership test on the next line would then raise an opaque + # ``TypeError: argument of type 'NoneType' is not iterable``, so we + # surface a descriptive error that matches the style of the missing-key + # message below. + if rawConfig is None: + raise AttributeError( + f"The config file '{configPath}' is empty. " + "It needs at least an 'instruments:' section." + ) + if "instruments" not in rawConfig: raise AttributeError( "All configurations must be inside the 'instruments' field. " diff --git a/test/pytest/test_config.py b/test/pytest/test_config.py index 1a4e6e1..fce70b4 100644 --- a/test/pytest/test_config.py +++ b/test/pytest/test_config.py @@ -177,6 +177,39 @@ def test_missing_instruments_key_raises(tmp_path): loadConfig(cfg) +# --------------------------------------------------------------------------- +# Error: empty / comments-only config file +# --------------------------------------------------------------------------- + + +def test_empty_config_raises(tmp_path): + """An empty config file must not crash with an opaque TypeError.""" + cfg = _write_config(tmp_path, "") + with pytest.raises(AttributeError, match="empty"): + loadConfig(cfg) + + +def test_comments_only_config_raises(tmp_path): + """A config file that contains only comments also parses to ``None``.""" + cfg = _write_config( + tmp_path, + """\ +# this file is intentionally just comments +# nothing else +""", + ) + with pytest.raises(AttributeError, match="empty"): + loadConfig(cfg) + + +def test_empty_config_error_mentions_instruments(tmp_path): + """The empty-config error should guide the user toward the required key.""" + cfg = _write_config(tmp_path, "") + with pytest.raises(AttributeError) as excinfo: + loadConfig(cfg) + assert "instruments" in str(excinfo.value) + + # --------------------------------------------------------------------------- # pollingRate # ---------------------------------------------------------------------------