From 7489c14455fdc556b8700807b8fa5d9bb73f9d7a Mon Sep 17 00:00:00 2001 From: Al Date: Fri, 15 Jul 2016 19:50:22 -0400 Subject: [PATCH] [osm] Adding method for overriding per-country boundary types (either by id or containing polygon) --- .../geodata/neighborhoods/reverse_geocode.py | 2 +- scripts/geodata/osm/components.py | 56 ++++++++++++++----- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/scripts/geodata/neighborhoods/reverse_geocode.py b/scripts/geodata/neighborhoods/reverse_geocode.py index 4fcc7265..96048ef7 100644 --- a/scripts/geodata/neighborhoods/reverse_geocode.py +++ b/scripts/geodata/neighborhoods/reverse_geocode.py @@ -339,7 +339,7 @@ class NeighborhoodReverseGeocoder(RTreePolygonIndex): if name and name == attrs.get('name'): continue - containing_component = osm_components.get_first_component(country, props) + containing_component = osm_components.component_from_properties(country, props) if containing_component != AddressFormatter.SUBURB: skip_node = True diff --git a/scripts/geodata/osm/components.py b/scripts/geodata/osm/components.py index 7bf46832..4cbeff9d 100644 --- a/scripts/geodata/osm/components.py +++ b/scripts/geodata/osm/components.py @@ -21,7 +21,7 @@ class OSMAddressComponents(object): ADMIN_LEVEL = 'admin_level' - # These keys are country-independent + # These keys override country-level global_keys = { 'place': { 'country': AddressFormatter.COUNTRY, @@ -55,24 +55,54 @@ class OSMAddressComponents(object): data = yaml.load(open(os.path.join(boundaries_dir, filename))) for prop, values in six.iteritems(data): for k, v in values.iteritems(): - if v not in AddressFormatter.address_formatter_fields: + if isinstance(v, six.string_types) and v not in AddressFormatter.address_formatter_fields: raise ValueError(u'Invalid value in {} for prop={}, key={}: {}'.format(filename, prop, k, v)) self.config[country_code] = data - def get_component(self, country, prop, value): - if prop in self.global_keys: - props = self.global_keys[prop] - else: + def component(self, country, prop, value): + props = self.global_keys.get(prop, {}) + if not props: props = self.config.get(country, {}).get(prop, {}) return props.get(value, None) - def get_first_component(self, country, properties): - for k, v in six.iteritems(props): - containing_component = self.get_component(country, k, v) - break - else: - containing_component = None - return containing_component + def component_from_properties(self, country, properties, containing=()): + country_config = self.config.get(country, {}) + config = country_config + + overrides = country_config.get('overrides') + if overrides: + id_overrides = overrides.get('id', {}) + element_type = properties.get('type') + element_id = properties.get('id') + + override_value = id_overrides.get(element_type, {}).get(six.binary_type(element_id or ''), None) + if override_value: + return override_value + + contained_by_overrides = overrides.get('contained_by') + if contained_by_overrides and containing: + # Note, containing should be passed in from smallest to largest + for containing_type, containing_id in containing: + config_updates = contained_by_overrides.get(containing_type, {}).get(six.binary_type(containing_id or ''), None) + print contained_by_overrides + if config_updates: + config.update(config_updates) + break + + for k, v in six.iteritems(properties): + containing_component = self.global_keys.get(k, {}).get(v, None) + + if containing_component is not None: + return containing_component + + for k, v in six.iteritems(properties): + if containing_component is None: + containing_component = config.get(k, {}).get(v, None) + + if containing_component is not None: + return containing_component + + return None osm_address_components = OSMAddressComponents()