Esempio n. 1
0
    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
Esempio n. 2
0
    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]
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
0
    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