Ejemplo n.º 1
0
 def _call_geocoder(self, url, timeout=None, raw=False):
     """
     For a generated query URL, get the results.
     """
     try:
         page = self.urlopen(url, timeout=timeout or self.timeout)
     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 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 raw:
         return page
     return json.loads(decode_page(page))
Ejemplo n.º 2
0
    def _request(self, url, *, timeout, headers):
        try:
            resp = self.session.get(url, timeout=timeout, headers=headers)
        except Exception as error:
            message = str(error)
            if isinstance(error, SocketTimeout):
                raise GeocoderTimedOut("Service timed out")
            elif isinstance(error, SSLError):
                if "timed out" in message:
                    raise GeocoderTimedOut("Service timed out")
            elif isinstance(error, requests.ConnectionError):
                if "unauthorized" in message.lower():
                    raise GeocoderServiceError(message)
                else:
                    raise GeocoderUnavailable(message)
            elif isinstance(error, requests.Timeout):
                raise GeocoderTimedOut("Service timed out")
            raise GeocoderServiceError(message)
        else:
            if resp.status_code >= 400:
                raise AdapterHTTPError(
                    "Non-successful status code %s" % resp.status_code,
                    status_code=resp.status_code,
                    text=resp.text,
                )

        return resp
Ejemplo n.º 3
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

        try:
            page = requester(url, 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
Ejemplo n.º 4
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(' ')
            ]

            location = place.get('description')

            return Location(location, (latitude, longitude), place)

        if exactly_one:
            return parse_code(places[0])
        else:
            return [parse_code(place) for place in places]
Ejemplo n.º 5
0
 def _call_geocoder(self, url, timeout=None, raw=False):
     """
     For a generated query URL, get the results.
     """
     try:
         page = self.urlopen(url, timeout=timeout or self.timeout)
     except Exception as error:  # pylint: disable=W0703
         if hasattr(self, '_geocoder_exception_handler'):
             self._geocoder_exception_handler(error)  # pylint: disable=E1101
         if isinstance(error, HTTPError):
             if error.msg.lower().contains("unauthorized"):
                 raise GeocoderAuthenticationFailure("Unauthorized")
             raise GeocoderServiceError(error.getcode(), error.msg)
         elif isinstance(error, URLError):
             if "timed out" in error.reason:
                 raise GeocoderTimedOut('Service timed out')
             raise
         elif isinstance(error, SocketTimeout):
             raise GeocoderTimedOut('Service timed out')
         elif isinstance(error, SSLError):
             if error.message == 'The read operation timed out':
                 raise GeocoderTimedOut('Service timed out')
             raise
         else:
             raise
     if raw:
         return page
     return json.loads(decode_page(page))
Ejemplo n.º 6
0
    def get_text(self, url, *, timeout, headers):
        req = Request(url=url, headers=headers)
        try:
            page = self.urlopen(req, timeout=timeout)
        except Exception as error:
            message = str(error.args[0]) if len(error.args) else str(error)
            if isinstance(error, HTTPError):
                code = error.getcode()
                body = self._read_http_error_body(error)
                raise AdapterHTTPError(message, status_code=code, text=body)
            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)
        else:
            text = self._decode_page(page)
            status_code = page.getcode()
            if status_code >= 400:
                raise AdapterHTTPError(
                    "Non-successful status code %s" % status_code,
                    status_code=status_code, text=text
                )

        return text
Ejemplo n.º 7
0
 def _check_status(status):
     """
     Validates error statuses.
     """
     if status == 0:
         # When there are no results, just return.
         return
     if status == 1:
         raise GeocoderServiceError('Internal server error.')
     elif status == 2:
         raise GeocoderQueryError('Invalid request.')
     elif status == 3:
         raise GeocoderAuthenticationFailure('Authentication failure.')
     elif status == 4:
         raise GeocoderQuotaExceeded('Quota validate failure.')
     elif status == 5:
         raise GeocoderQueryError('AK Illegal or Not Exist.')
     elif status == 101:
         raise GeocoderAuthenticationFailure('No AK')
     elif status == 102:
         raise GeocoderAuthenticationFailure('MCODE Error')
     elif status == 200:
         raise GeocoderAuthenticationFailure('Invalid AK')
     elif status == 211:
         raise GeocoderAuthenticationFailure('Invalid SN')
     elif 200 <= status < 300:
         raise GeocoderAuthenticationFailure('Authentication Failure')
     elif 300 <= status < 500:
         raise GeocoderQuotaExceeded('Quota Error.')
     else:
         raise GeocoderQueryError('Unknown error. Status: %r' % status)
