Skip to content

Commit af137d2

Browse files
authored
Quote CSV fields containing commas in CLI output (#305)
The CLI's `csv` output built each row with `",".join(...)`, which never quotes fields. An aggregation formula in the `component_id` column (e.g. `COALESCE(#396, 0.0) + COALESCE(#397, 0.0)`) contains commas, so it spilled into extra columns and produced malformed CSV that breaks downstream parsers like csvm. This switches the output to Python's `csv` module so such fields are quoted per RFC 4180. ## Changes - CSV output now uses `csv.writer` instead of manual `",".join(...)`, quoting any field containing commas. - Pin the line terminator to `\n` so output stays LF (the `csv` module defaults to CRLF), matching the previous `print()`-based behavior.
2 parents 4e2d662 + cb2c608 commit af137d2

2 files changed

Lines changed: 10 additions & 5 deletions

File tree

‎RELEASE_NOTES.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414

1515
## Bug Fixes
1616

17-
<!-- Here goes notable bug fixes that are worth a special mention or explanation -->
17+
* The CLI's CSV output now quotes fields containing commas, so aggregation formulae in the `component_id` column no longer break the CSV structure.

‎src/frequenz/client/reporting/cli/__main__.py‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import argparse
77
import asyncio
8+
import csv
9+
import sys
810
from datetime import datetime, timedelta
911
from typing import AsyncIterator
1012

@@ -198,11 +200,14 @@ async def data_iter() -> AsyncIterator[MetricSample]:
198200
print(sample)
199201

200202
elif fmt == "csv":
201-
# Print header
202-
print(",".join(MetricSample._fields))
203-
# Iterate over single metric generator and format as CSV
203+
# Use the csv module so fields containing commas (e.g. aggregation
204+
# formulae in component_id) are quoted per RFC 4180. Keep the LF line
205+
# terminator the previous print()-based output used (csv defaults to
206+
# CRLF).
207+
writer = csv.writer(sys.stdout, lineterminator="\n")
208+
writer.writerow(MetricSample._fields)
204209
async for sample in data_iter():
205-
print(",".join(str(e) for e in sample))
210+
writer.writerow(sample)
206211

207212
else:
208213
raise ValueError(f"Invalid output format: {fmt}")

0 commit comments

Comments
 (0)