Explain ragged CSV rows with record-level evidence

Quick answer

csv.reader yields a sequence for each record and does not impose a table width.

Example

The fixture compares each record length with the header length and prints record number, expected width, and actual width. It deliberately reports both a long row and a short row instead of padding or truncating either one.

import csv, io, json
rows = list(csv.reader(io.StringIO('id,name\n1,A\n2,B,x\n3\n')))
findings = [{'record': n, 'expected': 2, 'actual': len(row)} for n, row in enumerate(rows[1:], 2) if len(row) != 2]
assert findings == [{'record': 3, 'expected': 2, 'actual': 3}, {'record': 4, 'expected': 2, 'actual': 1}]
print(json.dumps(findings, separators=(',', ':')))

Expected stdout:

[{"record":3,"expected":2,"actual":3},{"record":4,"expected":2,"actual":1}]

Reading the result

If the export permits a trailing optional field, express that as an explicit schema version. A width mismatch alone cannot tell a validator which interpretation is intended.

Use parser record numbers rather than file-line numbers in this report. A quoted value can span physical lines, so those two coordinates have different meanings in a CSV investigation.

The expected width comes from the first parsed record only after that record has been accepted as the header. A preamble needs an explicit rule before it can serve that role.

Sources

- Python csv module documentation

Prepared with AI assistance. The example uses synthetic data; its stated limits apply.

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic