Ejemplo n.º 1
0
    def __init__(self, curs):
        self.curs = curs
        self.geolocator = GoogleV3()
        self.nominatim = nominatim.Nominatim()

        self.geocoder = Geocoder()
        self.re_numbers = re.compile("^\d+$")
Ejemplo n.º 2
0
def geocode(address):
    """Given an address, returns candidates."""
    pq = PlaceQuery(address)
    global _geocoder
    if _geocoder is None:
        _geocoder = Geocoder()
    return _geocoder.geocode(pq)
    def handle(self, *args, **options):
        
       # from omgeo import Geocoder
        g = Geocoder([
            ['omgeo.services.Bing',{
                'settings':{
                    'api_key':'AnoU4IZjQyL3BLIVJNmfpUgqh86Z8jVEk4n2uQNRzSWAu1Suu5I1NvmjGslFS1Dk'
                }
            }],
        #     ['omgeo.services.Nominatim',{}],
        #     ['omgeo.services.MapQuest',{
        #         'settings':{
        #             'api_key':'Fmjtd%7Cluua2501lu%2C2a%3Do5-962gq6'
        #         }    
        #     }]
        ])

        for s in BPStation.objects.filter(address__isnull=False):
            #get geocoded address for this address
            address_string = '%s, %s, %s, %s' % (s.address, s.city, s.state, s.zip,)
            geocode_results = g.geocode(address_string,True)
            geocode_candidates = geocode_results['candidates']
            for c in geocode_candidates:
                if c.confidence == 'High':
                    s.point_location = GEOSGeometry('POINT(%s %s)' % (c.x, c.y,),4326)
                    s.save()
                    self.stdout.write("Location found: %s %s\n" % (c.x, c.y,))
            
            if not s.point_location:
                self.stdout.write("No good geocode found\n")
        
        #manual override of locations that don't geocode well
        try:
            if len(args) > 0:
                self.stdout.write('Using manual CSV location ...\n')
                file_path = args[0]
            else:
                self.stdout.write('Using default CSV location ...\n')
                working_dir = os.path.join(SITE_ROOT, '../data')
                file_path = os.path.join(working_dir, 'geocodestragglers20120830.csv')
                    
            handle = csv.reader(open(file_path, 'rU'), delimiter=',', quotechar='"')
            header = handle.next()
            
            for h in handle:
                print h
                try:
                    station = BPStation.objects.get(name=h[1].strip())
                    
                    station.point_location = GEOSGeometry('POINT(%s %s)' % (h[7].strip(), h[8].strip(),),4326)
                    station.save()
                    self.stdout.write('%s: %s %s\n' % (h[0].strip(), h[7].strip(), h[8].strip(),))
                    
                except:
                    raise
            
            self.stdout.write('Successfully loaded manual Border Patrol geocodes.\n')
        except AttributeError:
            raise
Ejemplo n.º 4
0
    def handle(self, *args, **options):

        # from omgeo import Geocoder
        g = Geocoder([
            [
                'omgeo.services.Bing', {
                    'settings': {
                        'api_key':
                        'AnoU4IZjQyL3BLIVJNmfpUgqh86Z8jVEk4n2uQNRzSWAu1Suu5I1NvmjGslFS1Dk'
                    }
                }
            ],
            #     ['omgeo.services.Nominatim',{}],
            #     ['omgeo.services.MapQuest',{
            #         'settings':{
            #             'api_key':'Fmjtd%7Cluua2501lu%2C2a%3Do5-962gq6'
            #         }
            #     }]
        ])

        for s in Location.objects.all():
            #get geocoded address for this address
            address_string = '%s, %s' % (s.name, 'Champaign, IL')
            geocode_results = g.geocode(address_string, True)
            geocode_candidates = geocode_results['candidates']
            for c in geocode_candidates:
                if c.confidence == 'High':
                    s.point_location = GEOSGeometry(
                        'POINT(%s %s)' % (
                            c.x,
                            c.y,
                        ), 4326)
                    s.save()
                    self.stdout.write("Location found: %s %s\n" % (
                        c.x,
                        c.y,
                    ))

            if not s.point_location:
                address_string = '%s, %s' % (s.name, 'Urbana, IL')
                geocode_results = g.geocode(address_string, True)
                geocode_candidates = geocode_results['candidates']
                for c in geocode_candidates:
                    if c.confidence == 'High':
                        s.point_location = GEOSGeometry(
                            'POINT(%s %s)' % (
                                c.x,
                                c.y,
                            ), 4326)
                        s.save()
                        self.stdout.write("Location found: %s %s\n" % (
                            c.x,
                            c.y,
                        ))

            if not s.point_location:
                self.stdout.write("No good geocode found\n")
Ejemplo n.º 5
0
def load_data(inPath, outPath):
	outFile = open(outPath, 'w')
	counter = 0
	with open(inPath,'Ur') as inFile:
		for line in inFile:
			GarageID,Zip,Street,City,State,cnt = line.split(",")
			address = Street+" "+City+" "+State+" "+"USA"
			g = Geocoder()
			result = g.geocode(address)

			outFile.write('%s\n' % (result))
Ejemplo n.º 6
0
 def __init__(self, address):
     """Geocode given address and set self.coords to (x,y) tuple."""
     geocoder = Geocoder()
     georesult = geocoder.geocode(address)
     geocandidates = georesult['candidates']
     coord_pairs = [(c.x, c.y) for c in geocandidates]
     num_coord_pairs = len(coord_pairs)
     if num_coord_pairs == 0:
         raise Exception('No geocoding results for %s' % address)
     if num_coord_pairs > 1:
         choices = [c.match_addr for c in geocandidates]
         raise Exception('Ambiguous address. Choices are:\n%s' % choices)
     self.coords = coord_pairs[0]
Ejemplo n.º 7
0
	def handle(self, *args, **options):
			parser = StreetAddressParser()
		#try:
			g = Geocoder([
				['omgeo.services.Bing',{
					'settings':{
						'api_key':'AufKQbvq8uGM3qsQWwMwJNtlf6LLxe5bPvOAVcxi-79Qp0tDl0T2qScdOQiBNKkE'
					}
				}],
			])

			for location in Location.objects.filter(point_location__isnull=True):
				string = location.address.strip()

				if location.city is not None:
					string = string + ", " + location.city
				
				else:
					if location.agency:
						string = string + ", " + location.agency.name + " IL"
					else:
						string = string + ", Champaign, IL"
				
				block_pattern = re.compile('BLOCK OF')
				cleaned_address = re.sub(block_pattern,'', string)
				print cleaned_address
				
				if location.intersection_indicator:
					slash = re.compile('/')
					string = re.sub(slash,'at', string)
					print string

				if len(location.address.strip()) > 0:
					geocode_results = g.geocode(cleaned_address,True)
					geocode_candidates = geocode_results['candidates']
					for c in geocode_candidates:

						if math.floor(c.x) == -89.0 and math.floor(c.y) == 40.0:
							print "within acceptable ranges"
							if c.confidence == 'High':
								location.point_location = GEOSGeometry('POINT(%s %s)' % (c.x, c.y,),4326)
								location.save()
								self.stdout.write("Location found: %s %s\n" % (c.x, c.y,))
					
					if not location.point_location:
						self.stdout.write("No good geocode found for %s \n" % (cleaned_address))
					#location.attempted = True				
					location.save()

		#except (RuntimeError, TypeError, NameError):
		#	print "whoopsie"
Ejemplo n.º 8
0
 def __init__(self, curs):
     self.curs = curs
     self.geolocator = GoogleV3()
     self.nominatim = nominatim.Geocoder()
     
     self.geocoder = Geocoder()
     self.re_numbers = re.compile("^\d+$")
Ejemplo n.º 9
0
    def _test_geocode_results_all_(self,
                                   verbosity=0,
                                   geocoder=Geocoder(),
                                   expected_results=16):
        """
        Geocode a list of addresses. Some of these only work with Bing so
        fewer results are expected when Bing is not used as a geocoder.
        """
        if verbosity > 1:
            logger.setLevel(logging.INFO)

        queries_with_results = 0
        for place in self.pq:
            logger.info(place)
            logger.info(len(place) * '-')
            candidates = geocoder.get_candidates(self.pq[place])
            if len(candidates) == 0:
                logger.info('Input: %s\n(no results)' % self.pq[place].query)
            else:
                queries_with_results += 1
                logger.info('Input:  %s' % self.pq[place].query)
                logger.info([
                    'Output: %r (%s %s)\n' %
                    (c.match_addr, c.geoservice,
                     [c.locator, c.score, c.confidence, c.entity])
                    for c in candidates
                ])
        self.assertEqual(
            expected_results, queries_with_results,
            'Got results for %d of %d queries.' %
            (queries_with_results, len(self.pq)))
Ejemplo n.º 10
0
    def __init__(self, *args, **kwargs):
        super(GeocodingFilter, self).__init__(*args, **kwargs)
        self.geocoder = Geocoder()
        self.cache = {}

        with open(os.path.join(PWD, 'data', 'geocache.csv')) as infile:
            for record in csv.reader(infile):
                self.cache[record[0]] = (record[1], record[2])
Ejemplo n.º 11
0
def geocode_address(request, address):
    def result_in_bounding_box(result):
        x = float(result.x)
        y = float(result.y)
        left = float(settings.BOUNDING_BOX['left'])
        top = float(settings.BOUNDING_BOX['top'])
        right = float(settings.BOUNDING_BOX['right'])
        bottom = float(settings.BOUNDING_BOX['bottom'])
        return x > left and x < right and y > bottom and y < top

    if address is None or len(address) == 0:
        raise HttpBadRequestException("No address specfified")

    query = PlaceQuery(address, viewbox=Viewbox(
        settings.BOUNDING_BOX['left'],
        settings.BOUNDING_BOX['top'],
        settings.BOUNDING_BOX['right'],
        settings.BOUNDING_BOX['bottom'])
    )

    if (('OMGEO_GEOCODER_SOURCES' in dir(settings)
         and settings.OMGEO_GEOCODER_SOURCES is not None)):
        geocoder = Geocoder(settings.OMGEO_GEOCODER_SOURCES)
    else:
        geocoder = Geocoder()

    results = geocoder.geocode(query)
    if results is not False:
        response = []
        for result in results:
            # some geocoders do not support passing a bounding box filter
            if result_in_bounding_box(result):
                response.append({
                    "match_addr": result.match_addr,
                    "x": result.x,
                    "y": result.y,
                    "score": result.score,
                    "locator": result.locator,
                    "geoservice": result.geoservice,
                    "wkid": result.wkid,
                })
        return response
    else:
        # This is not a very helpful error message, but omgeo as of
        # v1.2 does not report failure details.
        return {"error": "The geocoder failed to generate a list of results."}
Ejemplo n.º 12
0
    def setUp(self):
        # Viewbox objects
        vb = {}
        vb['callowhill'] = Viewbox(-75.162628, 39.962769, -75.150963, 39.956322)
        # PlaceQuery objects
        self.pq = {}
        # North American Addresses:
        self.pq['azavea'] = PlaceQuery('340 N 12th St Ste 402 Philadelphia PA')
        self.pq['ambiguous_azavea'] = PlaceQuery('340 12th St Ste 402 Philadelphia PA')
        self.pq['wolf'] = PlaceQuery('Wolf Building')
        self.pq['wolf_philly'] = PlaceQuery('Wolf Building, Philadelphia PA')
        self.pq['wolf_bounded'] = PlaceQuery('Wolf Building', viewbox=vb['callowhill'])
        self.pq['alpha_774R_W_Central_Ave'] = PlaceQuery('774R W Central Ave Alpha NJ')
        self.pq['alpha_774_W_Central_Ave_Rear'] = PlaceQuery('774 W Central Ave Rear Alpha NJ')
        self.pq['pine_needles_dr'] = PlaceQuery('11761 pine needles providence forge')
        self.pq['pine_needles_ct'] = PlaceQuery('5328 pine needles providence forge')
        self.pq['pine_needles_terr'] = PlaceQuery('5359 pine needles providence forge')
        self.pq['moorestown_hyphenated'] = PlaceQuery('111-113 W Main St Moorestown NJ')
        self.pq['willow_street'] = PlaceQuery('2819F Willow Street Pike Willow Street PA')
        self.pq['quebec'] = PlaceQuery('756 Rue Berri Montreal QC', country='CA')
        self.pq['quebec_bang'] = PlaceQuery('177 Rue Commerciale, Saint-Louis-du-Ha! Ha! QC')
        self.pq['quebec_accent'] = PlaceQuery('527 Ch. Beauséjour, Saint-Elzéar-de-Témiscouata QC')
        self.pq['quebec_hyphenated'] = PlaceQuery('227-227A Rue Commerciale, Saint-Louis-du-Ha! Ha! QC')
        # European Addresses:
        self.pq['london_pieces'] = PlaceQuery(address='31 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line'] = PlaceQuery('31 Maiden Lane, London WC2E', country='UK')
        self.pq['london_pieces_hyphenated'] = PlaceQuery(address='31-32 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line_hyphenated'] = PlaceQuery('31-32 Maiden Lane London WC2E', country='UK')
        # Oceanic Addresses:
        self.pq['karori'] = PlaceQuery('102 Karori Road Karori Wellington', country='NZ')

        # Geocoder objects
        self.g = Geocoder()
        if ESRI_MAPS_API_KEY is not None:
            self.g_esri_na = Geocoder([['omgeo.services.EsriNA',
                    {'settings':{'api_key':ESRI_MAPS_API_KEY}}]])
            self.g_esri_eu = Geocoder([['omgeo.services.EsriEU',
                    {'settings':{'api_key':ESRI_MAPS_API_KEY}}]])
        else:
            self.g_esri_na = Geocoder([['omgeo.services.EsriNA', {}]])
            self.g_esri_eu = Geocoder([['omgeo.services.EsriEU', {}]])

        self.g_bing = Geocoder([['omgeo.services.Bing', {'settings':{'api_key':BING_MAPS_API_KEY}}]])
        self.g_nom = Geocoder([['omgeo.services.Nominatim',{}]])
        self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
Ejemplo n.º 13
0
def geocode(request):
    """
    Endpoint to geocode a lat/lng pair

    Configuration for sources is pulled from the OMGEO_SETTINGS
    settings key
    """
    rslt = Geocoder(sources=settings.OMGEO_SETTINGS)\
        .geocode(request.REQUEST['address'])

    candidates = rslt.get('candidates', None)
    if candidates and len(candidates) > 0:
        resp = {'address': candidates[0].match_addr,
                'epsg': candidates[0].wkid,
                'x': candidates[0].x,
                'y': candidates[0].y}

        return HttpResponse(json.dumps(resp))
    else:
        raise Http404('Could not geocode %s' % request.REQUEST['address'])
    def handle(self, *args, **options):
        
        try:
            g = Geocoder([
                ['omgeo.services.Bing',{
                    'settings':{
                        'api_key':'AufKQbvq8uGM3qsQWwMwJNtlf6LLxe5bPvOAVcxi-79Qp0tDl0T2qScdOQiBNKkE'
                    }
                }],
            #     ['omgeo.services.Nominatim',{}],
            #     ['omgeo.services.MapQuest',{
            #         'settings':{
            #             'api_key':'Fmjtd%7Cluua2501lu%2C2a%3Do5-962gq6'
            #         }    
            #     }]
            ])

            for s in Address.objects.all():
                #get geocoded address for this address
                address_string = s.string
                print address_string
                homeless = address_string.find('HOMELESS')
                print homeless
                if homeless == -1:
                    if len(address_string) > 0:
                        geocode_results = g.geocode(address_string,True)
                        geocode_candidates = geocode_results['candidates']
                        for c in geocode_candidates:
                            if c.confidence == 'High':
                                s.point_location = GEOSGeometry('POINT(%s %s)' % (c.x, c.y,),4326)
                                s.save()
                                self.stdout.write(address_string)
                                self.stdout.write("Location found: %s %s\n" % (c.x, c.y,))
                        
                        if not s.point_location:
                            self.stdout.write("No good geocode found for %s \n" % (address_string))
                        s.attempted = True
                        s.save()
        except:
            print "whoopsie for ",  address_string
            raise
Ejemplo n.º 15
0
    def handle(self, *args, **options):
        
       # from omgeo import Geocoder
        g = Geocoder([
            ['omgeo.services.Bing',{
                'settings':{
                    'api_key':'AnoU4IZjQyL3BLIVJNmfpUgqh86Z8jVEk4n2uQNRzSWAu1Suu5I1NvmjGslFS1Dk'
                }
            }],
        #     ['omgeo.services.Nominatim',{}],
        #     ['omgeo.services.MapQuest',{
        #         'settings':{
        #             'api_key':'Fmjtd%7Cluua2501lu%2C2a%3Do5-962gq6'
        #         }    
        #     }]
        ])

        for s in Location.objects.all():
            #get geocoded address for this address
            address_string = '%s, %s' % (s.name, 'Champaign, IL')
            geocode_results = g.geocode(address_string,True)
            geocode_candidates = geocode_results['candidates']
            for c in geocode_candidates:
                if c.confidence == 'High':
                    s.point_location = GEOSGeometry('POINT(%s %s)' % (c.x, c.y,),4326)
                    s.save()
                    self.stdout.write("Location found: %s %s\n" % (c.x, c.y,))

            if not s.point_location:
                address_string = '%s, %s' % (s.name, 'Urbana, IL')
                geocode_results = g.geocode(address_string,True)
                geocode_candidates = geocode_results['candidates']
                for c in geocode_candidates:
                    if c.confidence == 'High':
                        s.point_location = GEOSGeometry('POINT(%s %s)' % (c.x, c.y,),4326)
                        s.save()
                        self.stdout.write("Location found: %s %s\n" % (c.x, c.y,))
            
            if not s.point_location:
                self.stdout.write("No good geocode found\n")
Ejemplo n.º 16
0
    def setUp(self):
        # Viewbox objects
        vb = {}
        vb['callowhill'] = Viewbox(-75.162628, 39.962769, -75.150963, 39.956322)
        # PlaceQuery objects
        self.pq = {}
        # North American Addresses:
        self.pq['azavea'] = PlaceQuery('340 N 12th St Ste 402 Philadelphia PA')
        self.pq['ambiguous_azavea'] = PlaceQuery('340 12th St Ste 402 Philadelphia PA')
        self.pq['wolf'] = PlaceQuery('Wolf Building')
        self.pq['wolf_philly'] = PlaceQuery('Wolf Building, Philadelphia PA')
        self.pq['wolf_bounded'] = PlaceQuery('Wolf Building', viewbox=vb['callowhill'])
        self.pq['alpha_774R_W_Central_Ave'] = PlaceQuery('774R W Central Ave Alpha NJ')
        self.pq['alpha_774_W_Central_Ave_Rear'] = PlaceQuery('774 W Central Ave Rear Alpha NJ')
        self.pq['8_kirkbride'] = PlaceQuery('8 Kirkbride Rd 08822')
        self.pq['george_washington'] = PlaceQuery('201 W Montmorency Blvd, George, Washington')
        self.pq['pine_needles_dr'] = PlaceQuery('11761 pine needles providence forge')
        self.pq['pine_needles_ct'] = PlaceQuery('5328 pine needles providence forge')
        self.pq['pine_needles_terr'] = PlaceQuery('5359 pine needles providence forge')
        self.pq['moorestown_hyphenated'] = PlaceQuery('111-113 W Main St Moorestown NJ')
        self.pq['willow_street'] = PlaceQuery('2819F Willow Street Pike Willow Street PA')
        self.pq['quebec'] = PlaceQuery('756 Rue Berri Montreal QC', country='CA')
        self.pq['quebec_accent'] = PlaceQuery('527 Ch. Beauséjour, Saint-Elzéar-de-Témiscouata QC')
        self.pq['quebec_hyphenated'] = PlaceQuery('227-227A Rue Commerciale, Saint-Louis-du-Ha! Ha! QC')
        # European Addresses:
        self.pq['london_pieces'] = PlaceQuery(address='31 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line'] = PlaceQuery('31 Maiden Lane, London WC2E', country='UK')
        self.pq['london_pieces_hyphenated'] = PlaceQuery(address='31-32 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line_hyphenated'] = PlaceQuery('31-32 Maiden Lane London WC2E', country='UK')
        # Oceanian Addresses:
        self.pq['karori'] = PlaceQuery('102 Karori Road Karori Wellington', country='NZ')

        # Set up geocoders
        if ESRI_MAPS_API_KEY is None:
            esri_settings = {}
        else:
            esri_settings = dict(api_key=ESRI_MAPS_API_KEY)
        self.service_esri_na = ['omgeo.services.EsriNA', dict(settings=esri_settings)]
        self.service_esri_eu = ['omgeo.services.EsriEU', dict(settings=esri_settings)]
        g_sources = [self.service_esri_na, self.service_esri_eu]
        self.g_esri_na = Geocoder([self.service_esri_na])
        self.g_esri_eu = Geocoder([self.service_esri_eu])
        if BING_MAPS_API_KEY is not None:
            bing_settings = dict(api_key=BING_MAPS_API_KEY)
            self.service_bing = ['omgeo.services.Bing', dict(settings=bing_settings)]
            g_sources.append(self.service_bing)
            self.g_bing = Geocoder([self.service_bing])
        self.service_nom = ['omgeo.services.Nominatim', {}]
        g_sources.append(self.service_nom)
        self.g_nom = Geocoder([self.service_nom])
        self.g = Geocoder(sources=g_sources) # main geocoder used for tests
        # other geocoders for services not used in self.g
        self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
        self.g_esri_na_soap = Geocoder([['omgeo.services.EsriNASoap', {}]])
        self.g_esri_eu_soap = Geocoder([['omgeo.services.EsriEUSoap', {}]])
Ejemplo n.º 17
0
    def test_esri_geocoder_eu_default_override(self):
        """
        Test for default argument bug in 3.1 --
        EsriNA and EsriEU append processors rather than replace them
        """
        geocoder = Geocoder([['omgeo.services.EsriEU',
                            {'postprocessors': [AttrFilter([
                                'rooftop',
                                'interpolation',
                                'postal_specific'],
                                'locator')]}]])

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors),
            'EsriEU geocoder incorrectly processed defaults')
        self.assertEqual('AttrFilter',
            geocoder._sources[0]._postprocessors[0].__class__.__name__,
            'EsriEU geocoder incorrectly processed defaults')
Ejemplo n.º 18
0
class GeocodingFilter(filters.Filter):
    """ Geocode contributions based on address.
    """

    def __init__(self, *args, **kwargs):
        super(GeocodingFilter, self).__init__(*args, **kwargs)
        self.geocoder = Geocoder()
        self.cache = {}

        with open(os.path.join(PWD, 'data', 'geocache.csv')) as infile:
            for record in csv.reader(infile):
                self.cache[record[0]] = (record[1], record[2])

    def process_record(self, record):

        if not record.get('lat') and not record.get('lon'):

            vals = (record['address'], record['city'], record['state'], record['zip'])
            addr = "%s %s %s %s" % vals

            if addr in self.cache:

                ll = self.cache[addr]
                record['lat'] = ll[0]
                record['lon'] = ll[1]

            else:

                result = self.geocoder.geocode(addr)

                candidates = result.get('candidates', None)
                if candidates:
                    c = candidates[0]

                    record['lat'] = c.y
                    record['lon'] = c.x

        return record
Ejemplo n.º 19
0
class GeocoderTest(OmgeoTestCase):
    g = None # not set until set up
    BING_KEY_REQUIRED_MSG = 'Enter a Bing Maps API key to run the bing tests'
    
    def setUp(self):
        # Viewbox objects
        vb = {}
        vb['callowhill'] = Viewbox(-75.162628, 39.962769, -75.150963, 39.956322)
        # PlaceQuery objects
        self.pq = {}
        # North American Addresses:
        self.pq['azavea'] = PlaceQuery('340 N 12th St Ste 402 Philadelphia PA')
        self.pq['ambiguous_azavea'] = PlaceQuery('340 12th St Ste 402 Philadelphia PA')
        self.pq['wolf'] = PlaceQuery('Wolf Building')
        self.pq['wolf_philly'] = PlaceQuery('Wolf Building, Philadelphia PA')
        self.pq['wolf_bounded'] = PlaceQuery('Wolf Building', viewbox=vb['callowhill'])
        self.pq['alpha_774R_W_Central_Ave'] = PlaceQuery('774R W Central Ave Alpha NJ')
        self.pq['alpha_774_W_Central_Ave_Rear'] = PlaceQuery('774 W Central Ave Rear Alpha NJ')
        self.pq['8_kirkbride'] = PlaceQuery('8 Kirkbride Rd 08822')
        self.pq['george_washington'] = PlaceQuery('201 W Montmorency Blvd, George, Washington')
        self.pq['pine_needles_dr'] = PlaceQuery('11761 pine needles providence forge')
        self.pq['pine_needles_ct'] = PlaceQuery('5328 pine needles providence forge')
        self.pq['pine_needles_terr'] = PlaceQuery('5359 pine needles providence forge')
        self.pq['moorestown_hyphenated'] = PlaceQuery('111-113 W Main St Moorestown NJ')
        self.pq['willow_street'] = PlaceQuery('2819F Willow Street Pike Willow Street PA')
        self.pq['quebec'] = PlaceQuery('756 Rue Berri Montreal QC', country='CA')
        self.pq['quebec_accent'] = PlaceQuery('527 Ch. Beauséjour, Saint-Elzéar-de-Témiscouata QC')
        self.pq['quebec_hyphenated'] = PlaceQuery('227-227A Rue Commerciale, Saint-Louis-du-Ha! Ha! QC')
        # European Addresses:
        self.pq['london_pieces'] = PlaceQuery(address='31 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line'] = PlaceQuery('31 Maiden Lane, London WC2E', country='UK')
        self.pq['london_pieces_hyphenated'] = PlaceQuery(address='31-32 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line_hyphenated'] = PlaceQuery('31-32 Maiden Lane London WC2E', country='UK')
        # Oceanian Addresses:
        self.pq['karori'] = PlaceQuery('102 Karori Road Karori Wellington', country='NZ')

        # Set up geocoders
        if ESRI_MAPS_API_KEY is None:
            esri_settings = {}
        else:
            esri_settings = dict(api_key=ESRI_MAPS_API_KEY)
        self.service_esri_na = ['omgeo.services.EsriNA', dict(settings=esri_settings)]
        self.service_esri_eu = ['omgeo.services.EsriEU', dict(settings=esri_settings)]
        g_sources = [self.service_esri_na, self.service_esri_eu]
        self.g_esri_na = Geocoder([self.service_esri_na])
        self.g_esri_eu = Geocoder([self.service_esri_eu])
        if BING_MAPS_API_KEY is not None:
            bing_settings = dict(api_key=BING_MAPS_API_KEY)
            self.service_bing = ['omgeo.services.Bing', dict(settings=bing_settings)]
            g_sources.append(self.service_bing)
            self.g_bing = Geocoder([self.service_bing])
        self.service_nom = ['omgeo.services.Nominatim', {}]
        g_sources.append(self.service_nom)
        self.g_nom = Geocoder([self.service_nom])
        self.g = Geocoder(sources=g_sources) # main geocoder used for tests
        # other geocoders for services not used in self.g
        self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
        self.g_esri_na_soap = Geocoder([['omgeo.services.EsriNASoap', {}]])
        self.g_esri_eu_soap = Geocoder([['omgeo.services.EsriEUSoap', {}]])
        
    def tearDown(self):
        pass

    def test_geocode_azavea(self):
        candidates = self.g.geocode(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(len(candidates) > 1, False, 'More than one candidate returned.')
        
    def test_geocode_snap_points_1(self):
        candidates = self.g.geocode(self.pq['8_kirkbride'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(len(candidates) > 1, False, 'More than one candidate returned.')
        
    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_snap_points_2(self):
        candidates = self.g.geocode(self.pq['alpha_774_W_Central_Ave_Rear'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(len(candidates) > 1, False, 'More than one candidate returned.')

    def test_geocode_esri_na_us_soap(self):
        candidates = self.g_esri_na_soap.geocode(PlaceQuery('340 N 12th St., Philadelphia, PA, US'))
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    def test_geocode_esri_na_us(self):
        candidates = self.g_esri_na.geocode(self.pq['alpha_774_W_Central_Ave_Rear'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    def test_geocode_esri_eu_soap(self):
        candidates = self.g_esri_eu_soap.geocode(PlaceQuery(
            address='31 Maiden Lane', city='London', country='UK'))
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    def test_geocode_esri_na_nz(self):
        candidates = self.g_esri_na.geocode(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, False,
                         'Found New Zealand address when this should only'
                         'be using the North American ESRI geocoder.')

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_bing(self):
        candidates = self.g_bing.geocode(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        
    def test_geocode_nom(self):
        candidates = self.g_nom.geocode(PlaceQuery('1200 Callowhill St, Philadelphia, PA, 19123'))
        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 test_geocode_dc_address(self):
        candidates = self.g_dc.geocode(PlaceQuery('1600 pennsylvania'))
        self.assertTrue(len(candidates) > 0, 'No candidates returned.')
        self.assertTrue(candidates[0].locator == 'DC Address',
                        'Expected 1600 pennsylvania to be an address match')

    def test_geocode_dc_intersection(self):
        candidates = self.g_dc.geocode(PlaceQuery('h and 15th'))
        self.assertTrue(len(candidates) > 0, 'No candidates returned.')
        self.assertTrue(candidates[0].locator == 'DC Intersection',
                        'h and 15th to be an intersection match')

    def test_geocode_dupepicker(self):
        candidates = self.g.geocode(self.pq['ambiguous_azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        
    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_karori(self):
        def bldg_no_and_postal_in_addr(c):
            return ('102' in c.match_addr and '6012' in c.match_addr)
        candidates = self.g.geocode(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(any([bldg_no_and_postal_in_addr(c) for c in candidates]), True,
                         'Could not find bldg. no. "102" and postcode "6012" in any address.')

    def _test_geocode_results_all_(self, verbosity=0, geocoder=Geocoder(),
                                   expected_results=16):
        """
        Geocode a list of addresses.  Some of these only work with Bing so 
        fewer results are expected when Bing is not used as a geocoder
        """
        if verbosity > 1: 
            logger.setLevel(logging.INFO)

        queries_with_results = 0
        for place in self.pq:
            logger.info(place)
            logger.info(len(place) * '-')
            candidates = geocoder.geocode(self.pq[place])
            if len(candidates) == 0:
                logger.info('Input: %s\n(no results)' % self.pq[place].query)
            else:
                queries_with_results += 1
                logger.info('Input:  %s' % self.pq[place].query)
                logger.info(map(lambda c: 'Output: %r (%s %s)\n' %
                    (c.match_addr, 
                    c.geoservice, 
                    [c.locator, c.score, c.confidence, c.entity]),
                    candidates))
        self.assertEqual(expected_results, queries_with_results,
                         'Got results for %d of %d queries.' % (queries_with_results, len(self.pq)))

    def _test_geocode_results_all(self):
        if BING_MAPS_API_KEY is None:
            expected_results=16
        else:
            self.g.add_source(['omgeo.services.Bing',
                     {'settings':{'api_key':BING_MAPS_API_KEY}}])
            expected_results=len(self.pq)
        self._test_geocode_results_all_(geocoder=self.g, expected_results=len(self.pq))

    def test_esri_geocoder_na_default_override(self):
        # Bug in 3.1 - the EsriNA and EsriEU append processors rather than
        # replace
        geocoder = Geocoder([['omgeo.services.EsriNA',
                            {'postprocessors': [AttrFilter([
                                'rooftop',
                                'interpolation',
                                'postal_specific'],
                                'locator')]}]])

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors),
            'EsriNA geocoder incorrectly processed defaults')
        self.assertEqual('AttrFilter',
            geocoder._sources[0]._postprocessors[0].__class__.__name__,
            'EsriNA geocoder incorrectly processed defaults')

    def test_esri_geocoder_eu_default_override(self):
        # Bug in 3.1 - the EsriNA and EsriEU append processors rather than
        # replace
        geocoder = Geocoder([['omgeo.services.EsriEU',
                            {'postprocessors': [AttrFilter([
                                'rooftop',
                                'interpolation',
                                'postal_specific'],
                                'locator')]}]])

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors),
            'EsriEU geocoder incorrectly processed defaults')
        self.assertEqual('AttrFilter',
            geocoder._sources[0]._postprocessors[0].__class__.__name__,
            'EsriEU geocoder incorrectly processed defaults')
Ejemplo n.º 20
0
    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
                }
            }]])
Ejemplo n.º 21
0
class GeocoderTest(OmgeoTestCase):
    """Tests using various geocoding APIs. Requires internet connection."""
    g = None  # not set until set up
    BING_KEY_REQUIRED_MSG = 'Enter a Bing Maps API key to run the Bing tests.'
    MAPQUEST_KEY_REQUIRED_MSG = 'Enter a MapQuest API key to run the MapQuest tests. '\
                                'Keys can be obtained at http://developer.mapquest.com/.'
    PELIAS_KEY_REQUIRED_MSG = 'Enter a Pelias service search API key to run Pelias tests. '\
                              'Keys can be obtained at https://geocode.earth/.'
    GOOGLE_KEY_REQUIRED_MSG = 'Enter a Google API key to run Google tests.'
    ESRI_KEY_REQUIRED_MSG = 'Enter a Esri Client ID & Secret to run authenticated Esri tests.'

    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 tearDown(self):
        pass

    def test_geocode_azavea(self):
        candidates = self.g.get_candidates(self.pq['azavea'])
        self.assertOneCandidate(candidates)

    def test_impatiently_geocode_azavea(self):
        candidates = self.impatient_geocoder.get_candidates(self.pq['azavea'])
        self.assertEqual(
            len(candidates) == 0, True,
            'Candidates were unexpectedly returned in under 10ms.')

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_snap_points_2(self):
        """
        Bing geocoder expected to return the same place twice -- one with city as Alpha,
        and one with city as Phillipsburg. This test checks that only one is picked.
        """
        candidates = self.g_bing.get_candidates(
            self.pq['alpha_774_W_Central_Ave_Rear'])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_senado_mx(self):
        """
        Attempt to geocode ``Paseo de la Reforma 135, Tabacalera,
        Cuauhtémoc, Distrito Federal, 06030``.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq['senado_mx'])
        self.assertOneCandidate(candidates)
        search_text = 'Paseo de la Reforma 135'
        self.assertEqual(
            search_text in candidates[0].match_addr, True,
            '"%s" not found in match_addr. Got "%s".' %
            (search_text, candidates[0].match_addr))

    def test_geocode_structured_esri_wgs_senado_mx(self):
        """
        Attempt to geocode ``Paseo de la Reforma 135, Tabacalera,
        Cuauhtémoc, Distrito Federal, 06030`` using a structured query to
        EsriWGS.
        """
        candidates = self.g_esri_wgs.get_candidates(
            self.pq['senado_mx_struct'])
        self.assertOneCandidate(candidates)
        search_text = 'Paseo de la Reforma 135'
        self.assertEqual(
            search_text in candidates[0].match_addr, True,
            '"%s" not found in match_addr. Got "%s".' %
            (search_text, candidates[0].match_addr))

    def test_geocode_esri_wgs_340_12th_bounded(self):
        """
        Trying to geocode ``340 12th St, Philadelphia PA`` would normally return results
        for both ``340 N 12th St`` and ``340 S 12th St``. Using a bounding box around Callowhill,
        we should only get the former.
        """
        candidates = self.g_esri_wgs.get_candidates(
            self.pq['bounded_340_12th'])
        self.assertOneCandidate(candidates)
        self.assertEqual(
            '340 N 12th' in candidates[0].match_addr, True,
            '"340 N 12th" not found in match_addr. Got "%s"' %
            candidates[0].match_addr)

    def test_geocode_esri_wgs_zip_plus_4(self):
        """Check that geocoding 19127-1112 returns one result."""
        candidates = self.g_esri_wgs_postal_ok.get_candidates(
            self.pq['zip_plus_4_in_postal_plus_country'])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_multipart(self):
        """Check that geocoding multipart address returns one result."""
        candidates = self.g_esri_wgs.get_candidates(
            self.pq['willow_street_parts'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(ESRI_CLIENT_SECRET is None or ESRI_CLIENT_ID is None,
                     ESRI_KEY_REQUIRED_MSG)
    def test_geocode_esri_wgs_auth(self):
        """Test that using authentication with the ESRI WGS geocoder is working"""
        candidates = self.g_esri_wgs_auth.get_candidates(self.pq['azavea'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_bing(self):
        """Test Azavea's address using Bing geocoder"""
        candidates = self.g_bing.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skip("FIXME")
    def test_geocode_mapquest(self):
        """Test Azavea's address using MapQuest geocoder."""
        candidates = self.g_mapquest.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skip("FIXME")
    def test_geocode_mapquest_ssl(self):
        """Test Azavea's address using secure MapQuest geocoder."""
        candidates = self.g_mapquest_ssl.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(PELIAS_API_KEY is None, PELIAS_KEY_REQUIRED_MSG)
    def test_geocode_pelias(self):
        """Test Azavea's address using Pelias geocoder"""
        candidates = self.g_pelias.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skip("FIXME")
    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 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_EsriWGS_address_components(self):
        """Make sure EsriWGS returns address components"""
        candidate = self.g_esri_wgs.get_candidates(self.pq['azavea'])[0]
        self._test_address_components(candidate)

    def test_census_address_components(self):
        """Make sure census geocoder returns address components"""
        candidate = self.g_census.get_candidates(self.pq['azavea'])[0]
        self._test_address_components(candidate)

    def test_geocode_dupepicker(self):
        """
        Check that '340 12th St returns results'
        """
        candidates = self.g.get_candidates(self.pq['ambiguous_azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_karori(self):
        """
        Check that '102 Karori Road Karori Wellington' returns an address
        with the correct house number and postcode.
        """
        candidates = self.g_bing.get_candidates(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(
            any([('102' in c.match_addr and '6012' in c.match_addr)
                 for c in candidates]), True,
            'Could not find bldg. no. "102" and postcode "6012" in any address.'
        )

    def _test_address_components(self, candidate):
        for field in [
                'match_streetaddr', 'match_city', 'match_subregion',
                'match_region', 'match_postal', 'match_country'
        ]:
            self.assertIsNotNone(getattr(candidate, field, None),
                                 msg='Missing address component %s' % field)

    def _test_geocode_results_all_(self,
                                   verbosity=0,
                                   geocoder=Geocoder(),
                                   expected_results=16):
        """
        Geocode a list of addresses. Some of these only work with Bing so
        fewer results are expected when Bing is not used as a geocoder.
        """
        if verbosity > 1:
            logger.setLevel(logging.INFO)

        queries_with_results = 0
        for place in self.pq:
            logger.info(place)
            logger.info(len(place) * '-')
            candidates = geocoder.get_candidates(self.pq[place])
            if len(candidates) == 0:
                logger.info('Input: %s\n(no results)' % self.pq[place].query)
            else:
                queries_with_results += 1
                logger.info('Input:  %s' % self.pq[place].query)
                logger.info([
                    'Output: %r (%s %s)\n' %
                    (c.match_addr, c.geoservice,
                     [c.locator, c.score, c.confidence, c.entity])
                    for c in candidates
                ])
        self.assertEqual(
            expected_results, queries_with_results,
            'Got results for %d of %d queries.' %
            (queries_with_results, len(self.pq)))

    def _test_geocode_results_all(self):
        if BING_MAPS_API_KEY is None:
            expected_results = 16
        else:
            self.g.add_source([
                'omgeo.services.Bing', {
                    'settings': {
                        'api_key': BING_MAPS_API_KEY
                    }
                }
            ])
            expected_results = len(self.pq)
        self._test_geocode_results_all_(geocoder=self.g,
                                        expected_results=expected_results)

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    def test_google_geocode_azavea(self):
        candidates = self.g_google.get_candidates(self.pq['azavea'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    def test_google_geocode_multipart(self):
        """Check that geocoding multipart address returns one result."""
        candidates = self.g_google.get_candidates(
            self.pq['willow_street_parts'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    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')

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    def test_google_geocode_without_postprocessor_allows_people(self):
        candidates = self.g_google_wo_postprocess.get_candidates(
            self.pq['robert_cheetham'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    def test_google_geocode_excludes_people(self):
        candidates = self.g_google.get_candidates(self.pq['robert_cheetham'])
        self.assertEqual(
            len(candidates) == 0, True, 'Candidate(s) unexpectedly returned.')
Ejemplo n.º 22
0
class GeocoderTest(OmgeoTestCase):
    """Tests using various geocoding APIs. Requires internet connection."""
    g = None # not set until set up
    BING_KEY_REQUIRED_MSG = 'Enter a Bing Maps API key to run the Bing tests.'
    MAPQUEST_KEY_REQUIRED_MSG = 'Enter a MapQuest API key to run the MapQuest tests. '\
                                'Keys can be obtained at http://developer.mapquest.com/.'
    MAPZEN_KEY_REQUIRED_MSG = 'Enter a Mapzen Search API key to run Mapzen ' \
                              'tests. Keys can be obtained at ' \
                              'https://mapzen.com/developers/sign_in.'

    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'),
                    # 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 MAPZEN_API_KEY is not None:
            mapzen_settings = dict(api_key=MAPZEN_API_KEY)
            self.g_mapzen = Geocoder([['omgeo.services.Mapzen', {'settings':
            mapzen_settings}]])

        #: main geocoder used for tests, using default APIs
        self.g = Geocoder()

        # Set up params for old ESRI rest services:
        esri_settings = {} if ESRI_MAPS_API_KEY is None else {'api_key': ESRI_MAPS_API_KEY}
        old_esri_params = {'settings': esri_settings}

        # geocoders using individual services
        # self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
        self.g_esri_na = Geocoder([['omgeo.services.EsriNA', old_esri_params]])
        self.g_esri_eu = Geocoder([['omgeo.services.EsriEU', old_esri_params]])
        self.g_esri_na_soap = Geocoder([['omgeo.services.EsriNASoap', {}]])
        self.g_esri_eu_soap = Geocoder([['omgeo.services.EsriEUSoap', {}]])
        self.g_esri_wgs = Geocoder([['omgeo.services.EsriWGS', {}]])
        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.01}}]])

    def tearDown(self):
        pass

    def test_geocode_azavea(self):
        candidates = self.g.get_candidates(self.pq['azavea'])
        self.assertOneCandidate(candidates)

    def test_impatiently_geocode_azavea(self):
        candidates = self.impatient_geocoder.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) == 0, True, 'Candidates were unexpectedly returned in under 10ms.')

    def test_geocode_snap_points_1(self):
        """
        Geocoder expected to return the same place twice -- one with city as Flemington,
        and one with city as Readington Twp. This test checks that only one is picked.
        """
        candidates = self.g_esri_na.get_candidates(self.pq['8_kirkbride'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_snap_points_2(self):
        """
        Bing geocoder expected to return the same place twice -- one with city as Alpha,
        and one with city as Phillipsburg. This test checks that only one is picked.
        """
        candidates = self.g_bing.get_candidates(self.pq['alpha_774_W_Central_Ave_Rear'])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_senado_mx(self):
        """
        Attempt to geocode ``Paseo de la Reforma 135, Tabacalera,
        Cuauhtémoc, Distrito Federal, 06030``.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq['senado_mx'])
        self.assertOneCandidate(candidates)
        search_text = 'Paseo de la Reforma 135'
        self.assertEqual(search_text in candidates[0].match_addr, True,
                         '"%s" not found in match_addr. Got "%s".'
                         % (search_text, candidates[0].match_addr))

    def test_geocode_structured_esri_wgs_senado_mx(self):
        """
        Attempt to geocode ``Paseo de la Reforma 135, Tabacalera,
        Cuauhtémoc, Distrito Federal, 06030`` using a structured query to
        EsriWGS.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq['senado_mx_struct'])
        self.assertOneCandidate(candidates)
        search_text = 'Paseo de la Reforma 135'
        self.assertEqual(search_text in candidates[0].match_addr, True,
                         '"%s" not found in match_addr. Got "%s".'
                         % (search_text, candidates[0].match_addr))

    def test_geocode_esri_wgs_340_12th_bounded(self):
        """
        Trying to geocode ``340 12th St, Philadelphia PA`` would normally return results
        for both ``340 N 12th St`` and ``340 S 12th St``. Using a bounding box around Callowhill,
        we should only get the former.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq['bounded_340_12th'])
        self.assertOneCandidate(candidates)
        self.assertEqual('340 N 12th' in candidates[0].match_addr, True,
                         '"340 N 12th" not found in match_addr. Got "%s"' % candidates[0].match_addr)

    def test_geocode_esri_wgs_zip_plus_4(self):
        """Check that geocoding 19127-1112 returns one result."""
        candidates = self.g_esri_wgs_postal_ok.get_candidates(self.pq['zip_plus_4_in_postal_plus_country'])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_multipart(self):
        """Check that geocoding multipart address returns one result."""
        candidates = self.g_esri_wgs.get_candidates(self.pq['willow_street_parts'])
        self.assertOneCandidate(candidates)

    def test_bounded_no_viewbox(self):
        """
        Should return a nice error saying that PlaceQuery can't be bounded without Viewbox.
        """
        pass

    def test_geocode_esri_na_us_soap(self):
        """Test ESRI North America SOAP geocoder"""
        location = '340 N 12th St., Philadelphia, PA, US'
        candidates = self.g_esri_na_soap.get_candidates(location)
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned for %s.' % location)

    def test_geocode_esri_na_us(self):
        """Test ESRI North America REST geocoder"""
        location = '340 N 12th St., Philadelphia, PA, US'
        candidates = self.g_esri_na.get_candidates(location)
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned for %s.' % location)

    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.')

    def test_geocode_esri_na_nz(self):
        """
        Test ESRI North America REST geocoder using a city in New Zealand.
        """
        candidates = self.g_esri_na.get_candidates(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, False,
                         'Found New Zealand address when this should only'
                         'be using the North American ESRI geocoder. '
                         'Candidates are %s.' % candidates)

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_bing(self):
        """Test Azavea's address using Bing geocoder"""
        candidates = self.g_bing.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(MAPQUEST_API_KEY is None, MAPQUEST_KEY_REQUIRED_MSG)
    def test_geocode_mapquest(self):
        """Test Azavea's address using MapQuest geocoder."""
        candidates = self.g_mapquest.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(MAPQUEST_API_KEY is None, MAPQUEST_KEY_REQUIRED_MSG)
    def test_geocode_mapquest_ssl(self):
        """Test Azavea's address using secure MapQuest geocoder."""
        candidates = self.g_mapquest_ssl.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(MAPZEN_API_KEY is None, MAPZEN_KEY_REQUIRED_MSG)
    def test_geocode_mapzen(self):
        """Test Azavea's address using Mapzen geocoder"""
        candidates = self.g_mapzen.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    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 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_address_components(self):
        """Make sure EsriWGS returns address components"""
        candidate = self.g_esri_wgs.get_candidates(self.pq['azavea'])[0]
        self._test_address_components(candidate)
        candidate = self.g_census.get_candidates(self.pq['azavea'])[0]
        self._test_address_components(candidate)
    # def test_geocode_dc_address(self):
    #     """
    #     Check that '1600 Pennsylvania' returns first result using DC address locator.
    #     """
    #     candidates = self.g_dc.get_candidates(PlaceQuery('1600 pennsylvania'))
    #     self.assertTrue(len(candidates) > 0, 'No candidates returned.')
    #     self.assertTrue(candidates[0].locator == 'DC Address',
    #                     'Expected 1600 pennsylvania to be an address match')

    # def test_geocode_dc_intersection(self):
    #     """
    #     Check that 'H and 15th' returns first result using DC intersection locator.
    #     """
    #     candidates = self.g_dc.get_candidates(PlaceQuery('h and 15th'))
    #     self.assertTrue(len(candidates) > 0, 'No candidates returned.')
    #     self.assertTrue(candidates[0].locator == 'DC Intersection',
    #                     'h and 15th to be an intersection match')

    def test_geocode_dupepicker(self):
        """
        Check that '340 12th St returns results'
        """
        candidates = self.g.get_candidates(self.pq['ambiguous_azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_karori(self):
        """
        Check that '102 Karori Road Karori Wellington' returns an address
        with the correct house number and postcode.
        """
        candidates = self.g_bing.get_candidates(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(any([('102' in c.match_addr and '6012' in c.match_addr) for c in candidates]),
            True, 'Could not find bldg. no. "102" and postcode "6012" in any address.')

    def _test_address_components(self, candidate):
            for field in ['match_streetaddr', 'match_city', 'match_subregion', 'match_region',
                          'match_postal', 'match_country']:
                self.assertIsNotNone(getattr(candidate, field, None),
                                     msg='Missing address component %s' % field)

    def _test_geocode_results_all_(self, verbosity=0, geocoder=Geocoder(),
                                   expected_results=16):
        """
        Geocode a list of addresses. Some of these only work with Bing so
        fewer results are expected when Bing is not used as a geocoder.
        """
        if verbosity > 1:
            logger.setLevel(logging.INFO)

        queries_with_results = 0
        for place in self.pq:
            logger.info(place)
            logger.info(len(place) * '-')
            candidates = geocoder.get_candidates(self.pq[place])
            if len(candidates) == 0:
                logger.info('Input: %s\n(no results)' % self.pq[place].query)
            else:
                queries_with_results += 1
                logger.info('Input:  %s' % self.pq[place].query)
                logger.info(map(lambda c: 'Output: %r (%s %s)\n' %
                    (c.match_addr,
                    c.geoservice,
                    [c.locator, c.score, c.confidence, c.entity]),
                    candidates))
        self.assertEqual(expected_results, queries_with_results,
                         'Got results for %d of %d queries.' % (queries_with_results, len(self.pq)))

    def _test_geocode_results_all(self):
        if BING_MAPS_API_KEY is None:
            expected_results=16
        else:
            self.g.add_source(['omgeo.services.Bing',
                     {'settings':{'api_key':BING_MAPS_API_KEY}}])
            expected_results=len(self.pq)
        self._test_geocode_results_all_(geocoder=self.g, expected_results=len(self.pq))

    def test_esri_geocoder_na_default_override(self):
        """
        Test for default argument bug in 3.1 --
        EsriNA and EsriEU append processors rather than replace them
        """
        geocoder = Geocoder([['omgeo.services.EsriNA',
                            {'postprocessors': [AttrFilter([
                                'rooftop',
                                'interpolation',
                                'postal_specific'],
                                'locator')]}]])

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors),
            'EsriNA geocoder incorrectly processed defaults')
        self.assertEqual('AttrFilter',
            geocoder._sources[0]._postprocessors[0].__class__.__name__,
            'EsriNA geocoder incorrectly processed defaults')

    def test_esri_geocoder_eu_default_override(self):
        """
        Test for default argument bug in 3.1 --
        EsriNA and EsriEU append processors rather than replace them
        """
        geocoder = Geocoder([['omgeo.services.EsriEU',
                            {'postprocessors': [AttrFilter([
                                'rooftop',
                                'interpolation',
                                'postal_specific'],
                                'locator')]}]])

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors),
            'EsriEU geocoder incorrectly processed defaults')
        self.assertEqual('AttrFilter',
            geocoder._sources[0]._postprocessors[0].__class__.__name__,
            'EsriEU geocoder incorrectly processed defaults')
Ejemplo n.º 23
0
from __future__ import unicode_literals
from __future__ import division

import json

from django.http import HttpResponse
from django.utils.translation import ugettext as _
from django.conf import settings
from django.contrib.gis.geos.point import Point

from django_tinsel.decorators import json_api_call

from omgeo import Geocoder
from omgeo.places import Viewbox, PlaceQuery

geocoder = Geocoder(sources=settings.OMGEO_SETTINGS, postprocessors=[])
geocoder_for_magic_key = Geocoder(
    sources=settings.OMGEO_SETTINGS_FOR_MAGIC_KEY)


def _omgeo_candidate_to_dict(candidate, srid=3857):
    p = Point(candidate.x, candidate.y, srid=candidate.wkid)
    if candidate.wkid != srid:
        p.transform(srid)
    return {
        'address': candidate.match_addr,
        'region': candidate.match_region,
        'city': candidate.match_city,
        'srid': p.srid,
        'score': candidate.score,
        'x': p.x,
Ejemplo n.º 24
0
    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'),
            # 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 MAPZEN_API_KEY is not None:
            mapzen_settings = dict(api_key=MAPZEN_API_KEY)
            self.g_mapzen = Geocoder([['omgeo.services.Mapzen', {'settings': mapzen_settings}]])

        if GOOGLE_API_KEY is not None:
            self.g_google = Geocoder([['omgeo.services.Google',
                                     {'settings': {'api_key': GOOGLE_API_KEY}}]])

        #: main geocoder used for tests, using default APIs
        self.g = Geocoder()

        # Set up params for old ESRI rest services:
        esri_settings = {} if ESRI_MAPS_API_KEY is None else {'api_key': ESRI_MAPS_API_KEY}
        old_esri_params = {'settings': esri_settings}

        # geocoders using individual services
        # self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
        self.g_esri_na = Geocoder([['omgeo.services.EsriNA', old_esri_params]])
        self.g_esri_eu = Geocoder([['omgeo.services.EsriEU', old_esri_params]])
        self.g_esri_wgs = Geocoder([['omgeo.services.EsriWGS', {}]])
        if ESRI_MAPS_API_KEY is not None:  # SOAP services are subscriber-only now
            self.g_esri_na_soap = Geocoder([['omgeo.services.EsriNASoap', {}]])
            self.g_esri_eu_soap = Geocoder([['omgeo.services.EsriEUSoap', {}]])

        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.01}}]])
