main()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
3
"""Generates GeoJSON to map millage data to parks on OpenStreetMap.
4
5
Usage:
6
  main.py <path> [--verbose] [--debug]
7
8
Options:
9
  --verbose   Enable verbose logging.
10
  --debug     Use a smaller data set to fail faster.
11
12
"""
13
14
import sys
15
import csv
16
import json
17
18
import log
19
from docopt import docopt
20
21
from parks import reader, finder
22
23
24
OUTPUT_CSV = "parks.csv"
25
OUTPUT_OSM_JSON = "parks.osm_json"
26
27
28
def main(argv=None):
29
    """Parse arguments and run the program."""
30
31
    # Parse arguments
32
    arguments = docopt(__doc__, argv=argv or sys.argv[1:])
33
    verbose = arguments.get('--verbose')
34
    debug = arguments.get('--debug')
35
    input_csv_path = arguments['<path>']
36
37
    # Configure logging
38
    log.init(debug=verbose)
39
40
    # Run the program
41
    success = run(input_csv_path, OUTPUT_CSV, OUTPUT_OSM_JSON, debug=debug)
42
43
    if not success:
44
        sys.exit(1)
45
46
47
def run(input_csv_path, output_csv_path, output_osm_json_path, debug=False):
48
    """Merge the input data with OpenStreetMap data."""
49
50
    success = True
51
52
    # Read the input millage data
53
    millage_parks = reader.read(input_csv_path)
54
55
    # Find all parks on OSM
56
    osm_points = finder.find(debug=debug)
57
    osm_parks = {}
58
    for point in osm_points:
59
        if point['type'] in ('way', 'relation'):
60
            data = point['data']
61
            name = data['tag'].get('name', '<unknown>')
62
            osm_parks[name] = data
63
64
    # Display the difference between both park lists
65
    for name in millage_parks:
66
        if name not in osm_parks:
67
            log.warning("missing park on OSM: %s", name)
68
    for name in osm_parks:
69
        if name not in millage_parks:
70
            log.warning("missing park in CSV: %s", name)
71
72
    # Write the relevant OSM data to a flat file
73
    log.info("writing %s...", output_csv_path)
74
    with open(output_csv_path, 'w', newline='') as csvfile:
75
        csvwriter = csv.writer(csvfile)
76
        for park in osm_parks.values():
77
            csvwriter.writerow([park['id'], park['tag'].get('name')])
78
79
    # Generate new OSM JSON parks data with millage information
80
    modified_osm_points = []
81
    for point in osm_points:
82
        name = point['data']['tag'].get('name')
83
        if name:
84
            if name not in millage_parks:
85
                log.info("skipped untagged: %s", name)
86
                continue
87
            if point['type'] in ('way', 'relation'):
88
                point['data']['tag'] = dict(leisure='park')
89
                millage_park_data = millage_parks[name]
90
                for key, value in millage_park_data.items():
91
                    point['data']['tag'][key.lower()] = value
92
                log.info("tags added to park: %s", name)
93
        # map to names expected for GeoJSON
94
        point2 = {}
95
        point2['type'] = point['type']
96
        point2.update(point['data'])
97
        point2['nodes'] = point2.pop('nd', {})
98
        point2['tags'] = point2.pop('tag', {})
99
        modified_osm_points.append(point2)
100
101
    # Write the modified OSM data to an OSM JSON file
102
    log.info("writing %s...", output_osm_json_path)
103
    with open(output_osm_json_path, 'w') as osm_json_file:
104
        modified_osm_data = {'elements': modified_osm_points}
105
        modified_osm_json = json.dumps(modified_osm_data, indent='  ')
106
        osm_json_file.write(modified_osm_json)
107
108
    return success or debug
109
110
111
if __name__ == '__main__':
112
    main()
113