diff --git a/src/datasight/config.py b/src/datasight/config.py index bffa975..a636b99 100644 --- a/src/datasight/config.py +++ b/src/datasight/config.py @@ -265,6 +265,11 @@ def load_example_queries(path: str | None, project_dir: str) -> list[dict[str, A except yaml.YAMLError as e: logger.warning(f"Failed to parse {path}: {e}") return [] + if data is None: + # Empty or comment-only YAML — yaml.safe_load returns None. + # `datasight generate` writes such scaffolds when nothing is detected, + # so treat this as an empty config rather than warning on every load. + return [] if not isinstance(data, list): logger.warning(f"Expected a list in {path}, got {type(data).__name__}") return [] @@ -300,6 +305,11 @@ def load_measure_overrides(path: str | None, project_dir: str) -> list[dict[str, except yaml.YAMLError as e: logger.warning(f"Failed to parse {path}: {e}") return [] + if data is None: + # Empty or comment-only YAML — yaml.safe_load returns None. + # `datasight generate` writes such scaffolds when nothing is detected, + # so treat this as an empty config rather than warning on every load. + return [] if not isinstance(data, list): logger.warning(f"Expected a list in {path}, got {type(data).__name__}") return [] @@ -436,6 +446,11 @@ def load_time_series_config(path: str | None, project_dir: str) -> list[dict[str except yaml.YAMLError as e: logger.warning(f"Failed to parse {path}: {e}") return [] + if data is None: + # Empty or comment-only YAML — yaml.safe_load returns None. + # `datasight generate` writes such scaffolds when nothing is detected, + # so treat this as an empty config rather than warning on every load. + return [] if not isinstance(data, list): logger.warning(f"Expected a list in {path}, got {type(data).__name__}") return [] @@ -490,6 +505,11 @@ def load_joins_config(path: str | None, project_dir: str) -> list[dict[str, Any] except yaml.YAMLError as e: logger.warning(f"Failed to parse {path}: {e}") return [] + if data is None: + # Empty or comment-only YAML — yaml.safe_load returns None. + # `datasight generate` writes such scaffolds when nothing is detected, + # so treat this as an empty config rather than warning on every load. + return [] if not isinstance(data, list): logger.warning(f"Expected a list in {path}, got {type(data).__name__}") return [] diff --git a/src/datasight/validation.py b/src/datasight/validation.py index c999acd..bc721e7 100644 --- a/src/datasight/validation.py +++ b/src/datasight/validation.py @@ -42,6 +42,9 @@ def load_validation_config( except yaml.YAMLError as e: logger.warning(f"Failed to parse {path}: {e}") return [] + if data is None: + # Empty or comment-only YAML — yaml.safe_load returns None. + return [] if not isinstance(data, list): logger.warning(f"Expected a list in {path}, got {type(data).__name__}") return [] diff --git a/tests/test_config_extra.py b/tests/test_config_extra.py index 62a85a0..07da11d 100644 --- a/tests/test_config_extra.py +++ b/tests/test_config_extra.py @@ -253,10 +253,39 @@ def test_load_time_series_config_invalid_yaml(tmp_path): assert load_time_series_config(None, str(tmp_path)) == [] +def _capture_loguru_warnings(): + """Datasight uses loguru, which bypasses pytest's caplog by default.""" + from loguru import logger as _logger + + captured: list[str] = [] + sink_id = _logger.add(lambda msg: captured.append(str(msg)), level="WARNING") + return captured, lambda: _logger.remove(sink_id) + + def test_load_time_series_config_non_list(tmp_path): p = tmp_path / "time_series.yaml" p.write_text("foo: bar\n", encoding="utf-8") - assert load_time_series_config(None, str(tmp_path)) == [] + captured, cleanup = _capture_loguru_warnings() + try: + assert load_time_series_config(None, str(tmp_path)) == [] + finally: + cleanup() + # Genuine wrong-shape input still warns. + assert any("Expected a list" in line for line in captured) + + +def test_load_time_series_config_comment_only_is_silent(tmp_path): + """An all-comments scaffold (what `datasight generate` writes when it + finds no timestamp candidates) parses to None — treat as empty silently + rather than warning on every load.""" + p = tmp_path / "time_series.yaml" + p.write_text("# datasight time series declarations\n# nothing detected\n", encoding="utf-8") + captured, cleanup = _capture_loguru_warnings() + try: + assert load_time_series_config(None, str(tmp_path)) == [] + finally: + cleanup() + assert not any("Expected a list" in line for line in captured) def test_load_time_series_config_valid_and_invalid_entries(tmp_path):