from collections import OrderedDict import json import requests class SearchError(Exception): pass def lookup_with_params(**kwargs): url = "http://nominatim.openstreetmap.org/search" params = { "format": "jsonv2", "addressdetails": 1, "extratags": 1, "limit": 30, "namedetails": 1, "accept-language": "en", "polygon_text": 0, } params.update(kwargs) r = requests.get(url, params=params) if r.status_code == 500: raise SearchError try: return json.loads(r.text, object_pairs_hook=OrderedDict) except json.decoder.JSONDecodeError: raise SearchError(r) def lookup(q): return lookup_with_params(q=q) def get_us_county(county, state): if " " not in county and "county" not in county: county += " county" results = lookup(q="{}, {}".format(county, state)) def pred(hit): return ( "osm_type" in hit and hit["osm_type"] != "node" and county in hit["display_name"].lower() ) return next(filter(pred, results), None) def get_us_city(name, state): results = lookup_with_params(city=name, state=state) if len(results) != 1: results = [ hit for hit in results if hit["type"] == "city" or hit["osm_type"] == "node" ] if len(results) != 1: print("more than one") return hit = results[0] if hit["type"] not in ("administrative", "city"): print("not a city") return if hit["osm_type"] == "node": print("node") return if not hit["display_name"].startswith(name): print("wrong name") return assert "osm_type" in hit and "osm_id" in hit and "geotext" in hit return hit def get_hit_name(hit): address = hit.get("address") if not address: return hit["display_name"] address_values = list(address.values()) n1 = address_values[0] if len(address) == 1: return n1 country = address.pop("country", None) country_code = address.pop("country_code", None) if country_code: country_code == country_code.lower() if country_code == "us" and "state" in address: state = address["state"] return f"{n1}, {state}, USA" if country_code == "gb": country = "UK" if len(address) == 1: return f"{n1}, {country}" else: n2 = address_values[1] return f"{n1}, {n2}, {country}" def get_hit_label(hit): tags = hit["extratags"] designation = tags.get("designation") category = hit["category"] hit_type = hit["type"] if designation: return designation.replace("_", " ") if category == "boundary" and hit_type == "administrative": place = tags.get("place") or tags.get("linked_place") if place: return f"{place} {category}" if category == "place": return f"{hit_type}" return f"{hit_type} {category}"