Ejemplo n.º 8
0
    def _parse_reverse(self, response, exactly_one):
        if not len(response):
            return None
        if 'error' in response:
            # 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']))

        if response['address'].get('Address'):
            address = ("%(Address)s, %(City)s, %(Region)s %(Postal)s,"
                       " %(CountryCode)s" % response['address'])
        else:
            address = response['address']['LongLabel']

        location = Location(
            address, (response['location']['y'], response['location']['x']),
            response['address'])
        if exactly_one:
            return location
        else:
            return [location]
    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'}
        params['sourceCountry'] = "SG"
        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
Ejemplo n.º 10
0
Archivo: base.py Proyecto: GeoRab/geopy
 def _call_geocoder(self, url, timeout=None, raw=False):
     """
     For a generated query URL, get the results.
     """
     try:
         page = self.urlopen(url, timeout=timeout or self.timeout)
     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()
             error_code_map = {
                 400: GeocoderQueryError,
                 401: GeocoderAuthenticationFailure,
                 402: GeocoderQuotaExceeded,
                 403: GeocoderInsufficientPrivileges,
                 407: GeocoderAuthenticationFailure,
                 412: GeocoderQueryError,
                 413: GeocoderQueryError,
                 414: GeocoderQueryError,
                 502: GeocoderServiceError,
                 503: GeocoderTimedOut,
                 504: GeocoderTimedOut
             }
             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 isinstance(error, SocketTimeout):
             raise GeocoderTimedOut('Service timed out')
         elif isinstance(error, SSLError):
             if "timed out in message":
                 raise GeocoderTimedOut('Service timed out')
         if not py3k:
             err = GeocoderServiceError(message)
             err.__traceback__ = error
             raise err
         else:
             raise GeocoderServiceError(message)
     if raw:
         return page
     return json.loads(decode_page(page))
Ejemplo n.º 11
0
    def geocode(self, query='', street='', city='', state='', zip_cd='',
                n_matches=1, timeout=60):
        """
        Return a ranked list of locations for an address.
        :param string query: The single-line address you wish to geocode.
        :param string street: Optional, Street if not using single-line
        :param string city: Optional, City
        :param string state: Optional, State
        :param string zip_cd: Optional, Zip Code
        :param int n_matches: Return top n matches.
        :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.
        """

        params = {'Single Line Input': query,
                  'Street': street,
                  'City': city,
                  'State': state,
                  'ZIP': zip_cd,
                  'f': 'json',
                  'maxLocations': n_matches}

        if not (len(query) or len(street)):
            raise ConfigurationError(
                "Street or Full Address must be entered."
            )

        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, street, city, state, zip_cd, n_matches, timeout)
            raise GeocoderServiceError(str(response['error']))

        if not len(response['candidates']):
            return None

        geocoded = []
        candidate_cnt = 1
        for candidate in response['candidates']:
            geocoded.append({
                'candidate':candidate_cnt,
                'attributes':{
                    'score':candidate['score'],
                    'match_addr':candidate['address'],
                    'location':{'x':candidate['location']['x'],
                                'y':candidate['location']['y']}}})
            candidate_cnt += 1

        return {'candidates':geocoded}
Ejemplo n.º 12
0
    def reverse(
            self,
            query,
            exactly_one=True,
            timeout=None,  # pylint: disable=R0913,W0221
            distance=None,
            wkid=DEFAULT_WKID):
        """
        Given a point, find an address.

        :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?

        :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 string wkid: WKID to use for both input and output coordinates.
        """
        # ArcGIS is lon,lat; maintain lat,lon convention of geopy
        point = self._coerce_point_to_string(query).split(",")
        if wkid != DEFAULT_WKID:
            location = {"x": point[1], "y": point[0], "spatialReference": wkid}
        else:
            location = ",".join((point[1], point[0]))
        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)
            raise GeocoderServiceError(str(response['error']))
        address = ("%(Address)s, %(City)s, %(Region)s %(Postal)s,"
                   " %(CountryCode)s" % response['address'])
        return Location(address,
                        (response['location']['y'], response['location']['x']),
                        response['address'])