Ejemplo n.º 25
0
##pyodbc and omgeo are required.
## >pip install pyodbc
## >pip install omgeo


import pyodbc,csv
from omgeo import Geocoder

#build Geocoder instance
g = Geocoder()

#Connect to Falcon using SQL Server Native Client Connection String
sqlcon =   pyodbc.connect("Driver={SQL Server Native Client 10.0};Server=FALCON;Database=student_view;Trusted_Connection=yes;")
sqlcur = sqlcon.cursor()

#Query that will be passed to the cursor
query = """SELECT cec_key,addr_1,city,state,zip5
        FROM client_entering_class
        WHERE
        school_key = ?
        AND entry_year = ?
        AND app_stat_ind = 1
        """

#Containers for data
students = []
errors = []

#Define fixNull function for data cleaning
def fixNull(value):
    if value is None:
Ejemplo n.º 26
0
class AddressConverter(object):

    def __init__(self, curs):
        self.curs = curs
        self.geolocator = GoogleV3()
        self.nominatim = nominatim.Geocoder()
        
        self.geocoder = Geocoder()
        self.re_numbers = re.compile("^\d+$")

    def reject_all_numbers(self, address):
        if self.re_numbers.search(address):
            logger.info("Rejected by reject_all_numbers")
            return True
        return False

    def reject_short_words(self, address, length=4):
        if len(address) <= length:
            logger.info("Rejected by reject_short_words")
            return True
        return False

    def reject_large_main_places(self, address, threshold=15000):
        if address in main_places:
            population = main_places[address]["Population"]
            if int(population) >= threshold:
                return True
        return False

    def reject_resolution_to_main_place(self, address, threshold=15000):
        parts = address.split(",")
        first = parts[0].strip().lower()
        return self.reject_large_main_places(first, threshold)

    def reject_partial_match(self, result):
        if "partial_match" in result and result["partial_match"]:
            return True
        return False
        
    def resolve_address_google(self, address, **kwargs):
        try:
            encoded_address = encode(address)
            address = urllib.quote(encoded_address)

            url = "https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false&region=za&key=%s" % (address, configuration["environment"]["google_key"])
            response = urllib2.urlopen(url)
            js = response.read()
            try:
                js = json.loads(js)
            except ValueError:
                logger.exception("Error trying to resolve %s" % address)
                return None

            results = []
            if "results" in js and len(js["results"]) > 0:
                for result in js["results"]:

                    res = self.reject_partial_match(result)
                    if res: continue

                    if "reject_resolution_to_main_place" in kwargs:
                        try:
                            res = self.reject_resolution_to_main_place(result["formatted_address"], int(kwargs["reject_resolution_to_main_place"][0]))
                        except (ValueError, TypeError):
                            res = self.resolution_to_main_place(result["formatted_address"])
                        if res: continue

                    geom = result["geometry"]["location"]
                    results.append({
                        "lat" : geom["lat"],
                        "lng" : geom["lng"],   
                        "formatted_address" : result["formatted_address"],
                        "source" : "Google Geocoding API",
                    })

                if len(results) == 0: return None
                return results
        except Exception:
            logger.exception("Error trying to resolve %s" % address)
        return None
        
    def resolve_address_esri(self, address):
        result = self.geocoder.geocode(address + ", South Africa")
        if not result: return None
        if not "candidates" in result: return None
        if len(result["candidates"]) == 0: return None
        candidate = result["candidates"][0]
        address = candidate.match_addr
        latitude = candidate.y
        longitude = candidate.x

        return address, latitude, longitude

    def resolve_address_nominatim(self, address, **kwargs):
        encoded_address = encode(address)
        results = self.nominatim.geocode(encoded_address)
        return [
            {
                "lat" : r["lat"],
                "lng" : r["lon"],   
                "formatted_address" : r["display_name"],
                "source" : "Nominatim",
            }
            for r in results
        ]

    def convert_address(self, address, **kwargs):
        address = address.strip()
        if address == "": return None

        if "reject_numbers" in kwargs and self.reject_all_numbers(address): return None
        if "reject_short_words" in kwargs:
            try:
                val = self.reject_short_words(address, int(kwargs["reject_short_words"][0]))
            except (TypeError, ValueError):
                val = self.reject_short_words(address)
            if val: return None

        if "reject_large_main_places" in kwargs:
            try:
                val = self.reject_large_main_places(address, int(kwargs["reject_large_main_places"][0]))
            except (TypeError, ValueError):
                val = self.reject_large_main_places(address)
            if val: return None

        if not "south africa" in address.lower():
            address = address + ", South Africa"

        if "enable_nominatim" in kwargs:
            results = self.resolve_address_nominatim(address, **kwargs)

            if len(results) > 0:
                return results

        return self.resolve_address_google(address, **kwargs)

    def convert_to_geography(self, sql, latitude, longitude):
        poi = (longitude, latitude)

        self.curs.execute(sql, poi)

        return self.curs.fetchall()
