Recipe 02 / CSV to JSON

CSV in. Clean JSON out.

This recipe converts a header-based CSV into a JSON array. It preserves values as strings, including identifiers with leading zeroes, and writes the result to standard output.

Result: One JSON arrayGo to method
  1. Prepare a small fixture

    Use the sample below with a header and two records. Keep column names unique and non-empty. Save the converter as csv_to_json.py in the same folder. The standard-library CSV parser understands quoted fields; splitting each line on commas would incorrectly break a value that contains a quoted comma.

  2. Run the conversion

    Run python csv_to_json.py sample.csv. The script reads UTF-8 text, accepts a byte-order mark, and checks that each record has the header's field count. It leaves the source file untouched. Numbers remain strings deliberately; type conversion belongs in a separate step with explicit rules for each column.

  3. Inspect the result and the failure

    Compare the result with the expected array, then add an extra column to one record and rerun. The converter should report an error and exit with status 2 without emitting partial JSON. A header-only file produces an empty array. This small recipe loads the data into memory, so plan a streaming approach for very large exports.

csv_to_json.py

import csv
import json
import sys

def convert(path):
    with open(path, encoding="utf-8-sig", newline="") as source:
        reader = csv.reader(source, strict=True)
        headers = next(reader, None)
        if not headers or any(not name.strip() for name in headers):
            raise ValueError("A non-empty header is required")
        if len(set(headers)) != len(headers):
            raise ValueError("Header names must be unique")
        rows = []
        for values in reader:
            if len(values) != len(headers):
                raise ValueError(f"Field count mismatch near line {reader.line_num}")
            rows.append(dict(zip(headers, values)))
        return rows

if __name__ == "__main__":
    if len(sys.argv) != 2:
        raise SystemExit("Usage: python csv_to_json.py sample.csv")
    try:
        result = convert(sys.argv[1])
    except (OSError, ValueError, csv.Error, UnicodeError) as error:
        print(f"Conversion failed: {error}", file=sys.stderr)
        raise SystemExit(2)
    print(json.dumps(result, ensure_ascii=False, indent=2))

Input: sample.csv

name,count
Ada,2
Lin,3

Expected result

[
  {"name": "Ada", "count": "2"},
  {"name": "Lin", "count": "3"}
]

Run the recipe

python csv_to_json.py sample.csv

The serving check

The two names and counts match the fixture, the source file is unchanged, and a malformed row fails visibly.

Next at the counterTest batch