Files
troupe-standup/wizard-work/ledger/check_countries.py
T

81 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""Structural verifier for the countries extraction table.
Usage:
python3 check_countries.py <csv_path> <expected_rows>
Exits 0 iff the CSV satisfies the contract:
- header is exactly the 14-column contract (see HEADERS)
- every data row has exactly 14 fields
- alpha-2 codes are unique and there are exactly expected_rows rows
Exits 1 with a detailed message otherwise. The exit code IS the verdict:
0 = correct, nonzero = wrong.
"""
import csv
import sys
EXPECTED_HEADER = [
'name_common', 'name_official', 'alpha2', 'alpha3', 'numeric',
'region', 'subregion', 'capital', 'population', 'area_km2',
'currencies', 'languages', 'tlds', 'flag',
]
def main():
if len(sys.argv) != 3:
sys.stderr.write('usage: check_countries.py <csv_path> <expected_rows>\n')
return 2
csv_path, expected_raw = sys.argv[1], sys.argv[2]
try:
expected = int(expected_raw)
except ValueError:
sys.stderr.write('expected_rows must be an integer\n')
return 2
try:
fh = open(csv_path, encoding='utf-8')
except OSError as exc:
sys.stderr.write('cannot open %s: %s\n' % (csv_path, exc))
return 1
with fh:
reader = csv.reader(fh)
try:
header = next(reader)
except StopIteration:
sys.stderr.write('CSV is empty\n')
return 1
if header != EXPECTED_HEADER:
sys.stderr.write('bad header: %r\n' % header)
return 1
rows = list(reader)
codes = []
for index, row in enumerate(rows, start=2):
if len(row) != len(EXPECTED_HEADER):
sys.stderr.write('row %d has %d fields (expected %d)\n'
% (index, len(row), len(EXPECTED_HEADER)))
return 1
codes.append(row[2])
seen = set()
duplicates = []
for code in codes:
if code in seen:
duplicates.append(code)
seen.add(code)
ok = True
if len(rows) != expected:
sys.stderr.write('row count %d != expected %d\n'
% (len(rows), expected))
ok = False
if duplicates:
sys.stderr.write('duplicate alpha-2 codes: %r\n' % sorted(duplicates))
ok = False
print('rows=%d fields=%d unique_alpha2=%d header_ok=True'
% (len(rows), len(header), len(seen)))
return 0 if ok else 1
if __name__ == '__main__':
sys.exit(main())