Ejemplo n.º 27
0
class GeocoderTest(OmgeoTestCase):
    g = None # not set until set up
    def setUp(self):
        # Viewbox objects
        vb = {}
        vb['callowhill'] = Viewbox(-75.162628, 39.962769, -75.150963, 39.956322)
        # PlaceQuery objects
        self.pq = {}
        # North American Addresses:
        self.pq['azavea'] = PlaceQuery('340 N 12th St Ste 402 Philadelphia PA')
        self.pq['ambiguous_azavea'] = PlaceQuery('340 12th St Ste 402 Philadelphia PA')
        self.pq['wolf'] = PlaceQuery('Wolf Building')
        self.pq['wolf_philly'] = PlaceQuery('Wolf Building, Philadelphia PA')
        self.pq['wolf_bounded'] = PlaceQuery('Wolf Building', viewbox=vb['callowhill'])
        self.pq['alpha_774R_W_Central_Ave'] = PlaceQuery('774R W Central Ave Alpha NJ')
        self.pq['alpha_774_W_Central_Ave_Rear'] = PlaceQuery('774 W Central Ave Rear Alpha NJ')
        self.pq['pine_needles_dr'] = PlaceQuery('11761 pine needles providence forge')
        self.pq['pine_needles_ct'] = PlaceQuery('5328 pine needles providence forge')
        self.pq['pine_needles_terr'] = PlaceQuery('5359 pine needles providence forge')
        self.pq['moorestown_hyphenated'] = PlaceQuery('111-113 W Main St Moorestown NJ')
        self.pq['willow_street'] = PlaceQuery('2819F Willow Street Pike Willow Street PA')
        self.pq['quebec'] = PlaceQuery('756 Rue Berri Montreal QC', country='CA')
        self.pq['quebec_bang'] = PlaceQuery('177 Rue Commerciale, Saint-Louis-du-Ha! Ha! QC')
        self.pq['quebec_accent'] = PlaceQuery('527 Ch. Beauséjour, Saint-Elzéar-de-Témiscouata QC')
        self.pq['quebec_hyphenated'] = PlaceQuery('227-227A Rue Commerciale, Saint-Louis-du-Ha! Ha! QC')
        # European Addresses:
        self.pq['london_pieces'] = PlaceQuery(address='31 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line'] = PlaceQuery('31 Maiden Lane, London WC2E', country='UK')
        self.pq['london_pieces_hyphenated'] = PlaceQuery(address='31-32 Maiden Lane', city='London', country='UK')
        self.pq['london_one_line_hyphenated'] = PlaceQuery('31-32 Maiden Lane London WC2E', country='UK')
        # Oceanic Addresses:
        self.pq['karori'] = PlaceQuery('102 Karori Road Karori Wellington', country='NZ')

        # Geocoder objects
        self.g = Geocoder()
        if ESRI_MAPS_API_KEY is not None:
            self.g_esri_na = Geocoder([['omgeo.services.EsriNA',
                    {'settings':{'api_key':ESRI_MAPS_API_KEY}}]])
            self.g_esri_eu = Geocoder([['omgeo.services.EsriEU',
                    {'settings':{'api_key':ESRI_MAPS_API_KEY}}]])
        else:
            self.g_esri_na = Geocoder([['omgeo.services.EsriNA', {}]])
            self.g_esri_eu = Geocoder([['omgeo.services.EsriEU', {}]])

        self.g_bing = Geocoder([['omgeo.services.Bing', {'settings':{'api_key':BING_MAPS_API_KEY}}]])
        self.g_nom = Geocoder([['omgeo.services.Nominatim',{}]])
        self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])

    def tearDown(self):
        pass

    def test_geocode_azavea(self):
        candidates = self.g.geocode(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(len(candidates) > 1, False, 'More than one candidate returned.')

    def test_geocode_esri_na_us(self):
        candidates = self.g_esri_na.geocode(self.pq['alpha_774_W_Central_Ave_Rear'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    def test_geocode_esri_na_nz(self):
        candidates = self.g_esri_na.geocode(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, False, 'Found New Zealand address when this should only be using the North American ESRI geocoder.')

    def test_nom_bounded(self):
        candidates = self.g.geocode(PlaceQuery('8 Kirkbride Rd'))
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(BING_MAPS_API_KEY is None, 'Enter a Bing Maps API key to run the bing tests')
    def test_geocode_bing(self):
        candidates = self.g_bing.geocode(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    def test_geocode_dc_address(self):
        candidates = self.g_dc.geocode(PlaceQuery('1600 pennsylvania'))
        self.assertTrue(len(candidates) > 0, 'No candidates returned.')
        self.assertTrue(candidates[0].locator == 'DC Address', 'Expected 1600 pennsylvania to be an address match')

    def test_geocode_dc_intersection(self):
        candidates = self.g_dc.geocode(PlaceQuery('h and 15th'))
        self.assertTrue(len(candidates) > 0, 'No candidates returned.')
        self.assertTrue(candidates[0].locator == 'DC Intersection', 'h and 15th to be an intersection match')

    def test_geocode_dupepicker(self):
        candidates = self.g.geocode(self.pq['ambiguous_azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    def _test_geocode_results_all(self, verbosity=0, geocoder=Geocoder()):
        queries_with_results = 0
        for place in self.pq:
            if verbosity > 1: print '\n%s' % place
            if verbosity > 1: print len(place) * '-'
            candidates = geocoder.geocode(self.pq[place])
            if len(candidates) == 0:
                if verbosity > 1: print 'Input:  %s\n(no results)' % self.pq[place].query
            else:
                queries_with_results += 1
                if verbosity > 1: print 'Input:  %s' % self.pq[place].query
                for x in ['Output: %r (%s %s)' % (c.match_addr, c.geoservice, [c.locator, c.score, c.confidence, c.entity]) for c in candidates]:
                    if verbosity > 1: print x
        self.assertEqual(len(self.pq), queries_with_results, 'Got results for %d of %d queries.' % (queries_with_results, len(self.pq)))

    def test_geocode_results_all(self):
        if BING_MAPS_API_KEY is not None:
            self.g.add_source(['omgeo.services.Bing',
                     {'settings':{'api_key':BING_MAPS_API_KEY}}])
        self._test_geocode_results_all(geocoder=self.g)
Ejemplo n.º 28
0
class GeocoderTest(OmgeoTestCase):
    """Tests using various geocoding APIs. Requires internet connection."""
    g = None  # not set until set up
    BING_KEY_REQUIRED_MSG = 'Enter a Bing Maps API key to run the Bing tests.'
    MAPQUEST_KEY_REQUIRED_MSG = 'Enter a MapQuest API key to run the MapQuest tests. '\
                                'Keys can be obtained at http://developer.mapquest.com/.'
    MAPZEN_KEY_REQUIRED_MSG = 'Enter a Mapzen Search API key to run Mapzen ' \
                              'tests. Keys can be obtained at ' \
                              'https://mapzen.com/developers/sign_in.'
    ESRI_KEY_REQUIRED_MSG = 'Enter an ESRI API key to run ESRI SOAP tests.'
    GOOGLE_KEY_REQUIRED_MSG = 'Enter a Google API key to run Google tests.'

    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'),
            # 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 MAPZEN_API_KEY is not None:
            mapzen_settings = dict(api_key=MAPZEN_API_KEY)
            self.g_mapzen = Geocoder([['omgeo.services.Mapzen', {'settings': mapzen_settings}]])

        if GOOGLE_API_KEY is not None:
            self.g_google = Geocoder([['omgeo.services.Google',
                                     {'settings': {'api_key': GOOGLE_API_KEY}}]])

        #: main geocoder used for tests, using default APIs
        self.g = Geocoder()

        # Set up params for old ESRI rest services:
        esri_settings = {} if ESRI_MAPS_API_KEY is None else {'api_key': ESRI_MAPS_API_KEY}
        old_esri_params = {'settings': esri_settings}

        # geocoders using individual services
        # self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
        self.g_esri_na = Geocoder([['omgeo.services.EsriNA', old_esri_params]])
        self.g_esri_eu = Geocoder([['omgeo.services.EsriEU', old_esri_params]])
        self.g_esri_wgs = Geocoder([['omgeo.services.EsriWGS', {}]])
        if ESRI_MAPS_API_KEY is not None:  # SOAP services are subscriber-only now
            self.g_esri_na_soap = Geocoder([['omgeo.services.EsriNASoap', {}]])
            self.g_esri_eu_soap = Geocoder([['omgeo.services.EsriEUSoap', {}]])

        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.01}}]])

    def tearDown(self):
        pass

    def test_geocode_azavea(self):
        candidates = self.g.get_candidates(self.pq['azavea'])
        self.assertOneCandidate(candidates)

    def test_impatiently_geocode_azavea(self):
        candidates = self.impatient_geocoder.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) == 0, True,
                         'Candidates were unexpectedly returned in under 10ms.')

    @unittest.skipIf(ESRI_MAPS_API_KEY is None, ESRI_KEY_REQUIRED_MSG)
    def test_geocode_snap_points_1(self):
        """
        Geocoder expected to return the same place twice -- one with city as Flemington,
        and one with city as Readington Twp. This test checks that only one is picked.
        """
        candidates = self.g_esri_na.get_candidates(self.pq['8_kirkbride'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_snap_points_2(self):
        """
        Bing geocoder expected to return the same place twice -- one with city as Alpha,
        and one with city as Phillipsburg. This test checks that only one is picked.
        """
        candidates = self.g_bing.get_candidates(self.pq['alpha_774_W_Central_Ave_Rear'])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_senado_mx(self):
        """
        Attempt to geocode ``Paseo de la Reforma 135, Tabacalera,
        Cuauhtémoc, Distrito Federal, 06030``.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq['senado_mx'])
        self.assertOneCandidate(candidates)
        search_text = 'Paseo de la Reforma 135'
        self.assertEqual(search_text in candidates[0].match_addr, True,
                         '"%s" not found in match_addr. Got "%s".'
                         % (search_text, candidates[0].match_addr))

    def test_geocode_structured_esri_wgs_senado_mx(self):
        """
        Attempt to geocode ``Paseo de la Reforma 135, Tabacalera,
        Cuauhtémoc, Distrito Federal, 06030`` using a structured query to
        EsriWGS.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq['senado_mx_struct'])
        self.assertOneCandidate(candidates)
        search_text = 'Paseo de la Reforma 135'
        self.assertEqual(search_text in candidates[0].match_addr, True,
                         '"%s" not found in match_addr. Got "%s".'
                         % (search_text, candidates[0].match_addr))

    def test_geocode_esri_wgs_340_12th_bounded(self):
        """
        Trying to geocode ``340 12th St, Philadelphia PA`` would normally return results
        for both ``340 N 12th St`` and ``340 S 12th St``. Using a bounding box around Callowhill,
        we should only get the former.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq['bounded_340_12th'])
        self.assertOneCandidate(candidates)
        self.assertEqual('340 N 12th' in candidates[0].match_addr, True,
                         '"340 N 12th" not found in match_addr. Got "%s"' % candidates[0].match_addr)

    def test_geocode_esri_wgs_zip_plus_4(self):
        """Check that geocoding 19127-1112 returns one result."""
        candidates = self.g_esri_wgs_postal_ok.get_candidates(self.pq['zip_plus_4_in_postal_plus_country'])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_multipart(self):
        """Check that geocoding multipart address returns one result."""
        candidates = self.g_esri_wgs.get_candidates(self.pq['willow_street_parts'])
        self.assertOneCandidate(candidates)

    def test_bounded_no_viewbox(self):
        """
        Should return a nice error saying that PlaceQuery can't be bounded without Viewbox.
        """
        pass

    @unittest.skipIf(ESRI_MAPS_API_KEY is None, ESRI_KEY_REQUIRED_MSG)
    def test_geocode_esri_na_us_soap(self):
        """Test ESRI North America SOAP geocoder"""
        location = '340 N 12th St., Philadelphia, PA, US'
        candidates = self.g_esri_na_soap.get_candidates(location)
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned for %s.' % location)

    @unittest.skipIf(ESRI_MAPS_API_KEY is None, ESRI_KEY_REQUIRED_MSG)
    def test_geocode_esri_na_us(self):
        """Test ESRI North America REST geocoder"""
        location = '340 N 12th St., Philadelphia, PA, US'
        candidates = self.g_esri_na.get_candidates(location)
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned for %s.' % location)

    @unittest.skipIf(ESRI_MAPS_API_KEY is None, ESRI_KEY_REQUIRED_MSG)
    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.')

    @unittest.skipIf(ESRI_MAPS_API_KEY is None, ESRI_KEY_REQUIRED_MSG)
    def test_geocode_esri_na_nz(self):
        """
        Test ESRI North America REST geocoder using a city in New Zealand.
        """
        candidates = self.g_esri_na.get_candidates(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, False,
                         'Found New Zealand address when this should only'
                         'be using the North American ESRI geocoder. '
                         'Candidates are %s.' % candidates)

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_bing(self):
        """Test Azavea's address using Bing geocoder"""
        candidates = self.g_bing.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(MAPQUEST_API_KEY is None, MAPQUEST_KEY_REQUIRED_MSG)
    def test_geocode_mapquest(self):
        """Test Azavea's address using MapQuest geocoder."""
        candidates = self.g_mapquest.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(MAPQUEST_API_KEY is None, MAPQUEST_KEY_REQUIRED_MSG)
    def test_geocode_mapquest_ssl(self):
        """Test Azavea's address using secure MapQuest geocoder."""
        candidates = self.g_mapquest_ssl.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(MAPZEN_API_KEY is None, MAPZEN_KEY_REQUIRED_MSG)
    def test_geocode_mapzen(self):
        """Test Azavea's address using Mapzen geocoder"""
        candidates = self.g_mapzen.get_candidates(self.pq['azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(MAPQUEST_API_KEY is None, MAPQUEST_KEY_REQUIRED_MSG)
    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 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_EsriWGS_address_components(self):
        """Make sure EsriWGS returns address components"""
        candidate = self.g_esri_wgs.get_candidates(self.pq['azavea'])[0]
        self._test_address_components(candidate)

    def test_census_address_components(self):
        """Make sure census geocoder returns address components"""
        candidate = self.g_census.get_candidates(self.pq['azavea'])[0]
        self._test_address_components(candidate)

    def test_geocode_dupepicker(self):
        """
        Check that '340 12th St returns results'
        """
        candidates = self.g.get_candidates(self.pq['ambiguous_azavea'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_karori(self):
        """
        Check that '102 Karori Road Karori Wellington' returns an address
        with the correct house number and postcode.
        """
        candidates = self.g_bing.get_candidates(self.pq['karori'])
        self.assertEqual(len(candidates) > 0, True, 'No candidates returned.')
        self.assertEqual(any([('102' in c.match_addr and '6012' in c.match_addr) for c in candidates]),
            True, 'Could not find bldg. no. "102" and postcode "6012" in any address.')

    def _test_address_components(self, candidate):
            for field in ['match_streetaddr', 'match_city', 'match_subregion', 'match_region',
                          'match_postal', 'match_country']:
                self.assertIsNotNone(getattr(candidate, field, None),
                                     msg='Missing address component %s' % field)

    def _test_geocode_results_all_(self, verbosity=0, geocoder=Geocoder(),
                                   expected_results=16):
        """
        Geocode a list of addresses. Some of these only work with Bing so
        fewer results are expected when Bing is not used as a geocoder.
        """
        if verbosity > 1:
            logger.setLevel(logging.INFO)

        queries_with_results = 0
        for place in self.pq:
            logger.info(place)
            logger.info(len(place) * '-')
            candidates = geocoder.get_candidates(self.pq[place])
            if len(candidates) == 0:
                logger.info('Input: %s\n(no results)' % self.pq[place].query)
            else:
                queries_with_results += 1
                logger.info('Input:  %s' % self.pq[place].query)
                logger.info(map(lambda c: 'Output: %r (%s %s)\n' %
                                (c.match_addr,
                                 c.geoservice,
                                 [c.locator, c.score, c.confidence, c.entity]),
                                candidates))
        self.assertEqual(expected_results, queries_with_results,
                         'Got results for %d of %d queries.' % (queries_with_results, len(self.pq)))

    def _test_geocode_results_all(self):
        if BING_MAPS_API_KEY is None:
            expected_results = 16
        else:
            self.g.add_source(['omgeo.services.Bing', {'settings': {'api_key': BING_MAPS_API_KEY}}])
            expected_results = len(self.pq)
        self._test_geocode_results_all_(geocoder=self.g, expected_results=expected_results)

    def test_esri_geocoder_na_default_override(self):
        """
        Test for default argument bug in 3.1 --
        EsriNA and EsriEU append processors rather than replace them
        """
        geocoder = Geocoder([['omgeo.services.EsriNA',
                            {'postprocessors': [AttrFilter([
                                'rooftop',
                                'interpolation',
                                'postal_specific'],
                                'locator')]}]])

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors),
                         'EsriNA geocoder incorrectly processed defaults')
        self.assertEqual('AttrFilter', geocoder._sources[0]._postprocessors[0].__class__.__name__,
                         'EsriNA geocoder incorrectly processed defaults')

    def test_esri_geocoder_eu_default_override(self):
        """
        Test for default argument bug in 3.1 --
        EsriNA and EsriEU append processors rather than replace them
        """
        geocoder = Geocoder([['omgeo.services.EsriEU',
                            {'postprocessors': [AttrFilter([
                                'rooftop',
                                'interpolation',
                                'postal_specific'],
                                'locator')]}]])

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors),
                         'EsriEU geocoder incorrectly processed defaults')
        self.assertEqual('AttrFilter',
                         geocoder._sources[0]._postprocessors[0].__class__.__name__,
                         'EsriEU geocoder incorrectly processed defaults')

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    def test_google_geocode_azavea(self):
        candidates = self.g_google.get_candidates(self.pq['azavea'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    def test_google_geocode_multipart(self):
        """Check that geocoding multipart address returns one result."""
        candidates = self.g_google.get_candidates(self.pq['willow_street_parts'])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(GOOGLE_API_KEY is None, GOOGLE_KEY_REQUIRED_MSG)
    def test_google_country_filter(self):
        candidates = self.g_google.get_candidates('York')
        self.assertOneCandidate(candidates)
        self.assertEqual(candidates[0].match_region, 'PA')
        candidates = self.g_google.get_candidates(PlaceQuery('York', country='UK'))
        self.assertOneCandidate(candidates)
        self.assertEqual(candidates[0].match_country, 'GB')
Ejemplo n.º 29
0
class AddressConverter(object):
    def __init__(self, curs):
        self.curs = curs
        self.geolocator = GoogleV3()
        self.nominatim = nominatim.Nominatim()

        self.geocoder = Geocoder()
        self.re_numbers = re.compile("^\d+$")

    def reject_all_numbers(self, address):
        if self.re_numbers.search(address):
            logger.info("Rejected by reject_all_numbers")
            return True
        return False

    def reject_short_words(self, address, length=4):
        if len(address) <= length:
            logger.info("Rejected by reject_short_words")
            return True
        return False

    def reject_large_main_places(self, address, threshold=15000):
        if address in main_places:
            population = main_places[address]["Population"]
            if int(population) >= threshold:
                return True
        return False

    def reject_resolution_to_main_place(self, address, threshold=15000):
        parts = address.split(",")
        first = parts[0].strip().lower()
        return self.reject_large_main_places(first, threshold)

    def reject_partial_match(self, result):
        if "partial_match" in result and result["partial_match"]:
            return True
        return False

    def resolve_address_google(self, address, **kwargs):
        encoded_address = encode(address)
        address = urllib.quote(encoded_address)

        url = "https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false&region=za&key=%s" % (
            address, GOOGLE_API_KEY)
        response = urllib2.urlopen(url)
        js = response.read()
        try:
            js = json.loads(js)
        except ValueError as e:
            logger.exception("Error trying to resolve %s" % address)
            raise StandardError("Couldn't resolve %s: %s" %
                                (address, e.message))

        results = []
        if "status" in js and js["status"] not in ("OK", "ZERO_RESULTS"):
            logger.error(
                "Error trying to resolve %s - %s (%s)" %
                (address, js.get("error_message", "Generic Error"), js))
            raise StandardError("Couldn't resolve %s: %s" %
                                (address, js.get("error_message")))

        if "results" in js and len(js["results"]) > 0:
            for result in js["results"]:

                res = self.reject_partial_match(result)
                if res: continue

                if "reject_resolution_to_main_place" in kwargs:
                    try:
                        res = self.reject_resolution_to_main_place(
                            result["formatted_address"],
                            int(kwargs["reject_resolution_to_main_place"][0]))
                    except (ValueError, TypeError):
                        res = self.resolution_to_main_place(
                            result["formatted_address"])
                    if res: continue

                geom = result["geometry"]["location"]
                results.append({
                    "lat": geom["lat"],
                    "lng": geom["lng"],
                    "formatted_address": result["formatted_address"],
                    "source": "Google Geocoding API",
                })

            if len(results) == 0: return None
            return results

    def resolve_address_esri(self, address):
        result = self.geocoder.geocode(address + ", South Africa")
        if not result: return None
        if not "candidates" in result: return None
        if len(result["candidates"]) == 0: return None
        candidate = result["candidates"][0]
        address = candidate.match_addr
        latitude = candidate.y
        longitude = candidate.x

        return address, latitude, longitude

    def resolve_address_nominatim(self, address, **kwargs):
        encoded_address = encode(address)
        results = self.nominatim.query(encoded_address)
        return [{
            "lat": r["lat"],
            "lng": r["lon"],
            "formatted_address": r["display_name"],
            "source": "Nominatim",
        } for r in results]

    def convert_address(self, address, **kwargs):
        address = address.strip()
        if address == "": return None

        if re_is_latlng.match(address):
            return self.resolve_coords(address)

        if "reject_numbers" in kwargs and self.reject_all_numbers(address):
            return None
        if "reject_short_words" in kwargs:
            try:
                val = self.reject_short_words(
                    address, int(kwargs["reject_short_words"][0]))
            except (TypeError, ValueError):
                val = self.reject_short_words(address)
            if val: return None

        if "reject_large_main_places" in kwargs:
            try:
                val = self.reject_large_main_places(
                    address, int(kwargs["reject_large_main_places"][0]))
            except (TypeError, ValueError):
                val = self.reject_large_main_places(address)
            if val: return None

        if not "south africa" in address.lower():
            address = address + ", South Africa"

        if "enable_nominatim" in kwargs:
            results = self.resolve_address_nominatim(address, **kwargs)

            if len(results) > 0:
                return results

        return self.resolve_address_google(address, **kwargs)

    def convert_to_geography(self, sql, latitude, longitude):
        poi = (longitude, latitude)

        self.curs.execute(sql, poi)

        return self.curs.fetchall()

    def resolve_coords(self, coords):
        try:
            lat, lng = [float(s) for s in coords.split(',', 1)]
            return [{
                "lat": lat,
                "lng": lng,
                "formatted_address": "%s, %s" % (lat, lng),
                "source": "Direct",
            }]
        except ValueError:
            return None
Ejemplo n.º 30
0
# -*- coding: utf-8 -*-
from django.conf import settings

from rest_framework.response import Response
from rest_framework import decorators
from rest_framework.permissions import AllowAny

from omgeo import Geocoder
from omgeo.places import PlaceQuery

geocoder = Geocoder(sources=settings.OMGEO_SETTINGS)


@decorators.api_view(['GET'])
@decorators.permission_classes((AllowAny, ))
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 _omgeo_candidate_to_dict(candidate):
    return {
Ejemplo n.º 31
0
class GeocoderTest(OmgeoTestCase):
    """Tests using various geocoding APIs. Requires internet connection."""

    g = None  # not set until set up
    BING_KEY_REQUIRED_MSG = "Enter a Bing Maps API key to run the Bing tests."
    MAPQUEST_KEY_REQUIRED_MSG = (
        "Enter a MapQuest API key to run the MapQuest tests. " "Keys can be obtained at http://developer.mapquest.com/."
    )

    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"),
            # 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}]])

        #: main geocoder used for tests, using default APIs
        self.g = Geocoder()

        # Set up params for old ESRI rest services:
        esri_settings = {} if ESRI_MAPS_API_KEY is None else {"api_key": ESRI_MAPS_API_KEY}
        old_esri_params = {"settings": esri_settings}

        # geocoders using individual services
        # self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
        self.g_esri_na = Geocoder([["omgeo.services.EsriNA", old_esri_params]])
        self.g_esri_eu = Geocoder([["omgeo.services.EsriEU", old_esri_params]])
        self.g_esri_na_soap = Geocoder([["omgeo.services.EsriNASoap", {}]])
        self.g_esri_eu_soap = Geocoder([["omgeo.services.EsriEUSoap", {}]])
        self.g_esri_wgs = Geocoder([["omgeo.services.EsriWGS", {}]])
        self.g_nom = Geocoder([["omgeo.services.Nominatim", {}]])

        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.01}}]])

    def tearDown(self):
        pass

    def test_geocode_azavea(self):
        candidates = self.g.get_candidates(self.pq["azavea"])
        self.assertOneCandidate(candidates)

    def test_impatiently_geocode_azavea(self):
        candidates = self.impatient_geocoder.get_candidates(self.pq["azavea"])
        self.assertEqual(len(candidates) == 0, True, "Candidates were unexpectedly returned in under 10ms.")

    def test_geocode_snap_points_1(self):
        """
        Geocoder expected to return the same place twice -- one with city as Flemington,
        and one with city as Readington Twp. This test checks that only one is picked.
        """
        candidates = self.g_esri_na.get_candidates(self.pq["8_kirkbride"])
        self.assertOneCandidate(candidates)

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_snap_points_2(self):
        """
        Bing geocoder expected to return the same place twice -- one with city as Alpha,
        and one with city as Phillipsburg. This test checks that only one is picked.
        """
        candidates = self.g_bing.get_candidates(self.pq["alpha_774_W_Central_Ave_Rear"])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_senado_mx(self):
        """
        Attempt to geocode ``Paseo de la Reforma 135, Tabacalera,
        Cuauhtémoc, Distrito Federal, 06030``.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq["senado_mx"])
        self.assertOneCandidate(candidates)
        search_text = "Paseo de la Reforma 135"
        self.assertEqual(
            search_text in candidates[0].match_addr,
            True,
            '"%s" not found in match_addr. Got "%s".' % (search_text, candidates[0].match_addr),
        )

    def test_geocode_esri_wgs_340_12th_bounded(self):
        """
        Trying to geocode ``340 12th St, Philadelphia PA`` would normally return results
        for both ``340 N 12th St`` and ``340 S 12th St``. Using a bounding box around Callowhill,
        we should only get the former.
        """
        candidates = self.g_esri_wgs.get_candidates(self.pq["bounded_340_12th"])
        self.assertOneCandidate(candidates)
        self.assertEqual(
            "340 N 12th" in candidates[0].match_addr,
            True,
            '"340 N 12th" not found in match_addr. Got "%s"' % candidates[0].match_addr,
        )

    def test_geocode_esri_wgs_zip_plus_4(self):
        """Check that geocoding 19127-1112 returns one result."""
        candidates = self.g_esri_wgs_postal_ok.get_candidates(self.pq["zip_plus_4_in_postal_plus_country"])
        self.assertOneCandidate(candidates)

    def test_geocode_esri_wgs_multipart(self):
        """Check that geocoding multipart address returns one result."""
        candidates = self.g_esri_wgs.get_candidates(self.pq["willow_street_parts"])
        self.assertOneCandidate(candidates)

    def test_bounded_no_viewbox(self):
        """
        Should return a nice error saying that PlaceQuery can't be bounded without Viewbox.
        """
        pass

    def test_geocode_esri_na_us_soap(self):
        """Test ESRI North America SOAP geocoder"""
        location = "340 N 12th St., Philadelphia, PA, US"
        candidates = self.g_esri_na_soap.get_candidates(location)
        self.assertEqual(len(candidates) > 0, True, "No candidates returned for %s." % location)

    def test_geocode_esri_na_us(self):
        """Test ESRI North America REST geocoder"""
        location = "340 N 12th St., Philadelphia, PA, US"
        candidates = self.g_esri_na.get_candidates(location)
        self.assertEqual(len(candidates) > 0, True, "No candidates returned for %s." % location)

    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.")

    def test_geocode_esri_na_nz(self):
        """
        Test ESRI North America REST geocoder using a city in New Zealand.
        """
        candidates = self.g_esri_na.get_candidates(self.pq["karori"])
        self.assertEqual(
            len(candidates) > 0,
            False,
            "Found New Zealand address when this should only"
            "be using the North American ESRI geocoder. "
            "Candidates are %s." % candidates,
        )

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_bing(self):
        """Test Azavea's address using Bing geocoder"""
        candidates = self.g_bing.get_candidates(self.pq["azavea"])
        self.assertEqual(len(candidates) > 0, True, "No candidates returned.")

    @unittest.skipIf(MAPQUEST_API_KEY is None, MAPQUEST_KEY_REQUIRED_MSG)
    def test_geocode_mapquest(self):
        """Test Azavea's address using MapQuest geocoder."""
        candidates = self.g_mapquest.get_candidates(self.pq["azavea"])
        self.assertEqual(len(candidates) > 0, True, "No candidates returned.")

    @unittest.skipIf(MAPQUEST_API_KEY is None, MAPQUEST_KEY_REQUIRED_MSG)
    def test_geocode_mapquest_ssl(self):
        """Test Azavea's address using secure MapQuest geocoder."""
        candidates = self.g_mapquest_ssl.get_candidates(self.pq["azavea"])
        self.assertEqual(len(candidates) > 0, True, "No candidates returned.")

    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 test_geocode_dc_address(self):
    #     """
    #     Check that '1600 Pennsylvania' returns first result using DC address locator.
    #     """
    #     candidates = self.g_dc.get_candidates(PlaceQuery('1600 pennsylvania'))
    #     self.assertTrue(len(candidates) > 0, 'No candidates returned.')
    #     self.assertTrue(candidates[0].locator == 'DC Address',
    #                     'Expected 1600 pennsylvania to be an address match')

    # def test_geocode_dc_intersection(self):
    #     """
    #     Check that 'H and 15th' returns first result using DC intersection locator.
    #     """
    #     candidates = self.g_dc.get_candidates(PlaceQuery('h and 15th'))
    #     self.assertTrue(len(candidates) > 0, 'No candidates returned.')
    #     self.assertTrue(candidates[0].locator == 'DC Intersection',
    #                     'h and 15th to be an intersection match')

    def test_geocode_dupepicker(self):
        """
        Check that '340 12th St returns results'
        """
        candidates = self.g.get_candidates(self.pq["ambiguous_azavea"])
        self.assertEqual(len(candidates) > 0, True, "No candidates returned.")

    @unittest.skipIf(BING_MAPS_API_KEY is None, BING_KEY_REQUIRED_MSG)
    def test_geocode_karori(self):
        """
        Check that '102 Karori Road Karori Wellington' returns an address
        with the correct house number and postcode.
        """
        candidates = self.g_bing.get_candidates(self.pq["karori"])
        self.assertEqual(len(candidates) > 0, True, "No candidates returned.")
        self.assertEqual(
            any([("102" in c.match_addr and "6012" in c.match_addr) for c in candidates]),
            True,
            'Could not find bldg. no. "102" and postcode "6012" in any address.',
        )

    def _test_geocode_results_all_(self, verbosity=0, geocoder=Geocoder(), expected_results=16):
        """
        Geocode a list of addresses. Some of these only work with Bing so 
        fewer results are expected when Bing is not used as a geocoder.
        """
        if verbosity > 1:
            logger.setLevel(logging.INFO)

        queries_with_results = 0
        for place in self.pq:
            logger.info(place)
            logger.info(len(place) * "-")
            candidates = geocoder.get_candidates(self.pq[place])
            if len(candidates) == 0:
                logger.info("Input: %s\n(no results)" % self.pq[place].query)
            else:
                queries_with_results += 1
                logger.info("Input:  %s" % self.pq[place].query)
                logger.info(
                    map(
                        lambda c: "Output: %r (%s %s)\n"
                        % (c.match_addr, c.geoservice, [c.locator, c.score, c.confidence, c.entity]),
                        candidates,
                    )
                )
        self.assertEqual(
            expected_results,
            queries_with_results,
            "Got results for %d of %d queries." % (queries_with_results, len(self.pq)),
        )

    def _test_geocode_results_all(self):
        if BING_MAPS_API_KEY is None:
            expected_results = 16
        else:
            self.g.add_source(["omgeo.services.Bing", {"settings": {"api_key": BING_MAPS_API_KEY}}])
            expected_results = len(self.pq)
        self._test_geocode_results_all_(geocoder=self.g, expected_results=len(self.pq))

    def test_esri_geocoder_na_default_override(self):
        """
        Test for default argument bug in 3.1 --
        EsriNA and EsriEU append processors rather than replace them
        """
        geocoder = Geocoder(
            [
                [
                    "omgeo.services.EsriNA",
                    {"postprocessors": [AttrFilter(["rooftop", "interpolation", "postal_specific"], "locator")]},
                ]
            ]
        )

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors), "EsriNA geocoder incorrectly processed defaults")
        self.assertEqual(
            "AttrFilter",
            geocoder._sources[0]._postprocessors[0].__class__.__name__,
            "EsriNA geocoder incorrectly processed defaults",
        )

    def test_esri_geocoder_eu_default_override(self):
        """
        Test for default argument bug in 3.1 --
        EsriNA and EsriEU append processors rather than replace them
        """
        geocoder = Geocoder(
            [
                [
                    "omgeo.services.EsriEU",
                    {"postprocessors": [AttrFilter(["rooftop", "interpolation", "postal_specific"], "locator")]},
                ]
            ]
        )

        self.assertEqual(1, len(geocoder._sources[0]._postprocessors), "EsriEU geocoder incorrectly processed defaults")
        self.assertEqual(
            "AttrFilter",
            geocoder._sources[0]._postprocessors[0].__class__.__name__,
            "EsriEU geocoder incorrectly processed defaults",
        )
