Return clear exit statuses from a CSV preflight check

Quick answer

Give a CSV preflight distinct statuses for a clean file, a completed check that found a contract mismatch, and input that could not be parsed. A shell caller can continue on 0, collect a reviewable finding on 2, and stop on 3 because the parser never completed. The numbers are a local command contract, not csv defaults.

Example

preflight parses actual CSV text with csv.reader and strict=True. It accepts an exact id,email header and two-field data rows. A different header becomes a completed finding, while the unclosed quoted field makes the strict reader raise csv.Error and becomes an input error. The assertions exercise all three outcomes.

import csv
import io

CLEAN = 0
FINDINGS = 2
INPUT_ERROR = 3


def preflight(text):
    try:
        rows = list(csv.reader(io.StringIO(text, newline=""), strict=True))
    except csv.Error:
        return INPUT_ERROR

    if not rows or rows[0] != ["id", "email"]:
        return FINDINGS
    if any(len(row) != 2 for row in rows[1:]):
        return FINDINGS
    return CLEAN


assert preflight("id,email\n1,a@example.test\n") == CLEAN
assert preflight("id,name\n1,A\n") == FINDINGS
assert preflight('id,email\n1,"open\n') == INPUT_ERROR
print("clean=0 findings=2 input-error=3")

Expected stdout:

clean=0 findings=2 input-error=3

Reading the result

The FINDINGS status means the source was readable but did not meet this small contract. It should not be used for an exception that prevented complete validation, because a batch loop could otherwise treat a partial result as safe to review or import. For an executable CLI, return the selected value from main through SystemExit; the pure function here keeps all normal and failure cases runnable in one deterministic example.

This preflight deliberately checks only parser syntax, one header, and row width. It does not validate email syntax, decoding, duplicate IDs, or report-file writes. Allocate separate stable codes only when callers need to distinguish those failure classes.

Sources

- Python csv.reader documentation

- Python csv Dialect.strict 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