|
1 | 1 | import petl as etl |
2 | 2 |
|
| 3 | + |
3 | 4 | def create_ward(row): |
| 5 | + # Incoming data like: "21-20 DEM" |
4 | 6 | return int(row['ward_div'].split('-')[0].lstrip('0')) |
5 | 7 |
|
| 8 | + |
6 | 9 | def create_division(row): |
7 | 10 | # Delete "DEM" or "REP" from the end of the name |
8 | 11 | # Get characters after -, trim leading zeros, convert to int |
9 | 12 | return int(row['ward_div'].split('-')[1].lstrip('0').strip('DEM').strip('REP')) |
10 | 13 |
|
| 14 | + |
11 | 15 | def process_committee(filepath): |
12 | 16 | table = etl.fromcsv(filepath) \ |
13 | 17 | .rename({'Race': 'ward_div', |
14 | 18 | 'Party': 'party', |
15 | 19 | 'Name': 'fullName', |
16 | | - 'Add1': 'address', |
| 20 | + 'Address': 'address', |
17 | 21 | 'Zip': 'zip'}) \ |
18 | 22 | .cut('ward_div', 'party', 'fullName', |
19 | 23 | 'address', 'zip') \ |
20 | | - .convert({'fullName': 'title', |
21 | | - 'address': 'title'}) \ |
22 | | - .convert('party', 'lower') \ |
| 24 | + .convert({'ward_div': 'strip', |
| 25 | + 'fullName': lambda v: v.strip().title(), |
| 26 | + 'address': lambda v: v.strip().title(), |
| 27 | + 'zip': 'strip'}) \ |
| 28 | + .convert('party', lambda v: v.strip().lower()) \ |
23 | 29 | .addfield('ward', create_ward, index=0) \ |
24 | | - .addfield('division', create_division, index=1) \ |
25 | | - .cutout('ward_div') |
26 | | - |
27 | | - return table |
| 30 | + .addfield('division', create_division, index=1) |
| 31 | + |
| 32 | + # Assign the A/B suffix in a single deterministic pass over the |
| 33 | + # materialized rows. petl re-invokes row functions an unspecified number |
| 34 | + # of times (tables are lazy and re-iterable), so the first-seen suffix |
| 35 | + # cannot be derived from mutable state inside a petl transform -- doing so |
| 36 | + # makes every row 'B'. Build the IDs here instead. |
| 37 | + seen = set() |
| 38 | + rows = [] |
| 39 | + for rec in etl.dicts(table): |
| 40 | + wd = rec['ward_div'] |
| 41 | + suffix = 'A' if wd not in seen else 'B' |
| 42 | + seen.add(wd) |
| 43 | + rec['ID'] = (wd + ' ' + suffix).replace(' ', '-') |
| 44 | + rows.append(rec) |
| 45 | + |
| 46 | + return etl.fromdicts(rows) \ |
| 47 | + .cut('ID', 'ward', 'division', 'party', 'fullName', 'address', 'zip') |
0 commit comments