Ejemplo n.º 13
0
    def _decode_page(self, page):
        encoding = page.headers.get_content_charset() or "utf-8"
        try:
            body_bytes = page.read()
        except Exception:
            raise GeocoderServiceError("Unable to read the response")

        try:
            return str(body_bytes, encoding=encoding)
        except ValueError:
            raise GeocoderParseError("Unable to decode the response bytes")
Ejemplo n.º 14
0
 def _call_geocoder(self, url, raw=False):
     """
     For a generated query URL, get the results.
     """
     try:
         page = self.urlopen(url)
     except HTTPError as error:
         raise GeocoderServiceError(error.getcode(),
                                    getattr(error, 'msg', None))
     if raw:
         return page
     return json.loads(decode_page(page))
Ejemplo n.º 15
0
 def _call_geocoder(self, url, timeout=None, raw=False):
     """
     For a generated query URL, get the results.
     """
     try:
         page = self.urlopen(url, timeout=timeout or self.timeout)
     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 isinstance(error, SocketTimeout):
             raise GeocoderTimedOut('Service timed out')
         elif isinstance(error, SSLError):
             if "timed out in message":
                 raise GeocoderTimedOut('Service timed out')
         if not py3k:
             err = GeocoderServiceError(message)
             err.__traceback__ = error
             raise err
         else:
             raise GeocoderServiceError(message)
     if raw:
         return page
     return json.loads(decode_page(page))
Ejemplo n.º 16
0
    def _parse_json(self, doc, exactly_one=True):
        """
        Parse a location name, latitude, and longitude from an JSON response.
        """
        status_code = doc.get("statusCode", 200)
        if status_code != 200:
            err = doc.get("errorDetails", "")
            if status_code == 401:
                raise GeocoderAuthenticationFailure(err)
            elif status_code == 403:
                raise GeocoderInsufficientPrivileges(err)
            elif status_code == 429:
                raise GeocoderRateLimited(err)
            elif status_code == 503:
                raise GeocoderUnavailable(err)
            else:
                raise GeocoderServiceError(err)

        try:
            resources = doc['Response']['View'][0]['Result']
        except IndexError:
            resources = None
        if not resources:
            return None

        def parse_resource(resource):
            """
            Parse each return object.
            """
            stripchars = ", \n"
            addr = resource['Location']['Address']

            address = addr.get('Label', '').strip(stripchars)
            city = addr.get('City', '').strip(stripchars)
            state = addr.get('State', '').strip(stripchars)
            zipcode = addr.get('PostalCode', '').strip(stripchars)
            country = addr.get('Country', '').strip(stripchars)

            city_state = join_filter(", ", [city, state])
            place = join_filter(" ", [city_state, zipcode])
            location = join_filter(", ", [address, place, country])

            display_pos = resource['Location']['DisplayPosition']
            latitude = float(display_pos['Latitude'])
            longitude = float(display_pos['Longitude'])

            return Location(location, (latitude, longitude), resource)

        if exactly_one:
            return parse_resource(resources[0])
        else:
            return [parse_resource(resource) for resource in resources]
Ejemplo n.º 17
0
 def _raise_for_error(self, body):
     err = body.get('status')
     if err:
         code = err['value']
         message = err['message']
         # http://www.geonames.org/export/webservice-exception.html
         if message.startswith("user account not enabled to use"):
             raise GeocoderInsufficientPrivileges(message)
         if code == 10:
             raise GeocoderAuthenticationFailure(message)
         if code in (18, 19, 20):
             raise GeocoderQuotaExceeded(message)
         raise GeocoderServiceError(message)
