TECHPARTNER CONSULTING

Codester demo · Scripts & Code → Python

CSV to Airtable Sync — Dry-Run First, Every Time

CSV to Airtable sync with dry-run first: validation, field mapping, rejection report, upserts only on --commit.

$12 on CodesterUnit tests: 9 passedDry run below: real, on the bundled sample file

The sample file

The package includes a sample CSV and config so you can see the whole loop with no Airtable account: 2 valid rows and 2 intentional rejections. sample_customers.csv, as shipped:

customer_idnameemailmonthly_spendactiveDry-run verdict
C-1001Acme Fitnessops@acme.example1200.50trueValid
C-1002Northwind Studioowner@northwind.example775yesValid
C-1003(missing)missing-name@example.com500trueRejected — missing required value: name
C-1002Duplicate Studioduplicate@example.com100falseRejected — duplicate key in CSV: C-1002

The field-mapping config (sample_config.json)

{
  "key_column": "customer_id",
  "key_field": "External ID",
  "field_mapping": {
    "customer_id": "External ID",
    "name": "Customer Name",
    "email": "Email",
    "monthly_spend": "Monthly Spend",
    "active": "Active"
  },
  "required": ["customer_id", "name", "email"],
  "types": {
    "monthly_spend": "number",
    "active": "boolean"
  }
}

The dry run — nothing is written

Dry-run is the default: the whole file is validated first and nothing touches Airtable until --commit is added — and a commit refuses the entire file if even one row is rejected. Here is the actual dry run on the sample: the summary it prints, and the rejections.jsonl it writes, with a row-level reason for each rejected row.

$ python3 sync.py sample_customers.csv --config sample_config.json
{
  "valid": 2,
  "rejected": 2,
  "committed": false
}
exit code: 0

--- rejections.jsonl (written by the dry run) ---
{"reason": "missing required value: name", "row": {"active": "true", "customer_id": "C-1003", "email": "missing-name@example.com", "monthly_spend": "500", "name": ""}, "row_number": 4}
{"reason": "duplicate key in CSV: C-1002", "row": {"active": "false", "customer_id": "C-1002", "email": "duplicate@example.com", "monthly_spend": "100", "name": "Duplicate Studio"}, "row_number": 5}

From the package

Screenshots shipped inside the Codester package.

CSV to Airtable Sync output, from the package's own screenshots.

What it does