def test_full_geocode__convert_to_block(self): from ebpub.geocoder.base import full_geocode # This block goes up to 298. result = full_geocode('299 S. Wabash Ave.', convert_to_block=True) self.failIf(result['ambiguous']) self.assertEqual(result['type'], 'block') self.assertEqual(result['result']['address'], '200 block of S. Wabash Ave.') # This is also the default behavior. self.assertEqual(result, full_geocode('299 S. Wabash Ave.'))
def geocode(self, location_name, **kwargs): """ Tries to geocode the given location string, returning a Point object or None. Override this if you want to replace with (or fall back to) an external geocoding service. If the result is ambiguous -- multiple matches -- then tries to use optional args to resolve the ambiguity, and if still ambiguous, returns the first remaining result. """ try: result = full_geocode(location_name, guess=True, **kwargs) if result['result']: if result['type'] == 'block' and result.get('ambiguous'): self.logger.debug( "Invalid Block but valid street for %r; results unlikely to be useful, giving up" % location_name) return None return result['result'] except (GeocodingException, ParsingError): self.logger.debug("Could not geocode location: %s: %s" % (location_name, traceback.format_exc())) return None
def geocode(self, location_name, **kwargs): """ Tries to geocode the given location string, returning a Point object or None. Override this if you want to replace with (or fall back to) an external geocoding service. If the result is ambiguous -- multiple matches -- then tries to use optional args to resolve the ambiguity, and if still ambiguous, returns the first remaining result. """ try: result = full_geocode(location_name, guess=True, **kwargs) if result['result']: if result['type'] == 'block' and result.get('ambiguous'): self.logger.debug("Invalid Block but valid street for %r; results unlikely to be useful, giving up" % location_name) return None return result['result'] except (GeocodingException, ParsingError): self.logger.debug( "Could not geocode location: %s: %s" % (location_name, traceback.format_exc())) return None
def test_full_geocode__convert_to_block(self): from ebpub.geocoder.base import full_geocode # This block goes up to 298. result = full_geocode("299 S. Wabash Ave.", convert_to_block=True) self.failIf(result["ambiguous"]) self.assertEqual(result["type"], "block") self.assertEqual(result["result"]["address"], "200 block of S. Wabash Ave.")
def test_full_geocode__bad_block_on_good_street(self): from ebpub.geocoder.base import full_geocode # This block goes up to 298. result = full_geocode('299 S. Wabash Ave.', convert_to_block=False) self.assert_(result['ambiguous']) self.assertEqual(result['type'], 'block') self.assertEqual(result['street_name'], 'Wabash Ave.') self.assertEqual(len(result['result']), 3)
def test_full_geocode__bad_block_on_good_street(self): from ebpub.geocoder.base import full_geocode # This block goes up to 298. result = full_geocode("299 S. Wabash Ave.") self.assert_(result["ambiguous"]) self.assertEqual(result["type"], "block") self.assertEqual(result["street_name"], "Wabash Ave.") self.assertEqual(len(result["result"]), 3)
def _build_geocoder_results(query): results = full_geocode(query) if results['type'] == 'block': return [] if results['ambiguous'] == True: rs = results['result'] else: rs = [results['result']] return [_build_json_result(query, r, results) for r in rs]
def clean(self): self._clean_captcha() cleaned_data = super(NewsItemForm, self).clean() # Reverse-geocode if we need to - eg. user clicked map # but didn't give an address. if not cleaned_data.get('location_name'): if cleaned_data.get('location'): from ebpub.geocoder.reverse import reverse_geocode from ebpub.geocoder.reverse import ReverseGeocodeError try: block, distance = reverse_geocode(cleaned_data['location']) cleaned_data['location_name'] = block.pretty_name except ReverseGeocodeError: logger.info( "Saving NewsItem with no location_name because reverse-geocoding %(location)s failed" % cleaned_data) # Geocode if we can, and need to. # Should not be necessary, but this is groundwork for #284. if not cleaned_data.get('location'): if cleaned_data.get('location_name'): from ebpub.geocoder.base import full_geocode try: geocoded = full_geocode( cleaned_data['location_name'].strip(), guess=True) cleaned_data['location'] = geocoded['result'].location.wkt except (IndexError, KeyError, AttributeError): logger.info( "Saving NewsItem with no location because geocoding %(location_name)s failed" % cleaned_data) # Note, any NewsItem fields that aren't listed in self._meta.fields # have to be manually saved here, because that's the list that's # normally consulted when setting attributes on the instance. # ... And yes, clean() is normally responsible for setting # attributes on the bound instance. for key in forms.fields_for_model(self._meta.model): if key in cleaned_data.keys(): setattr(self.instance, key, cleaned_data[key]) return cleaned_data
def clean(self): self._clean_captcha() cleaned_data = super(NewsItemForm, self).clean() # Reverse-geocode if we need to - eg. user clicked map # but didn't give an address. if not cleaned_data.get('location_name'): if cleaned_data.get('location'): from ebpub.geocoder.reverse import reverse_geocode from ebpub.geocoder.reverse import ReverseGeocodeError try: block, distance = reverse_geocode(cleaned_data['location']) cleaned_data['location_name'] = block.pretty_name except ReverseGeocodeError: logger.info("Saving NewsItem with no location_name because reverse-geocoding %(location)s failed" % cleaned_data) # Geocode if we can, and need to. # Should not be necessary, but this is groundwork for #284. if not cleaned_data.get('location'): if cleaned_data.get('location_name'): from ebpub.geocoder.base import full_geocode try: geocoded = full_geocode(cleaned_data['location_name'].strip(), guess=True) cleaned_data['location'] = geocoded['result'].location.wkt except (IndexError, KeyError, AttributeError): logger.info("Saving NewsItem with no location because geocoding %(location_name)s failed" % cleaned_data) # Note, any NewsItem fields that aren't listed in self._meta.fields # have to be manually saved here, because that's the list that's # normally consulted when setting attributes on the instance. # ... And yes, clean() is normally responsible for setting # attributes on the bound instance. for key in forms.fields_for_model(self._meta.model): if key in cleaned_data.keys(): setattr(self.instance, key, cleaned_data[key]) return cleaned_data
def _geocode_geojson(query): """Geocode a string and return the result as a list of GeoJSON Features. """ if not query: return [] try: res = full_geocode(query) # normalize a bit if not res['ambiguous']: res['result'] = [res['result']] except DoesNotExist: return [] features = [] if res['type'] == 'location': for r in res['result']: feature = { 'type': 'Feature', 'geometry': simplejson.loads(r.location.centroid.geojson), 'properties': { 'type': r.location_type.slug, 'name': r.name, 'city': r.city, 'query': query, } } features.append(feature) elif res['type'] == 'place': for r in res['result']: feature = { 'type': 'Feature', 'geometry': simplejson.loads(r.location.geojson), 'properties': { 'type': 'place', 'name': r.pretty_name, 'address': r.address, 'query': query, } } features.append(feature) elif res['type'] == 'address': for r in res['result']: feature = { 'type': 'Feature', 'geometry': { 'type': 'Point', 'coordinates': [r.lng, r.lat], }, 'properties': { 'type': 'address', 'address': r.get('address'), 'city': r.get('city'), 'state': r.get('state'), 'zip': r.get('zip'), 'query': query } } features.append(feature) # we could get type == 'block', but # ebpub.db.views.ajax_wkt returned nothing for this, # so for now we follow their lead. # elif res['type'] == 'block': # pass return features
def _geocode_geojson(query): if not query: return [] try: res = full_geocode(query) # normalize a bit if not res['ambiguous']: res['result'] = [res['result']] except DoesNotExist: return [] features = [] if res['type'] == 'location': for r in res['result']: feature = { 'type': 'Feature', 'geometry': simplejson.loads(r.location.centroid.geojson), 'properties': { 'type': r.location_type.slug, 'name': r.name, 'city': r.city, 'query': query, } } features.append(feature) elif res['type'] == 'place': for r in res['result']: feature = { 'type': 'Feature', 'geometry': simplejson.loads(r.location.geojson), 'properties': { 'type': 'place', 'name': r.pretty_name, 'address': r.address, 'query': query, } } features.append(feature) elif res['type'] == 'address': for r in res['result']: feature = { 'type': 'Feature', 'geometry': { 'type': 'Point', 'coordinates': [r.lng, r.lat], }, 'properties': { 'type': 'address', 'address': r.get('address'), 'city': r.get('city'), 'state': r.get('state'), 'zip': r.get('zip'), 'query': query } } features.append(feature) # we could get type == 'block', but # ebpub.db.views.ajax_wkt returned nothing for this, # so for now we follow their lead. # elif res['type'] == 'block': # pass return features
def test_full_geocode_place(self): from ebpub.geocoder.base import full_geocode place = full_geocode('Sears Tower', search_places=True) self.assertEqual(place['type'], 'place') self.assertEqual(place['result'].normalized_name, 'SEARS TOWER')
def test_full_geocode_place(self): from ebpub.geocoder.base import full_geocode place = full_geocode("Sears Tower", search_places=True) self.assertEqual(place["type"], "place") self.assertEqual(place["result"].normalized_name, "SEARS TOWER")
def search(request, schema_slug=''): "Performs a location search and redirects to the address/xy page." # Check whether a schema was provided. if schema_slug: try: schema = get_schema_manager(request).get(slug=schema_slug) except Schema.DoesNotExist: raise Http404('Schema does not exist') url_prefix = schema.url()[:-1] else: schema = None url_prefix = '' # Get the query. q = request.GET.get('q', '').strip() if not q: return HttpResponseRedirect(url_prefix + '/') # TODO: Do something better than redirecting. # For /search/?type=alert, we redirect results to the alert page, not the # place page. if request.GET.get('type', '') == 'alert': url_method = 'alert_url' else: url_method = 'url' # Try to geocode it using full_geocode(). try: result = full_geocode(q, search_places=False) except: logger.debug('Unhandled exception from full_geocode:') log_exception(level=logging.DEBUG, logger=logger) else: if result['ambiguous']: if result['type'] == 'block': streets = [] street_blocks = {} for block in result['result']: street_name = block.street_pretty_name if street_name not in streets: streets.append(street_name) street_blocks[street_name] = [] street_blocks[street_name].append(block) choices = [{'name': s, 'blocks': street_blocks[s]} for s in streets] return eb_render(request, 'db/search_invalid_block.html', { 'query': q, 'choices': choices, }) else: return eb_render(request, 'db/did_you_mean.html', {'query': q, 'choices': result['result']}) elif result['type'] == 'location': return HttpResponseRedirect(url_prefix + getattr(result['result'], url_method)()) elif result['type'] == 'address': # Block if result['result']['block']: return HttpResponseRedirect(url_prefix + getattr(result['result']['block'], url_method)()) # Intersection try: intersection = Intersection.objects.get(id=result['result']['intersection_id']) except Intersection.DoesNotExist: pass else: return HttpResponseRedirect(url_prefix + getattr(intersection, url_method)()) # Failing the geocoding, look in the special-case table. try: special_case = SearchSpecialCase.objects.get(query=normalize(q)) except SearchSpecialCase.DoesNotExist: pass else: if special_case.redirect_to: return HttpResponseRedirect(special_case.redirect_to) else: return eb_render(request, 'db/search_special_case.html', {'query': q, 'special_case': special_case}) # Failing that, display a list of ZIP codes if this looks like a ZIP. if re.search(r'^\s*\d{5}(?:-\d{4})?\s*$', q): z_list = Location.objects.filter(location_type__slug='zipcodes', is_public=True).select_related().order_by('name') if z_list: return eb_render(request, 'db/search_error_zip_list.html', {'query': q, 'zipcode_list': z_list}) # Failing all of that, display the search error page. lt_list = LocationType.objects.filter(is_significant=True).order_by('name') return eb_render(request, 'db/search_error.html', {'query': q, 'locationtype_list': lt_list})