Ejemplo n.º 18
0
    def geocode(self, query, exactly_one=True, timeout=None, restrict_to=None):
        """
        Geocode a location query.

        :param string 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 restrict_to: Restricts results to a subset of location
        types. e.g. ['Address', 'CountryRegion']
        """
        params = {'text': query, 'f': 'json'}
        if exactly_one is True:
            params['maxLocations'] = 1
        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['locations']):
            return None
        geocoded = []
        for resource in response['locations']:
            geometry = resource['feature']['geometry']
            if restrict_to is not None:
                if self.address_type(resource) not in restrict_to:
                    continue
            geocoded.append(
                Location(resource['name'], (geometry['y'], geometry['x']),
                         resource))
        if exactly_one is True and len(geocoded) > 0:
            return geocoded[0]
        elif len(geocoded) == 0:
            return None
        return geocoded
    def _parse_json(doc, exactly_one=True):  # pylint: disable=W0221
        """
        Parse a location name, latitude, and longitude from an JSON response.
        """
        status_code = doc.get("statusCode", 200)
        if status_code != 200:
            err = doc.get("errorDetails", "")
            if status_code == 401:
                raise GeocoderAuthenticationFailure(err)
            elif status_code == 403:
                raise GeocoderInsufficientPrivileges(err)
            elif status_code == 429:
                raise GeocoderQuotaExceeded(err)
            elif status_code == 503:
                raise GeocoderUnavailable(err)
            else:
                raise GeocoderServiceError(err)

        resources = doc['resourceSets'][0]['resources']
        if resources is None or not len(resources):  # pragma: no cover
            return None

        def parse_resource(resource):
            """
            Parse each return object.
            """
            stripchars = ", \n"
            addr = resource['address']

            address = addr.get('addressLine', '').strip(stripchars)
            city = addr.get('locality', '').strip(stripchars)
            state = addr.get('adminDistrict', '').strip(stripchars)
            zipcode = addr.get('postalCode', '').strip(stripchars)
            country = addr.get('countryRegion', '').strip(stripchars)

            city_state = join_filter(", ", [city, state])
            place = join_filter(" ", [city_state, zipcode])
            location = join_filter(", ", [address, place, country])

            latitude = resource['point']['coordinates'][0] or None
            longitude = resource['point']['coordinates'][1] or None
            if latitude and longitude:
                latitude = float(latitude)
                longitude = float(longitude)

            return Location(location, (latitude, longitude), resource)

        if exactly_one:
            return parse_resource(resources[0])
        else:
            return [parse_resource(resource) for resource in resources]
Ejemplo n.º 20
0
    def _parse_json(self, doc, userlocation, exactly_one):
        """
        Parse JSON response body.
        """
        self.temparray = []
        places = doc.get('geonames', [])
        err = doc.get('status', None)
        if err and 'message' in err:
            if err['message'].startswith("user account not enabled to use"):
                raise GeocoderInsufficientPrivileges(err['message'])
            else:
                raise GeocoderServiceError(err['message'])
        if not len(places):
            return None

        def parse_code(place):
            """
            Parse each record.
            """
            latitude = place.get('lat', None)
            longitude = place.get('lng', None)
            if latitude and longitude:
                latitude = float(latitude)
                longitude = float(longitude)
            else:
                return None

            placename = place.get('name')
            state = place.get('adminCode1', None)
            country = place.get('countryCode', None)

            location = ', '.join([x for x in [placename, state, country] if x])

            return Location(location, (latitude, longitude), place)

        if userlocation is None:
            if exactly_one:
                return parse_code(places[0])
            else:
                return [parse_code(place) for place in places]
        else:
            for place in places:
                self.temparray.append(parse_code(place))
            resultplace = Calculation.calculations(userlocation,
                                                   self.temparray)

            if exactly_one:
                return resultplace[0]
            else:
                return resultplace
Ejemplo n.º 21
0
 def _call_geocoder(self, url, timeout=None, raw=False):
     """
     For a generated query URL, get the results.
     """
     try:
         page = self.urlopen(url, timeout=timeout or self.timeout)
     except HTTPError as error:
         if hasattr(self, '_geocoder_exception_handler'):
             self._geocoder_exception_handler(error)  # pylint: disable=E1101
         raise GeocoderServiceError(error.getcode(),
                                    getattr(error, 'msg', None))
     if raw:
         return page
     return json.loads(decode_page(page))
