def geocode(self, query, *, exactly_one=True, timeout=DEFAULT_SENTINEL): """ Return a location point for a `3 words` query. If the `3 words` address doesn't exist, a :class:`geopy.exc.GeocoderQueryError` exception will be thrown. :param str query: The 3-word address you wish to geocode. :param bool exactly_one: Return one result or a list of results, if available. Due to the address scheme there is always exactly one result for each `3 words` address, so this parameter is rather useless for this geocoder. :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. :rtype: :class:`geopy.location.Location` or a list of them, if ``exactly_one=False``. """ if not _check_query(query): raise exc.GeocoderQueryError( "Search string must be 'word.word.word'") params = { 'words': query, 'key': self.api_key, } url = "?".join((self.geocode_api, urlencode(params))) logger.debug("%s.geocode: %s", self.__class__.__name__, url) callback = partial(self._parse_json, exactly_one=exactly_one) return self._call_geocoder(url, callback, timeout=timeout)
def geocode(self, query, lang='en', exactly_one=True, timeout=None): """ Geocode a "3 words" or "OneWord" query. :param string query: The 3-word or OneWord-address you wish to geocode. :param string lang: two character language codes as supported by the API (http://what3words.com/api/reference/languages). :param bool exactly_one: Parameter has no effect for this geocoder. Due to the address scheme there is always exactly one result. :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. .. versionadded:: 0.97 """ if not self._check_query(query): raise exc.GeocoderQueryError("Search string must be either like " "'word.word.word' or '*word' ") params = { 'string': self.format_string % query, 'lang': self.format_string % lang.lower(), 'key': self.api_key, } url = "?".join(((self.api + "w3w"), urlencode(params))) logger.debug("%s.geocode: %s", self.__class__.__name__, url) return self._parse_json(self._call_geocoder(url, timeout=timeout), exactly_one)
def _parse_reverse_json(self, resources, exactly_one=True): """ Parses a location from a single-result reverse API call. """ if resources.get('error') == "21": raise exc.GeocoderQueryError("Invalid coordinates") def parse_resource(resource): """ Parse resource to return Geopy Location object """ words = resource['words'] words = join_filter(".", [words[0], words[1], words[2]]) position = resource['position'] latitude, longitude = position[0], position[1] if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return Location(words, (latitude, longitude), resource) location = parse_resource(resources) if exactly_one: return location else: return [location]
def _parse_json(self, resources, exactly_one=True): """ Parse type, words, latitude, and longitude and language from a JSON response. """ if resources.get('error') == "X1": raise exc.GeocoderAuthenticationFailure() if resources.get('error') == "11": raise exc.GeocoderQueryError( "Address (Word(s)) not recognised by What3Words.") def parse_resource(resource): """ Parse record. """ if resource['type'] == '3 words': words = resource['words'] words = join_filter(".", [words[0], words[1], words[2]]) position = resource['position'] latitude, longitude = position[0], position[1] if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return Location(words, (latitude, longitude), resource) elif resource['type'] == 'OneWord': # TODO this branch probably needs to be removed, as OneWord # addresses have been canceled. words = resource['words'] words = join_filter(".", [words[0], words[1], words[2]]) oneword = resource['oneword'] info = resource['info'] address = join_filter(", ", [ oneword, words, info['name'], info['address1'], info['address2'], info['address3'], info['city'], info['county'], info['postcode'], info['country_id'] ]) position = resource['position'] latitude, longitude = position[0], position[1] if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return Location(address, (latitude, longitude), resource) else: raise exc.GeocoderParseError('Error parsing result.') location = parse_resource(resources) if exactly_one: return location else: return [location]
def geocode(self, query, lang='en', exactly_one=True, timeout=DEFAULT_SENTINEL): """ Return a location point for a `3 words` query. If the `3 words` address doesn't exist, a :class:`geopy.exc.GeocoderQueryError` exception will be thrown. :param str query: The 3-word address you wish to geocode. :param str lang: two character language codes as supported by the API (https://docs.what3words.com/api/v2/#lang). :param bool exactly_one: Return one result or a list of results, if available. Due to the address scheme there is always exactly one result for each `3 words` address, so this parameter is rather useless for this geocoder. .. versionchanged:: 1.14.0 ``exactly_one=False`` now returns a list of a single location. This option wasn't respected before. :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. :rtype: :class:`geopy.location.Location` or a list of them, if ``exactly_one=False``. """ if not self._check_query(query): raise exc.GeocoderQueryError( "Search string must be 'word.word.word'" ) params = { 'addr': self.format_string % query, 'lang': lang.lower(), 'key': self.api_key, } url = "?".join(((self.api + "forward"), urlencode(params))) logger.debug("%s.geocode: %s", self.__class__.__name__, url) return self._parse_json( self._call_geocoder(url, timeout=timeout), exactly_one=exactly_one )
def _parse_json(self, resources, exactly_one=True): """ Parse type, words, latitude, and longitude and language from a JSON response. """ error = resources.get('error') if error is not None: # https://developer.what3words.com/public-api/docs#error-handling exc_msg = "Error returned by What3Words: %s" % resources["error"][ "message"] exc_code = error.get('code') if exc_code in ['MissingKey', 'InvalidKey']: raise exc.GeocoderAuthenticationFailure(exc_msg) raise exc.GeocoderQueryError(exc_msg) def parse_resource(resource): """ Parse record. """ if 'coordinates' in resource: words = resource['words'] position = resource['coordinates'] latitude, longitude = position['lat'], position['lng'] if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return Location(words, (latitude, longitude), resource) else: raise exc.GeocoderParseError('Error parsing result.') location = parse_resource(resources) if exactly_one: return location else: return [location]
def _parse_json(self, resources, exactly_one=True): """ Parse type, words, latitude, and longitude and language from a JSON response. """ code = resources['status'].get('code') if code: # https://docs.what3words.com/api/v2/#errors exc_msg = "Error returned by What3Words: %s" % resources['status'][ 'message'] if code == 401: raise exc.GeocoderAuthenticationFailure(exc_msg) raise exc.GeocoderQueryError(exc_msg) def parse_resource(resource): """ Parse record. """ if 'geometry' in resource: words = resource['words'] position = resource['geometry'] latitude, longitude = position['lat'], position['lng'] if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return Location(words, (latitude, longitude), resource) else: raise exc.GeocoderParseError('Error parsing result.') location = parse_resource(resources) if exactly_one: return location else: return [location]
def _parse_reverse_json(resources): """ Parses a location from a single-result reverse API call. """ if resources.get('error') == "21": raise exc.GeocoderQueryError("Invalid coordinates") def parse_resource(resource): words = resource['words'] words = join_filter(".", [words[0], words[1], words[2]]) position = resource['position'] latitude, longitude = position[0], position[1] if latitude and longitude: latitude = float(latitude) longitude = float(longitude) return Location(words, (latitude, longitude), resource) return parse_resource(resources)