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)) |