Ejemplo n.º 22
0
 def _normalize_exceptions(self):
     try:
         yield
     except (GeopyError, AdapterHTTPError, AssertionError):
         raise
     except Exception as error:
         message = str(error)
         if isinstance(error, asyncio.TimeoutError):
             raise GeocoderTimedOut("Service timed out")
         elif isinstance(error, SSLError):
             if "timed out" in message:
                 raise GeocoderTimedOut("Service timed out")
         elif isinstance(error, aiohttp.ClientConnectionError):
             raise GeocoderUnavailable(message)
         raise GeocoderServiceError(message)
Ejemplo n.º 23
0
    def _parse_geocode(self, response, exactly_one):
        if 'error' in response:
            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
Ejemplo n.º 24
0
    def geocode_batch(self, addresses, timeout=None, wkid=DEFAULT_WKID):
        """
        Process address dict returning top match only.

        :param list addresses: List of tuples (uid, address) uid = int, address = sting.

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

        if not len(addresses):
            raise ConfigurationError(
                "Must pass a list of tuples with uid and address.")

        geocoded = []
        for i in xrange(0, len(addresses), 300):

            records = []
            for a in addresses[i:i + 300]:
                attributes_dict = {
                    "attributes": {
                        "OBJECTID": a[0],
                        "Single Line Input": a[1]
                    }
                }
                records.append(attributes_dict)

            query = {"records": records}

            params = {'addresses': query, 'outSR': wkid, 'f': 'json'}

            url = "?".join((self.batch_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(timeout=timeout)
                raise GeocoderServiceError(str(response['error']))

            #add code for parsing output here
            for location in response['locations']:
                geocoded.append({
                    'uid': location['attributes']['ResultID'],
                    'attributes': {
                        'score': location['score'],
                        'match_addr': location['attributes']['Match_addr'],
                        'location': {
                            'x': location['location']['x'],
                            'y': location['location']['y']
                        }
                    }
                })

        return {'geocoded': geocoded}
Ejemplo n.º 25
0
    def geocode(self,
                query,
                exactly_one=True,
                timeout=None,
                userlocation=None):
        """
        Geocode a location query.

        :param string 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.
        """
        #using different url, depend on activating multiple results based on exactly_one flag
        if exactly_one:
            params = {'text': query, 'maxLocations': 1, 'f': 'json'}
            url = "?".join((self.api, urlencode(params)))
        else:
            params = {'SingleLine': query, 'f': 'json'}
            url = "?".join((self.api_multi, 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.
        self.temparray = []
        if exactly_one:
            if not len(response['locations']):
                return None
            self.temparray = []
            for resource in response['locations']:
                geometry = resource['feature']['geometry']
                self.temparray.append(
                    Location(resource['name'], (geometry['y'], geometry['x']),
                             resource))
            return self.temparray[0]

        if not len(response['candidates']):
            return None
        self.temparray = []
        for resource in response['candidates']:
            geometry = resource['location']
            self.temparray.append(
                Location(resource['address'], (geometry['y'], geometry['x']),
                         resource))

        if userlocation != None:
            resultplace = Calculation.calculations(userlocation,
                                                   self.temparray)
            return resultplace
        else:
            return self.temparray
Ejemplo n.º 26
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
Ejemplo n.º 27
0
    def reverse(self, query, timeout=None, distance=100, wkid=DEFAULT_WKID):
        """
        Given a point, find an address.

        :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 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: Search radius from query location, in meters.
            Default 100 meters if not specified.

        :param string wkid: WKID to use for both input and output coordinates.
            Default 4326 matching Brown ArcGIS server.
        """

        # ArcGIS is lon,lat; maintain lat,lon convention of geopy
        point = self._coerce_point_to_string(query).split(",")
        if wkid != DEFAULT_WKID:
            location = {"x": point[1], "y": point[0], "spatialReference": wkid}
        else:
            location = ",".join((point[1], point[0]))

        params = {
            'location': location,
            'f': 'json',
            'distance': distance,
            'outSR': wkid
        }

        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,
                                    timeout=timeout,
                                    distance=distance,
                                    wkid=wkid)
            raise GeocoderServiceError(str(response['error']))

        address = {
            'match_addr':
            ('%(Street)s, %(City)s, %(State)s, %(ZIP)s' % response['address']),
            'location': {
                'x': response['location']['x'],
                'y': response['location']['y']
            }
        }

        return address
Ejemplo n.º 28
0
    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,
                stacklevel=2)
            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]