Integrate PR45: Remove trailing null values for proper ApexCharts header display

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-01 01:36:08 +00:00
parent b790ee1f6c
commit 662a51e20f
2 changed files with 72 additions and 0 deletions

View file

@ -580,6 +580,12 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091
)
)
# Remove trailing null values from chart_data (for proper ApexCharts header display).
# Internal nulls at segment boundaries are preserved for gap visualization.
# Only trailing nulls cause issues with in_header showing "N/A".
while chart_data and chart_data[-1].get(price_field) is None:
chart_data.pop()
# Convert to array of arrays format if requested
if output_format == "array_of_arrays":
array_fields_template = call.data.get("array_fields")

View file

@ -159,3 +159,69 @@ class TestPriceConversion:
round_decimals = 2
final = round(converted, round_decimals)
assert final == 0.12, "Should round to 2 decimal places"
class TestTrailingNullRemoval:
"""Test trailing null value removal for ApexCharts header display."""
def test_trailing_nulls_removed(self) -> None:
"""Test that trailing null values are removed from chart_data."""
price_field = "price_per_kwh"
chart_data = [
{"start_time": "2025-12-01T00:00:00", price_field: 10.0},
{"start_time": "2025-12-01T00:15:00", price_field: 12.0},
{"start_time": "2025-12-01T00:30:00", price_field: None}, # Trailing null
{"start_time": "2025-12-01T00:45:00", price_field: None}, # Trailing null
]
# Simulate the trailing null removal logic
while chart_data and chart_data[-1].get(price_field) is None:
chart_data.pop()
assert len(chart_data) == 2, "Should have 2 items after removing trailing nulls"
assert chart_data[-1][price_field] == 12.0, "Last item should be the last non-null price"
def test_internal_nulls_preserved(self) -> None:
"""Test that internal null values are preserved for gap visualization."""
price_field = "price_per_kwh"
chart_data = [
{"start_time": "2025-12-01T00:00:00", price_field: 10.0},
{"start_time": "2025-12-01T00:15:00", price_field: None}, # Internal null (gap)
{"start_time": "2025-12-01T00:30:00", price_field: 12.0},
{"start_time": "2025-12-01T00:45:00", price_field: None}, # Trailing null
]
# Simulate the trailing null removal logic
while chart_data and chart_data[-1].get(price_field) is None:
chart_data.pop()
assert len(chart_data) == 3, "Should have 3 items after removing trailing null"
assert chart_data[1][price_field] is None, "Internal null should be preserved"
assert chart_data[-1][price_field] == 12.0, "Last item should be the last non-null price"
def test_no_nulls_unchanged(self) -> None:
"""Test that chart_data without trailing nulls is unchanged."""
price_field = "price_per_kwh"
chart_data = [
{"start_time": "2025-12-01T00:00:00", price_field: 10.0},
{"start_time": "2025-12-01T00:15:00", price_field: 12.0},
]
original_length = len(chart_data)
# Simulate the trailing null removal logic
while chart_data and chart_data[-1].get(price_field) is None:
chart_data.pop()
assert len(chart_data) == original_length, "Data without trailing nulls should be unchanged"
def test_empty_data_handled(self) -> None:
"""Test that empty chart_data is handled without error."""
price_field = "price_per_kwh"
chart_data: list[dict] = []
# Simulate the trailing null removal logic - should not raise
while chart_data and chart_data[-1].get(price_field) is None:
chart_data.pop()
assert chart_data == [], "Empty data should remain empty"