def _parse_reverse_result(self, result): latitude, longitude = result['position'].split(',') return Location(result['address']['freeformAddress'], (latitude, longitude), result)
def geocode(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL, out_fields=None): """ Return a location point by address. :param str query: The address or query you wish to geocode. :param bool exactly_one: Return one result or a list of results, if available. :param int timeout: Time, in seconds, to wait for the geocoding service to respond before raising a :class:`geopy.exc.GeocoderTimedOut` exception. Set this only if you wish to override, on this call only, the value set during the geocoder's initialization. :param out_fields: A list of output fields to be returned in the attributes field of the raw data. This can be either a python list/tuple of fields or a comma-separated string. See https://developers.arcgis.com/rest/geocode/api-reference/geocoding-service-output.htm for a list of supported output fields. If you want to return all supported output fields, set ``out_fields="*"``. .. versionadded:: 1.14.0 :type out_fields: str or iterable :rtype: ``None``, :class:`geopy.location.Location` or a list of them, if ``exactly_one=False``. """ params = {'singleLine': self.format_string % query, 'f': 'json'} if exactly_one: params['maxLocations'] = 1 if out_fields is not None: if isinstance(out_fields, string_compare): params['outFields'] = out_fields else: params['outFields'] = ",".join(out_fields) url = "?".join((self.api, urlencode(params))) logger.debug("%s.geocode: %s", self.__class__.__name__, url) response = self._call_geocoder(url, timeout=timeout) # Handle any errors; recursing in the case of an expired token. if 'error' in response: if response['error']['code'] == self._TOKEN_EXPIRED: self.retry += 1 self._refresh_authentication_token() return self.geocode( query, exactly_one=exactly_one, timeout=timeout ) raise GeocoderServiceError(str(response['error'])) # Success; convert from the ArcGIS JSON format. if not len(response['candidates']): return None geocoded = [] for resource in response['candidates']: geometry = resource['location'] geocoded.append( Location( resource['address'], (geometry['y'], geometry['x']), resource ) ) if exactly_one: return geocoded[0] return geocoded
def test_location_ne(self): loc1 = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_POINT, {}) loc2 = Location(GRAND_CENTRAL_STR, Point(0, 0), {}) self.assertNotEqual(loc1, loc2)
def _parse_search_result(self, result): latitude = result['position']['lat'] longitude = result['position']['lon'] return Location(result['address']['freeformAddress'], (latitude, longitude), result)
def test_location_len(self): loc = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_POINT, {}) self.assertEqual(len(loc), 2)
def test_location_eq(self): loc1 = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_POINT, {}) loc2 = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_COORDS_TUPLE, {}) self.assertEqual(loc1, loc2)
def test_location_raw(self): loc = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_POINT, raw=GRAND_CENTRAL_RAW) self._location_properties_test(loc, GRAND_CENTRAL_RAW)
def locations(draw): resp = draw(googleResponses()) asPoint = Point(resp['geometry']['location']['lat'], resp['geometry']['location']['lng']) return Location(resp['formatted_address'], asPoint, resp)
def test_location_array_access(self): loc = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_COORDS_TUPLE, {}) self.assertEqual(loc[0], GRAND_CENTRAL_STR) self.assertEqual(loc[1][0], GRAND_CENTRAL_COORDS_TUPLE[0]) self.assertEqual(loc[1][1], GRAND_CENTRAL_COORDS_TUPLE[1])
def test_location_properties(self): loc = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_POINT, {}) self._location_properties_test(loc)
def test_location_point_typeerror(self): with self.assertRaises(TypeError): Location(GRAND_CENTRAL_STR, 1, {})
def test_location_iter(self): loc = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_COORDS_TUPLE, {}) self._location_iter_test(loc) self.assertEqual(loc.point, GRAND_CENTRAL_POINT)
def test_location_none(self): with self.assertRaises(TypeError): Location(GRAND_CENTRAL_STR, None, {})
def reverse(self, query, exactly_one=True, timeout=DEFAULT_SENTINEL, distance=None, wkid=DEFAULT_WKID): """ Return an address by location point. :param query: The coordinates for which you wish to obtain the closest human-readable addresses. :type query: :class:`geopy.point.Point`, list or tuple of ``(latitude, longitude)``, or string as ``"%(latitude)s, %(longitude)s"``. :param bool exactly_one: Return one result or a list of results, if available. :param int timeout: Time, in seconds, to wait for the geocoding service to respond before raising a :class:`geopy.exc.GeocoderTimedOut` exception. Set this only if you wish to override, on this call only, the value set during the geocoder's initialization. :param int distance: Distance from the query location, in meters, within which to search. ArcGIS has a default of 100 meters, if not specified. :param str wkid: WKID to use for both input and output coordinates. .. deprecated:: 1.14.0 It wasn't working before because it was specified incorrectly in the request parameters, and won't work even if we fix the request, because :class:`geopy.point.Point` normalizes the coordinates according to WKID 4326. Please open an issue in the geopy issue tracker if you believe that custom wkid values should be supported. This parameter is scheduled for removal in geopy 2.0. :rtype: ``None``, :class:`geopy.location.Location` or a list of them, if ``exactly_one=False``. """ location = self._coerce_point_to_string(query, "%(lon)s,%(lat)s") if wkid != DEFAULT_WKID: warnings.warn("%s.reverse: custom wkid value has been ignored. " "It wasn't working before because it was specified " "incorrectly in the request parameters, and won't " "work even if we fix the request, because geopy.Point " "normalizes the coordinates according to WKID %s. " "Please open an issue in the geopy issue tracker " "if you believe that custom wkid values should be " "supported." % (type(self).__name__, DEFAULT_WKID), DeprecationWarning) wkid = DEFAULT_WKID params = {'location': location, 'f': 'json', 'outSR': wkid} if distance is not None: params['distance'] = distance url = "?".join((self.reverse_api, urlencode(params))) logger.debug("%s.reverse: %s", self.__class__.__name__, url) response = self._call_geocoder(url, timeout=timeout) if not len(response): return None if 'error' in response: if response['error']['code'] == self._TOKEN_EXPIRED: self.retry += 1 self._refresh_authentication_token() return self.reverse(query, exactly_one=exactly_one, timeout=timeout, distance=distance, wkid=wkid) # https://developers.arcgis.com/rest/geocode/api-reference/geocoding-service-output.htm if response['error']['code'] == 400: # 'details': ['Unable to find address for the specified location.']} try: if 'Unable to find' in response['error']['details'][0]: return None except (KeyError, IndexError): pass raise GeocoderServiceError(str(response['error'])) address = ( "%(Address)s, %(City)s, %(Region)s %(Postal)s," " %(CountryCode)s" % response['address'] ) location = Location( address, (response['location']['y'], response['location']['x']), response['address'] ) if exactly_one: return location else: return [location]
def test_location_string(self): loc = Location(GRAND_CENTRAL_STR, GRAND_CENTRAL_POINT, {}) self.assertEqual(str(loc), loc.address)
def parse_place(place): '''Get the location, lat, lng from a single json place.''' location = place.get('formatted_address') latitude = place['geometry']['location']['lat'] longitude = place['geometry']['location']['lng'] return Location(location, (latitude, longitude), place)
def _parse_code(self, feature): # Parse each resource. latitude = feature.get('geometry', {}).get('coordinates', [])[1] longitude = feature.get('geometry', {}).get('coordinates', [])[0] placename = feature.get('properties', {}).get('name') return Location(placename, (latitude, longitude), feature)