Ejemplo n.º 32
0
    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"),
            # 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}]])

        #: main geocoder used for tests, using default APIs
        self.g = Geocoder()

        # Set up params for old ESRI rest services:
        esri_settings = {} if ESRI_MAPS_API_KEY is None else {"api_key": ESRI_MAPS_API_KEY}
        old_esri_params = {"settings": esri_settings}

        # geocoders using individual services
        # self.g_dc = Geocoder([['omgeo.services.CitizenAtlas', {}]])
        self.g_esri_na = Geocoder([["omgeo.services.EsriNA", old_esri_params]])
        self.g_esri_eu = Geocoder([["omgeo.services.EsriEU", old_esri_params]])
        self.g_esri_na_soap = Geocoder([["omgeo.services.EsriNASoap", {}]])
        self.g_esri_eu_soap = Geocoder([["omgeo.services.EsriEUSoap", {}]])
        self.g_esri_wgs = Geocoder([["omgeo.services.EsriWGS", {}]])
        self.g_nom = Geocoder([["omgeo.services.Nominatim", {}]])

        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.01}}]])
Ejemplo n.º 33
0
def getBranches(provinceId,
                localidadId,
                localidadName,
                provinceName,
                extracash=False):
    try:
        fixpath = root + paths['fix'] + '/rapipago_fix.csv'
        toFix = []
        g = Geocoder()
        extracash = 'true' if extracash else 'false'
        res = requests.get(
            'https://www.rapipago.com.ar/rapipagoWeb/index.php/resultado_sucursales?prov='
            + provinceId + '&loc=' + localidadId + '&extracash=' + extracash)
        if res.status_code != 200:
            raise ValueError('Error solicitando sucursales.')
        soup = BeautifulSoup(res.text, 'lxml')
        content = soup.find_all('div', class_="w-row accordion_content")
        branches = []
        #chequeo si el sitio posee sucursales
        if content != None:
            for c in content:
                try:
                    global toPendingFixCount
                    withoutError = True
                    title = c.select('.text_expand_drop')[0].get_text()
                    address = c.select('.text_expand_drop')[1].get_text()
                    attentionHour = c.select(
                        '.text_horarios_drop')[0].get_text().replace(
                            'Horarios de atención:',
                            '').replace('\n', '').replace('   ', '')
                    data = [localidadName, title, address, attentionHour]
                    latlngExt = c.find_all('a')
                    #chequeo si encontro etiquetas de latitud y longitud
                    if len(latlngExt) > 0:
                        latlngExt = str(latlngExt[0])
                        lat = findBetweenR(latlngExt, 'data-lat="',
                                           '" data-lng')
                        lng = findBetweenR(latlngExt, 'data-lng="',
                                           '" data-marker')
                        data.append(lat)
                        data.append(lng)
                    #al no encontrar o no poseer con exactitud, controla si ya fueron definidas manualmente
                    if len(latlngExt) == 0 or (lat == '0.00000000'
                                               or lng == '0.00000000'):
                        fixNotFound = True
                        with open(fixpath, 'r') as f:
                            reader = csv.reader(f)
                            fixList = list(reader)
                        search = [provinceName, localidadName, title, address]
                        for i, lc in enumerate(fixList):
                            concurrence = 0
                            for co in search:
                                if co in lc:
                                    concurrence = concurrence + 1
                            if concurrence == len(search):
                                data = lc[1:len(lc)]
                                fixNotFound = False
                        #no esta la sucursal definida manualmente e intenta geolocalizarla
                        if fixNotFound:
                            try:
                                result = g.geocode(address + ', ' +
                                                   localidadName +
                                                   ', Argentina')
                                lat = result['candidates'][0].x
                                lng = result['candidates'][0].y
                            except Exception as e:
                                #no logro geolocalizarla y sera puesta a la lista manual
                                withoutError = False
                                try:
                                    mode = 'a' if os.path.exists(
                                        fixpath) else 'w'
                                    listString = ','.join(data)
                                    if len(latlngExt) == 0:
                                        listString = listString + ',0.00000000,0.00000000'
                                    with open(fixpath, mode) as _file:
                                        _file.write('\n' + provinceName + ',' +
                                                    (listString))
                                    toPendingFixCount = toPendingFixCount + 1
                                except Exception as e:
                                    print(e)
                    if withoutError:
                        branches.append(data)
                except Exception as e:
                    print(e)
            return branches
        return []
    except Exception as e:
        print(e)