
Making a CSV Contract With Your Data Provider in Writing
What to agree with whoever sends you CSV files, as a document plus a manifest your code can check: six deliveries, six different rejections, 193,708 rows.
Take messy CSV, JSON and spreadsheets and land them in tables without losing a row or a character on the way.

What to agree with whoever sends you CSV files, as a document plus a manifest your code can check: six deliveries, six different rejections, 193,708 rows.

A cut-off CSV loaded in pandas without a warning, last row 200000,Ana,Smith,...,2. Check the final byte, the last record's width, quotes, row count and gzip.

April's load failed on qty 1.5, but six columns had drifted. Compare per-column kinds of value between two CSV deliveries, not just inferred types.

Find CSV values missing from a lookup table with an anti-join, keep line numbers right, avoid the NOT IN trap with NULLs and see a foreign key's error.

Check every date in a CSV with a strict parse and a round trip, then ranges. strptime accepted 2025-3-4, DuckDB cast kept the date of 2025-03-14 10:30.

Find repeated ids in a CSV before a primary key rejects the load, with SQL, pandas and uniq -d, line numbers and an exact versus conflicting split.

Validate each CSV row against a pydantic model with types, literals, patterns and a cross-field rule: 193,708 rows in 0.95 s, with file line numbers.

Infer a Table Schema, fix it by hand, add unique, enum and pattern constraints and validate with Frictionless: 10 errors for 8 faults in 193,708 rows.

How many rows does this CSV have? wc -l, awk, csv, pandas and DuckDB gave 7, 8, 7, an error, 4 and 8 on one small file. Count records and field widths.

Validate a CSV delivery in five layers, bytes, structure, schema, values and keys, with line numbers and exit codes: 193,708 rows checked in about a second.

Check every column of a CSV against a regex and report failing rows with file line numbers. fullmatch beats match, and 2025-13-45 passes a date pattern.

A comma inside a number breaks int(), shifts columns when unquoted, and turns European 1.200 into 1.2. Parse strictly, set thousands= and decimal=, and test.
We send one email when a new article is published. No spam.