Let a jsonl export keep a record a value

`--format jsonl` existed, but `_cell` ran json.dumps at row-build time,
before a format was chosen — so a nested value was a string by then and
jsonl only re-escaped it, leaving a consumer against csv's 128KB field
limit either way. Stringifying moved to the csv writer, so csv is
byte-identical and jsonl carries json. The runs TUI followed, or a record
would draw as a Python repr.
This commit is contained in:
2026-08-30 17:36:10 +02:00
parent 4f30430677
commit 65c8cc1eb6
4 changed files with 45 additions and 9 deletions
+18 -8
View File
@@ -406,12 +406,10 @@ def _selected(
def _cell(value: Any) -> Any:
"""A value as a table holds it: a scalar, or JSON when it is not one."""
if hasattr(value, "isoformat"):
return value.isoformat()
if value is None or isinstance(value, (str, int, float, bool)):
return value
return json.dumps(value)
"""A value as a table holds it: a scalar, a date as its ISO string, or a
record kept as one — csv stringifies it at write time; jsonl wants it a
value, not a string full of it."""
return value.isoformat() if hasattr(value, "isoformat") else value
def _leaves(value: Any, prefix: str = "") -> Iterator[tuple[str, Any]]:
@@ -464,13 +462,25 @@ def _drain(buffer: io.StringIO) -> str:
def _csv(columns: list[str], chunks: Iterator[list[dict[str, Any]]]) -> Iterator[str]:
"""Header first, then a chunk at a time through one reused buffer."""
"""Header first, then a chunk at a time through one reused buffer.
A cell that is still a record here — `_cell` leaves one alone for jsonl's
sake — becomes the JSON string a csv cell can hold.
"""
buffer = io.StringIO()
writer = csv.DictWriter(buffer, fieldnames=columns)
writer.writeheader()
yield _drain(buffer)
for chunk in chunks:
writer.writerows(chunk)
writer.writerows(
{
key: value
if value is None or isinstance(value, (str, int, float, bool))
else json.dumps(value)
for key, value in row.items()
}
for row in chunk
)
yield _drain(buffer)