def _parse_response(self, content): """ Returns the parsed result of a PlaceFinder API call. """ try: placefinder = ( content["bossresponse"]["placefinder"] ) if not len(placefinder) or not len(placefinder.get("results", [])): return None results = [ Location( self.humanize(place), (float(place["latitude"]), float(place["longitude"])), raw=place ) for place in placefinder["results"] ] except (KeyError, ValueError): raise GeocoderParseError("Error parsing PlaceFinder result") return results
def _parse_json(self, doc, exactly_one): """ Parse JSON response body. """ if doc.get('error'): raise GeocoderServiceError(doc['error']['message']) try: places = doc['response']['GeoObjectCollection']['featureMember'] except KeyError: raise GeocoderParseError('Failed to parse server response') def parse_code(place): """ Parse each record. """ try: place = place['GeoObject'] except KeyError: raise GeocoderParseError('Failed to parse server response') longitude, latitude = [ float(_) for _ in place['Point']['pos'].split(' ') ] name_elements = ['name', 'description'] location = ', '.join( [place[k] for k in name_elements if place.get(k)]) return Location(location, (latitude, longitude), place) if exactly_one: try: return parse_code(places[0]) except IndexError: return None else: return [parse_code(place) for place in places]
def _call_geocoder(self, url, timeout=DEFAULT_SENTINEL, raw=False, requester=None, deserializer=json.loads, **kwargs): """ For a generated query URL, get the results. """ if requester: req = url # Don't construct an urllib's Request for a custom requester. # `requester` might be anything which can issue an HTTP request. # Assume that `requester` is a method of the `requests` library. # Requests, however, doesn't accept SSL context in its HTTP # request methods. A custom HTTP adapter has to be created for that. # So the current usage is not directly compatible with `requests`. requester = functools.partial(requester, context=self.ssl_context, proxies=self.proxies, headers=self.headers) else: if isinstance(url, Request): # copy Request headers = self.headers.copy() headers.update(url.header_items()) req = Request(url=url.get_full_url(), headers=headers) else: req = Request(url=url, headers=self.headers) requester = requester or self.urlopen if timeout is None: warnings.warn( ('`timeout=None` has been passed to a geocoder call. Using ' 'default geocoder timeout. In geopy 2.0 the ' 'behavior will be different: None will mean "no timeout" ' 'instead of "default geocoder timeout". Pass ' 'geopy.geocoders.base.DEFAULT_SENTINEL instead of None ' 'to get rid of this warning.'), DeprecationWarning) timeout = DEFAULT_SENTINEL timeout = (timeout if timeout is not DEFAULT_SENTINEL else self.timeout) try: page = requester(req, timeout=timeout, **kwargs) except Exception as error: message = (str(error) if not py3k else (str(error.args[0]) if len(error.args) else str(error))) self._geocoder_exception_handler(error, message) if isinstance(error, HTTPError): code = error.getcode() try: raise ERROR_CODE_MAP[code](message) except KeyError: raise GeocoderServiceError(message) elif isinstance(error, URLError): if "timed out" in message: raise GeocoderTimedOut('Service timed out') elif "unreachable" in message: raise GeocoderUnavailable('Service not available') elif isinstance(error, SocketTimeout): raise GeocoderTimedOut('Service timed out') elif isinstance(error, SSLError): if "timed out" in message: raise GeocoderTimedOut('Service timed out') raise GeocoderServiceError(message) if hasattr(page, 'getcode'): status_code = page.getcode() elif hasattr(page, 'status_code'): status_code = page.status_code else: status_code = None if status_code in ERROR_CODE_MAP: raise ERROR_CODE_MAP[page.status_code]("\n%s" % decode_page(page)) if raw: return page page = decode_page(page) if deserializer is not None: try: return deserializer(page) except ValueError: raise GeocoderParseError( "Could not deserialize using deserializer:\n%s" % page) else: return page
def timezone(self, location, at_time=None, timeout=DEFAULT_SENTINEL): """ **This is an unstable API.** Finds the timezone a `location` was in for a specified `at_time`, and returns a pytz timezone object. .. versionadded:: 1.2.0 :param location: The coordinates for which you want a timezone. :type location: :class:`geopy.point.Point`, list or tuple of (latitude, longitude), or string as "%(latitude)s, %(longitude)s" :param at_time: The time at which you want the timezone of this location. This is optional, and defaults to the time that the function is called in UTC. :type at_time: int or float or datetime :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: pytz timezone. See :func:`pytz.timezone`. """ if not pytz_available: raise ImportError( 'pytz must be installed in order to locate timezones. ' ' Install with `pip install geopy -e ".[timezone]"`.') location = self._coerce_point_to_string(location) if isinstance(at_time, Number): timestamp = at_time elif isinstance(at_time, datetime): timestamp = timegm(at_time.utctimetuple()) elif at_time is None: timestamp = timegm(datetime.utcnow().utctimetuple()) else: raise GeocoderQueryError("`at_time` must be an epoch integer or " "datetime.datetime object") params = { "location": location, "timestamp": timestamp, } if self.api_key: params['key'] = self.api_key url = "?".join((self.tz_api, urlencode(params))) logger.debug("%s.timezone: %s", self.__class__.__name__, url) response = self._call_geocoder(url, timeout=timeout) try: tz = timezone(response["timeZoneId"]) except UnknownTimeZoneError: raise GeocoderParseError( "pytz could not parse the timezone identifier (%s) " "returned by the service." % response["timeZoneId"]) except KeyError: raise GeocoderParseError( "geopy could not find a timezone in this response: %s" % response) return tz
def _call_geocoder(self, url, timeout=None, raw=False, requester=None, deserializer=json.loads, **kwargs): """ For a generated query URL, get the results. """ requester = requester or self.urlopen req = Request(url=url, headers=self.headers) try: page = requester(req, timeout=(timeout or self.timeout), **kwargs) except Exception as error: # pylint: disable=W0703 message = (str(error) if not py3k else (str(error.args[0]) if len(error.args) else str(error))) if hasattr(self, '_geocoder_exception_handler'): self._geocoder_exception_handler(error, message) # pylint: disable=E1101 if isinstance(error, HTTPError): code = error.getcode() try: raise ERROR_CODE_MAP[code](message) except KeyError: raise GeocoderServiceError(message) elif isinstance(error, URLError): if "timed out" in message: raise GeocoderTimedOut('Service timed out') elif "unreachable" in message: raise GeocoderUnavailable('Service not available') elif isinstance(error, SocketTimeout): raise GeocoderTimedOut('Service timed out') elif isinstance(error, SSLError): if "timed out" in message: raise GeocoderTimedOut('Service timed out') raise GeocoderServiceError(message) if hasattr(page, 'getcode'): status_code = page.getcode() elif hasattr(page, 'status_code'): status_code = page.status_code else: status_code = None if status_code in ERROR_CODE_MAP: raise ERROR_CODE_MAP[page.status_code]("\n%s" % decode_page(page)) if raw: return page page = decode_page(page) if deserializer is not None: try: return deserializer(page) except ValueError: raise GeocoderParseError( "Could not deserialize using deserializer:\n%s" % page) else: return page