Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / geopy / geocoders / navidata.py @ 564

History | View | Annotate | Download (5.95 KB)

1
"""
2
:class:`.NaviData` is the NaviData.pl geocoder.
3
"""
4

    
5
from geopy.compat import urlencode
6
from geopy.location import Location
7
from geopy.util import logger
8
from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT
9

    
10
from geopy.exc import (
11
    GeocoderQueryError,
12
    GeocoderQuotaExceeded,
13
)
14

    
15

    
16
__all__ = ("NaviData", )
17

    
18

    
19
class NaviData(Geocoder):  # pylint: disable=W0223
20
    """
21
    Geocoder using the NaviData API. Documentation at:
22

23
        http://www.navidata.pl
24
    """
25

    
26
    def __init__(
27
            self,
28
            api_key=None,
29
            domain='api.navidata.pl',
30
            timeout=DEFAULT_TIMEOUT,
31
            proxies=None,
32
            user_agent=None,
33
    ):
34
        """
35
            .. versionadded:: 1.8.0
36

37
        Initialize NaviData geocoder. Please note that 'scheme' parameter is
38
        not supported: at present state, all NaviData traffic use plain http.
39

40
        :param string api_key: The commercial API key for service. None
41
            required if you use the API for non-commercial purposes.
42

43
        :param string domain: Currently it is 'api.navidata.pl', can
44
            be changed for testing purposes.
45

46
        :param dict proxies: If specified, routes this geocoder's requests
47
            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
48
            more information, see documentation on
49
            :class:`urllib2.ProxyHandler`.
50

51
        """
52
        super(NaviData, self).__init__(
53
            scheme="http", timeout=timeout, proxies=proxies, user_agent=user_agent
54
        )
55

    
56
        self.api_key = api_key
57
        self.domain = domain.strip('/')
58
        self.geocode_api = 'http://%s/geocode' % (self.domain)
59
        self.reverse_geocode_api = 'http://%s/revGeo' % (self.domain)
60

    
61
    def geocode(
62
            self,
63
            query,
64
            exactly_one=True,
65
            timeout=None,
66
        ):
67
        """
68
        Geocode a location query.
69

70
        :param string query: The query string to be geocoded; this must
71
            be URL encoded.
72

73
        :param bool exactly_one: Return one result or a list of results, if
74
            available.
75

76
        :param int timeout: Time, in seconds, to wait for the geocoding service
77
            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
78
            exception. Set this only if you wish to override, on this call
79
            only, the value set during the geocoder's initialization.
80

81
        """
82
        params = {
83
            'q': self.format_string % query,
84
        }
85

    
86
        if self.api_key is not None:
87
            params["api_key"] = self.api_key
88

    
89
        url = "?".join((self.geocode_api, urlencode(params)))
90

    
91
        logger.debug("%s.geocode: %s", self.__class__.__name__, url)
92
        return self._parse_json_geocode(
93
            self._call_geocoder(url, timeout=timeout), exactly_one
94
        )
95

    
96
    def reverse(
97
            self,
98
            query,
99
            exactly_one=True,
100
            timeout=None,
101
        ):
102
        """
103
        Given a point, find an address.
104

105
        :param query: The coordinates for which you wish to obtain the
106
            closest human-readable addresses.
107
        :type query: :class:`geopy.point.Point`, list or tuple of (latitude,
108
            longitude), or string as "%(latitude)s, %(longitude)s"
109

110
        :param boolean exactly_one: Return one result or a list of results, if
111
            available. Currently this has no effect
112
            (only one address is returned by API).
113

114
        :param int timeout: Time, in seconds, to wait for the geocoding service
115
            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
116
            exception. Set this only if you wish to override, on this call
117
            only, the value set during the geocoder's initialization.
118

119
        """
120

    
121
        (lat, lon) = self._coerce_point_to_string(query).split(',')
122

    
123
        params = {
124
            'lat': lat,
125
            'lon': lon
126
        }
127

    
128
        if self.api_key is not None:
129
            params["api_key"] = self.api_key
130

    
131
        url = "?".join((self.reverse_geocode_api, urlencode(params)))
132
        logger.debug("%s.reverse: %s", self.__class__.__name__, url)
133
        return self._parse_json_revgeocode(
134
            self._call_geocoder(url, timeout=timeout)
135
        )
136

    
137
    @staticmethod
138
    def _parse_json_geocode(page, exactly_one=True):
139
        '''Returns location, (latitude, longitude) from json feed.'''
140

    
141
        places = page
142

    
143
        if not len(places):
144
            return None
145

    
146
        def parse_place(place):
147
            '''Get the location, lat, lon from a single json result.'''
148
            location = place.get('description')
149
            latitude = place.get('lat')
150
            longitude = place.get('lon')
151
            return Location(location, (latitude, longitude), place)
152

    
153
        if exactly_one:
154
            return parse_place(places[0])
155
        else:
156
            return [parse_place(place) for place in places]
157

    
158
    @staticmethod
159
    def _parse_json_revgeocode(page):
160
        '''Returns location, (latitude, longitude) from json feed.'''
161
        result = page
162

    
163
        if result.get('description', None) is None:
164
            return None
165

    
166
        location = result.get('description')
167
        latitude = result.get('lat')
168
        longitude = result.get('lon')
169

    
170
        return Location(location, (latitude, longitude), result)
171

    
172

    
173
    @staticmethod
174
    def _check_status(status):
175
        """
176
        Validates error statuses.
177
        """
178
        status_code = status['code']
179

    
180
        if status_code == 200:
181
            # When there are no results, just return.
182
            return
183

    
184
        elif status_code == 429:
185
            # Rate limit exceeded
186
            raise GeocoderQuotaExceeded(
187
                'The given key has gone over the requests limit in the 24'
188
                ' hour period or has submitted too many requests in too'
189
                ' short a period of time.'
190
            )
191

    
192
        elif status_code == 403:
193
            raise GeocoderQueryError(
194
                'Your request was denied.'
195
            )
196
        else:
197
            raise GeocoderQueryError('Unknown error: ' + str(status_code))