def setUp(self): # places self.pq_us = PlaceQuery('1200 Callowhill St, Philadelphia, PA 19107') self.pq_uk = PlaceQuery('32 Bond Road, Ste A, Surbiton, Surrey KT6') self.pq_uk_with_country_UK = PlaceQuery('32 Bond Road, Ste A, Surbiton, Surrey KT6', country='UK') self.pq_uk_with_country_GB = PlaceQuery('32 Bond Road, Ste A, Surbiton, Surrey KT6', country='GB') # candidates self.good = Candidate(match_addr='123 Any St', locator='address', score=85.3) self.better = Candidate(match_addr='123 Any St', locator='parcel', score=92) self.best = Candidate(match_addr='123 Any St', locator='rooftop', score=100) self.wolf_good = Candidate(match_addr='1200 Callowhill St', locator='address', score=76) self.wolf_better = Candidate(match_addr='1200 Callowhill St', locator='parcel', score=90) self.wolf_best = Candidate(match_addr='1200 Callowhill St', locator='rooftop', score=99.9, x=-75.158, y=39.959) self.wolf_340 = Candidate(match_addr='340 N 12th St', locator='rooftop', score=99.5, x=-75.158, y=39.959) # same coords self.inky = Candidate(match_addr='324 N Broad St', locator='rooftop', score=99.9, x=-75.163, y=39.959) # same y self.capt_thomas = Candidate(match_addr='843 Callowhill St', locator='rooftop', score=99.9, x=-75.163, y=39.959) # same y self.reading_term = Candidate(match_addr='1200 Arch St', locator='rooftop', score=99.9, x=-75.163, y=39.953) # same x self.with_address_types = Candidate(match_addr='123 Any St', locator='address', entity_types=['address', 'place']) self.with_nonsense_types = Candidate(match_addr='123 Any St', locator='address', entity_types=['house', 'building']) self.locators_worse_to_better = ['address', 'parcel', 'rooftop']
def test_google_country_filter(self): candidates = self.g_google.get_candidates(PlaceQuery('York', country='US')) self.assertOneCandidate(candidates) self.assertEqual(candidates[0].match_region, 'PA') candidates = self.g_google_wo_postprocess.get_candidates(PlaceQuery('York', country='GB')) self.assertOneCandidate(candidates) self.assertEqual(candidates[0].match_country, 'GB')
def test_pro_streetnumber_ReplaceRangeWithNumber(self): """Test ReplaceRangeWithNumber preprocessor.""" place_in = PlaceQuery('4452-54 Main Street, Philadelphia') # Mom's Pizza in Manayunk place_out = ReplaceRangeWithNumber().process(place_in) query_exp = '4452 Main Street, Philadelphia' self.assertEqual_(place_out.query, query_exp) zip_plus_4 = '19127-1112' place_in = PlaceQuery(zip_plus_4) # sets PlaceQuery.query to zip_plus_4 on init place_out = ReplaceRangeWithNumber().process(place_in) self.assertEqual_(place_out.query, zip_plus_4)
def geocode(request): """ Endpoint to geocode a lat/lng pair Configuration for sources is pulled from the OMGEO_SETTINGS settings key """ viewbox = _get_viewbox_from_request(request) address = request.REQUEST['address'] pq = PlaceQuery(query=address, viewbox=viewbox) geocode_result = geocoder.geocode(pq) candidates = geocode_result.get('candidates', None) if not candidates or len(candidates) == 0: return _no_results_response(address) else: candidates = [_omgeo_candidate_to_dict(c) for c in candidates] if _contains_bbox(request): bbox = { 'xmin': request.REQUEST['xmin'], 'ymin': request.REQUEST['ymin'], 'xmax': request.REQUEST['xmax'], 'ymax': request.REQUEST['ymax'] } candidates = [c for c in candidates if _in_bbox(bbox, c)] if len(candidates) == 0: return _no_results_response(address, inregion=True) return {'candidates': candidates}
def test_pro_CancelIfRegexInAttr_case_sensitive(self): """Test CancelIfRegexInAttr preprocessor using case-sensitive option.""" place_in = PlaceQuery('PO Box 123, Philadelphia, PA') place_out = CancelIfRegexInAttr(regex="PO BOX", attrs=('query',), ignorecase=False).process(place_in) place_exp = place_in # we should still have it because PO BOX does not match exactly self.assertEqual_(place_out, place_exp)
def _geocode_without_magic_key(request, address): # See settings.OMGEO_SETTINGS for configuration viewbox = _get_viewbox_from_request(request) pq = PlaceQuery(query=address, viewbox=viewbox) geocode_result = geocoder.geocode(pq) candidates = geocode_result.get('candidates', None) if not candidates: return _no_results_response(address) else: candidates = [_omgeo_candidate_to_dict(c) for c in candidates] if _contains_bbox(request): # The geocoder favored results inside the bounding box but may have # returned results outside the bounding box, so filter those away. bbox = { 'xmin': request.REQUEST['xmin'], 'ymin': request.REQUEST['ymin'], 'xmax': request.REQUEST['xmax'], 'ymax': request.REQUEST['ymax'] } candidates = [c for c in candidates if _in_bbox(bbox, c)] if len(candidates) == 0: return _no_results_response(address, inregion=True) return {'candidates': candidates}
def test_pro_parsing_ParseSingleLine(self): """Test ParseSingleLine preprocessor using single-line UK address.""" place_in = PlaceQuery('32 Bond Road, Surbiton, Surrey KT6 7SH') place_out = ParseSingleLine().process(place_in) self.assertEqual_(place_out.address, '32 Bond Road') self.assertEqual_(place_out.city, 'Surbiton, Surrey') self.assertEqual_(place_out.postal, 'KT6 7SH')
def test_pro_CancelIfRegexInAttr(self): """Test CancelIfRegexInAttr preprocessor.""" place_in = PlaceQuery('PO Box 123, Philadelphia, PA') place_out = CancelIfRegexInAttr(regex="po box", attrs=('query', )).process(place_in) place_exp = False self.assertEqual_(place_out, place_exp)
def test_pro_CancelIfRegexInAttr_unicode_args(self): """Test CancelIfRegexInAttr preprocessor using bytestring query and unicode regex/attrs.""" place_in = PlaceQuery(u'PO Box 123, Lindström, MN'.encode("utf-8")) # Test all 3 combinations for completeness, but only test the result once since if they # fail it will be by raising exceptions place_out = CancelIfRegexInAttr(regex=u"po box", attrs=('query',)).process(place_in) place_out = CancelIfRegexInAttr(regex="po box", attrs=(u'query',)).process(place_in) place_out = CancelIfRegexInAttr(regex=u"po box", attrs=('query',)).process(place_in) place_exp = False self.assertEqual_(place_out, place_exp)
def test_geocode_nom(self): """ Test 1200 Callowhill Street using Nominatim geocoder. Also check to make sure coordinate values are floats and not some other data type. """ candidates = self.g_nom.get_candidates(PlaceQuery('1200 Callowhill St, Philadelphia, PA')) x_type = type(candidates[0].x) y_type = type(candidates[0].y) self.assertEqual(x_type == float, True, 'x coord is of type %s instead of float' % x_type) self.assertEqual(y_type == float, True, 'y coord is of type %s instead of float' % y_type) self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
def geocode(request, format=None): query = request.GET.get('search', None) key = request.GET.get('key', None) if (not query): response = Response(data={'error': 'Search parameter is required.'}, status=400) return response pq = PlaceQuery(query=query, country='US', key=key) result = geocoder.geocode(pq) candidates = result['candidates'] candidates = [_omgeo_candidate_to_dict(c) for c in candidates] return Response(candidates)
def geocode(self, pq, waterfall=None, force_stats_logging=False): """ :arg PlaceQuery pq: PlaceQuery object (required). :arg bool waterfall: Boolean set to True if all geocoders listed should be used to find results, instead of stopping after the first geocoding service with valid candidates (defaults to self.waterfall). :arg bool force_stats_logging: Raise exception if stats logging fails (default False). :returns: Returns a dictionary including: * candidates - list of Candidate objects * upstream_response_info - list of UpstreamResponseInfo objects """ start_time = time.time() waterfall = self.waterfall if waterfall is None else waterfall if type(pq) in (str, unicode): pq = PlaceQuery(pq) processed_pq = copy.copy(pq) for p in self._preprocessors: # apply universal address preprocessing processed_pq = p.process(processed_pq) if processed_pq == False: return get_result( ) # universal preprocessor rejects PlaceQuery upstream_response_info_list = [] processed_candidates = [] for gs in self._sources: # iterate through each GeocodeService candidates, upstream_response_info = gs.geocode(processed_pq) if upstream_response_info is not None: upstream_response_info_list.append(upstream_response_info) processed_candidates += candidates # merge lists if waterfall is False and len(processed_candidates) > 0: break # if >= 1 good candidate, don't go to next geocoder for p in self._postprocessors: # apply univ. candidate postprocessing if processed_candidates == []: break # avoid post-processing empty list processed_candidates = p.process(processed_candidates) result = dict(candidates=processed_candidates, upstream_response_info=upstream_response_info_list) stats_dict = self.convert_geocode_result_to_nested_dicts(result) stats_dict = dict(stats_dict, original_pq=pq.__dict__) try: stats_logger.info(stats_dict) except Exception as exception: logger.error('Encountered exception while logging stats %s:\n%s', stats_dict, exception) if force_stats_logging: raise exception return result
def _geocode_with_magic_key(address, key): # See settings.OMGEO_SETTINGS_FOR_MAGIC_KEY for configuration pq = PlaceQuery(query=address, key=key) geocode_result = geocoder_for_magic_key.geocode(pq) candidates = geocode_result.get('candidates', None) if candidates: # Address searches return many candidates. But the user already # chose a specific suggestion so we want the first candidate. # The exception is a "point of interest" search, where the user's # chosen suggestion may be a category like "Beaches" and you want to # see many candidates. if candidates[0].locator_type != 'POI': candidates = [candidates[0]] candidates = [_omgeo_candidate_to_dict(c) for c in candidates] return {'candidates': candidates} else: return _no_results_response(address)
def geocode(request): """ Search for specified address, returning candidates with lat/long """ key = request.REQUEST.get('key') address = request.REQUEST.get('address').encode('utf-8') if key: # See settings.OMGEO_SETTINGS for configuration pq = PlaceQuery(query=address, key=key) geocode_result = geocoder.geocode(pq) candidates = geocode_result.get('candidates', None) if candidates: # There should only be one candidate since the user already chose a # specific suggestion and the front end filters out suggestions # that might result in more than one candidate (like "Beaches"). match = candidates[0] return {'lat': match.y, 'lng': match.x} return _no_results_response(address)
def test_pro_CancelIfPOBox(self): """Test CancelIfPOBox preprocessor.""" place_in = PlaceQuery('PO Box 123, Philadelphia, PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='PO Box 123', city='Philadelphia', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='P.O Box 123', city='Philadelphia', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='P O box 123', city='Philadelphia', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='P.O. Box 123', city='Philadelphia', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='P.O. Box K', city='New Stanton', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='PO. Box K', city='New Stanton', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='P.O.B. 123', city='Philadelphia', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='P.O. BX123', city='Philadelphia', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery(address='POB 123', city='Philadelphia', state='PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery('POBOX 123, Philadelphia, PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_(place_out, False) place_in = PlaceQuery( '1200 Callowhill St, PO Box 466, Philadelphia, PA') place_out = CancelIfPOBox().process(place_in) self.assertEqual_( place_out, place_in) # should still geocode because we a physical address
def setUp(self): # Viewbox objects - callowhill is from BSS Spring Garden station to Wash. Sq. vb = { 'callowhill': Viewbox(-75.162628, 39.962769, -75.150963, 39.956322) } # PlaceQuery objects self.pq = { # North American Addresses: 'azavea': PlaceQuery('340 N 12th St Ste 402 Philadelphia PA'), 'ambiguous_azavea': PlaceQuery('340 12th St Ste 402 Philadelphia PA'), 'zip_plus_4_in_postal_plus_country': PlaceQuery(postal='19127-1115', country='US'), 'wolf': PlaceQuery('Wolf Building'), 'wolf_philly': PlaceQuery('Wolf Building, Philadelphia PA'), 'wolf_bounded': PlaceQuery('Wolf Building', bounded=True, viewbox=vb['callowhill']), 'bounded_340_12th': PlaceQuery('340 12th St, Philadelphia PA', bounded=True, viewbox=vb['callowhill']), 'alpha_774R_W_Central_Ave': PlaceQuery('774R W Central Ave Alpha NJ'), 'alpha_774_W_Central_Ave_Rear': PlaceQuery('774 W Central Ave Rear, Alpha NJ'), '8_kirkbride': PlaceQuery('8 Kirkbride Rd 08822'), 'george_washington': PlaceQuery('201 W Montmorency Blvd, George, Washington'), 'pine_needles_dr': PlaceQuery('11761 pine needles providence forge'), 'pine_needles_ct': PlaceQuery('5328 pine needles providence forge'), 'pine_needles_terr': PlaceQuery('5359 pine needles providence forge'), 'moorestown_hyphenated': PlaceQuery('111-113 W Main St Moorestown NJ'), 'willow_street': PlaceQuery('2819F Willow Street Pike Willow Street PA'), 'willow_street_parts': PlaceQuery(address='2819F Willow Street Pike', city='Willow Street', state='PA', country='US'), 'quebec': PlaceQuery('756 Rue Berri Montreal QC', country='CA'), 'quebec_accent': PlaceQuery('527 Ch. Beauséjour, Saint-Elzéar-de-Témiscouata QC'), 'quebec_hyphenated': PlaceQuery('227-227A Rue Commerciale, Saint-Louis-du-Ha! Ha! QC'), 'senado_mx': PlaceQuery('Paseo de la Reforma 135, Tabacalera, Cuauhtémoc, Distrito Federal, 06030'), 'senado_mx_struct': PlaceQuery(address='Paseo de la Reforma 135', neighborhood='Tabacalera, Cuauhtémoc', subregion='', state='Distrito Federal', postal='06030', country='MX'), 'robert_cheetham': PlaceQuery('Robert Cheetham, Philadelphia'), # European Addresses: 'london_pieces': PlaceQuery(address='31 Maiden Lane', city='London', country='UK'), 'london_one_line': PlaceQuery('31 Maiden Lane, London WC2E', country='UK'), 'london_pieces_hyphenated': PlaceQuery(address='31-32 Maiden Lane', city='London', country='UK'), 'london_one_line_hyphenated': PlaceQuery('31-32 Maiden Lane London WC2E', country='UK'), # Oceanian Addresses: 'karori': PlaceQuery('102 Karori Road Karori Wellington', country='NZ'), } if BING_MAPS_API_KEY is not None: bing_settings = dict(api_key=BING_MAPS_API_KEY) self.g_bing = Geocoder( [['omgeo.services.Bing', { 'settings': bing_settings }]]) if MAPQUEST_API_KEY is not None: mapquest_settings = dict(api_key=MAPQUEST_API_KEY) self.g_mapquest = Geocoder( [['omgeo.services.MapQuest', { 'settings': mapquest_settings }]]) self.g_mapquest_ssl = Geocoder([[ 'omgeo.services.MapQuestSSL', { 'settings': mapquest_settings } ]]) if PELIAS_API_KEY is not None: pelias_settings = dict(api_key=PELIAS_API_KEY) self.g_pelias = Geocoder( [['omgeo.services.Pelias', { 'settings': pelias_settings }]]) if GOOGLE_API_KEY is not None: self.g_google = Geocoder([[ 'omgeo.services.Google', { 'settings': { 'api_key': GOOGLE_API_KEY } } ]]) self.g_google_wo_postprocess = Geocoder([[ 'omgeo.services.Google', { 'settings': { 'api_key': GOOGLE_API_KEY }, 'postprocessors': [] } ]]) #: main geocoder used for tests, using default APIs self.g = Geocoder() # geocoders using individual services self.g_esri_wgs = Geocoder([['omgeo.services.EsriWGS', {}]]) if ESRI_CLIENT_ID is not None and ESRI_CLIENT_SECRET is not None: self.g_esri_wgs_auth = Geocoder([[ 'omgeo.services.EsriWGS', { 'settings': { 'client_id': ESRI_CLIENT_ID, 'client_secret': ESRI_CLIENT_SECRET } } ]]) if MAPQUEST_API_KEY is not None: # MapQuest's open Nominatime API now also requires a key self.g_nom = Geocoder([['omgeo.services.Nominatim', {}]]) self.g_census = Geocoder([['omgeo.services.USCensus', {}]]) ESRI_WGS_LOCATOR_MAP = { 'PointAddress': 'rooftop', 'StreetAddress': 'interpolation', 'PostalExt': 'postal_specific', # accept ZIP+4 'Postal': 'postal' } ESRI_WGS_POSTPROCESSORS_POSTAL_OK = [ AttrExclude( ['USA.Postal'], 'locator' ), # accept postal from everywhere but US (need PostalExt) AttrFilter( ['PointAddress', 'StreetAddress', 'PostalExt', 'Postal'], 'locator_type'), AttrSorter( ['PointAddress', 'StreetAddress', 'PostalExt', 'Postal'], 'locator_type'), AttrRename('locator', ESRI_WGS_LOCATOR_MAP ), # after filter to avoid searching things we toss out UseHighScoreIfAtLeast(99.8), ScoreSorter(), GroupBy('match_addr'), GroupBy(('x', 'y')), ] GEOCODERS_POSTAL_OK = [[ 'omgeo.services.EsriWGS', { 'postprocessors': ESRI_WGS_POSTPROCESSORS_POSTAL_OK } ]] self.g_esri_wgs_postal_ok = Geocoder(GEOCODERS_POSTAL_OK) #: geocoder with fast timeout self.impatient_geocoder = Geocoder( [['omgeo.services.EsriWGS', { 'settings': { 'timeout': 0.001 } }]])
def test_geocode_census(self): """Test Azavea's address using US Census geocoder.""" candidates = self.g_census.get_candidates( PlaceQuery('1200 Callowhill St, Philadelphia, PA')) self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
def test_pro_CancelIfRegexInAttr_unicode_query(self): """Test CancelIfRegexInAttr preprocessor using unicode query and default regex/attrs.""" place_in = PlaceQuery(u'PO Box 123, Lindström, MN') place_out = CancelIfRegexInAttr(regex="po box", attrs=('query',)).process(place_in) place_exp = False self.assertEqual_(place_out, place_exp)
def test_geocode_esri_eu_soap(self): """Test ESRI Europe SOAP geocoder""" candidates = self.g_esri_eu_soap.get_candidates(PlaceQuery( address='31 Maiden Lane', city='London', country='UK')) self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')