MCP-004 — Handle empty data list in generate_vega_spec()
Goal
Prevent generate_vega_spec() from crashing with a KeyError when data is an empty list. Return a user-friendly error message or a graceful empty chart spec instead.
Context
- PR review flagged that
data[0]['date'] raises KeyError when data=[].
- The referenced file path in the review is
src/data360/mcp_server/viz.py (line 142); the actual implementation lives in src/data360/visualization.py and/or src/data360/viz_config.py — confirm exact location before patching.
- Empty data can legitimately occur when an API query returns no results for a given filter combination; callers should receive a clear signal rather than an unhandled exception.
Acceptance criteria
Implementation hints
- Entry point:
src/data360/visualization.py → get_viz_spec() (function starting ~line 183). The _fetch_data_internal() helper at line ~109 already raises ValueError("No data found...") for empty API responses, and get_viz_spec() catches that at line ~243. However, if data reaches downstream spec-building steps (e.g. after filtering in the relevant_fields branch), an empty DataFrame/list can still cause KeyError or IndexError on first-row access.
- Current behavior: When
data is empty after filtering, the code may attempt data[0]['date'] (or an equivalent first-row access) and raise KeyError uncaught.
- Desired behavior: Add a guard immediately after any potential reduction to empty (e.g. after
viz_data = data[valid_cols].copy()) that returns err("Error: No data available after applying the requested filters."). The existing check at line ~439 (if viz_data.empty: return err(...)) provides the pattern to follow.
- Test file:
tests/test_visualization.py — add a test case in the existing TestGetVizSpecDracoFallbackWarning class or a new class. Mock _fetch_data_internal to return a DataFrame that becomes empty after field filtering, and assert the returned dict has url=None and a non-None error.
- Prior art:
_fetch_data_internal() at line ~109 already checks if not raw_data: raise ValueError(...) — follow the same early-exit pattern. The if viz_data.empty: return err(...) guard at line ~439 shows how to do it after cleaning.
- Gotchas: The file path in the original PR review (
src/data360/mcp_server/viz.py) does not exist yet. If a separate viz.py module is created as part of a refactor, place the guard there; otherwise add it to src/data360/visualization.py.
Dependencies
Related
- MCP-002 / MCP-003 — touch the same spec-building pipeline; sequence or coordinate to avoid merge conflicts.
Task file: TODO/MCP-004-viz-empty-data-guard.md
MCP-004 — Handle empty
datalist ingenerate_vega_spec()Goal
Prevent
generate_vega_spec()from crashing with aKeyErrorwhendatais an empty list. Return a user-friendly error message or a graceful empty chart spec instead.Context
data[0]['date']raisesKeyErrorwhendata=[].src/data360/mcp_server/viz.py(line 142); the actual implementation lives insrc/data360/visualization.pyand/orsrc/data360/viz_config.py— confirm exact location before patching.Acceptance criteria
generate_vega_spec()(or equivalent entry point) checks for an emptydatalist before accessingdata[0].test_generate_vega_spec_empty_dataasserts no exception is raised and the return value is well-formed.Implementation hints
src/data360/visualization.py→get_viz_spec()(function starting ~line 183). The_fetch_data_internal()helper at line ~109 already raisesValueError("No data found...")for empty API responses, andget_viz_spec()catches that at line ~243. However, ifdatareaches downstream spec-building steps (e.g. after filtering in therelevant_fieldsbranch), an empty DataFrame/list can still causeKeyErrororIndexErroron first-row access.datais empty after filtering, the code may attemptdata[0]['date'](or an equivalent first-row access) and raiseKeyErroruncaught.viz_data = data[valid_cols].copy()) that returnserr("Error: No data available after applying the requested filters."). The existing check at line ~439 (if viz_data.empty: return err(...)) provides the pattern to follow.tests/test_visualization.py— add a test case in the existingTestGetVizSpecDracoFallbackWarningclass or a new class. Mock_fetch_data_internalto return a DataFrame that becomes empty after field filtering, and assert the returned dict hasurl=Noneand a non-Noneerror._fetch_data_internal()at line ~109 already checksif not raw_data: raise ValueError(...)— follow the same early-exit pattern. Theif viz_data.empty: return err(...)guard at line ~439 shows how to do it after cleaning.src/data360/mcp_server/viz.py) does not exist yet. If a separateviz.pymodule is created as part of a refactor, place the guard there; otherwise add it tosrc/data360/visualization.py.Dependencies
Related
Task file:
TODO/MCP-004-viz-empty-data-guard.md