#!/usr/bin/env python3 """Flatten the REST Countries v3.1 dataset into a clean, flat table. Usage: python3 extract_countries.py Source (raw, from the REST Countries repository): https://raw.githubusercontent.com/restcountries/restcountries/master/src/main/resources/countriesV3.1.json The JSON is an array of 250 country records; this script flattens every record to one CSV row with the fixed 14-column contract below. Columns (order): name_common | name_official | alpha2 | alpha3 | numeric | region | subregion | capital | population | area_km2 | currencies | languages | tlds | flag """ import csv import json import sys def as_text(value): """Empty string for None/empty, plain str otherwise.""" if value is None or value == '': return '' return str(value) def list_join(value): """Join a list of strings with ' | '; empty string for None.""" if value is None: return '' return ' | '.join(str(item) for item in value) def currency_codes(currencies): if not isinstance(currencies, dict): return '' return ' | '.join(sorted(currencies.keys())) def language_codes(languages): if not isinstance(languages, dict): return '' return ' | '.join(sorted(languages.keys())) def flatten(record): name = record.get('name') or {} return [ as_text(name.get('common')), # name_common as_text(name.get('official')), # name_official as_text(record.get('cca2')), # alpha2 as_text(record.get('cca3')), # alpha3 as_text(record.get('ccn3')), # numeric as_text(record.get('region')), # region as_text(record.get('subregion')), # subregion list_join(record.get('capital')), # capital as_text(record.get('population')), # population as_text(record.get('area')), # area_km2 currency_codes(record.get('currencies')), # currencies language_codes(record.get('languages')), # languages list_join(record.get('tld')), # tlds as_text(record.get('flag')), # flag ] HEADERS = [ '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: extract_countries.py \n') return 2 source_path, out_path = sys.argv[1], sys.argv[2] try: with open(source_path, encoding='utf-8') as fh: records = json.load(fh) except (OSError, ValueError) as exc: sys.stderr.write('cannot read source %s: %s\n' % (source_path, exc)) return 1 if not isinstance(records, list): sys.stderr.write('source JSON is not a list\n') return 1 with open(out_path, 'w', encoding='utf-8', newline='') as fh: writer = csv.writer(fh, lineterminator='\n') writer.writerow(HEADERS) for record in records: writer.writerow(flatten(record)) print('records_in: %d' % len(records)) print('wrote: %s' % out_path) return 0 if __name__ == '__main__': sys.exit(main())