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 / dot_us.py @ 545
History | View | Annotate | Download (5.11 KB)
1 |
"""
|
---|---|
2 |
:class:`GeocoderDotUS` geocoder.
|
3 |
"""
|
4 |
|
5 |
import csv |
6 |
from base64 import encodestring |
7 |
from geopy.compat import urlencode, py3k, Request |
8 |
from geopy.geocoders.base import ( |
9 |
Geocoder, |
10 |
DEFAULT_FORMAT_STRING, |
11 |
DEFAULT_TIMEOUT, |
12 |
) |
13 |
from geopy.location import Location |
14 |
from geopy.exc import ConfigurationError |
15 |
from geopy.util import logger, join_filter |
16 |
|
17 |
|
18 |
__all__ = ("GeocoderDotUS", )
|
19 |
|
20 |
|
21 |
class GeocoderDotUS(Geocoder): # pylint: disable=W0223 |
22 |
"""
|
23 |
GeocoderDotUS geocoder, documentation at:
|
24 |
http://geocoder.us/
|
25 |
|
26 |
Note that GeocoderDotUS does not support SSL.
|
27 |
"""
|
28 |
|
29 |
def __init__( |
30 |
self,
|
31 |
username=None,
|
32 |
password=None,
|
33 |
format_string=DEFAULT_FORMAT_STRING, |
34 |
timeout=DEFAULT_TIMEOUT, |
35 |
proxies=None,
|
36 |
): # pylint: disable=R0913
|
37 |
"""
|
38 |
:param string username:
|
39 |
|
40 |
:param string password:
|
41 |
|
42 |
:param string format_string: String containing '%s' where the
|
43 |
string to geocode should be interpolated before querying the
|
44 |
geocoder. For example: '%s, Mountain View, CA'. The default
|
45 |
is just '%s'.
|
46 |
|
47 |
:param int timeout: Time, in seconds, to wait for the geocoding service
|
48 |
to respond before raising an :class:`geopy.exc.GeocoderTimedOut`
|
49 |
exception.
|
50 |
|
51 |
.. versionadded:: 0.97
|
52 |
|
53 |
:param dict proxies: If specified, routes this geocoder's requests
|
54 |
through the specified proxy. E.g., {"https": "192.0.2.0"}. For
|
55 |
more information, see documentation on
|
56 |
:class:`urllib2.ProxyHandler`.
|
57 |
|
58 |
.. versionadded:: 0.96
|
59 |
"""
|
60 |
super(GeocoderDotUS, self).__init__( |
61 |
format_string=format_string, timeout=timeout, proxies=proxies |
62 |
) |
63 |
if username or password: |
64 |
if not (username and password): |
65 |
raise ConfigurationError(
|
66 |
"Username and password must both specified"
|
67 |
) |
68 |
self.authenticated = True |
69 |
self.api = "http://geocoder.us/member/service/namedcsv" |
70 |
else:
|
71 |
self.authenticated = False |
72 |
self.api = "http://geocoder.us/service/namedcsv" |
73 |
self.username = username
|
74 |
self.password = password
|
75 |
|
76 |
def geocode(self, query, exactly_one=True, timeout=None): |
77 |
"""
|
78 |
Geocode a location query.
|
79 |
|
80 |
:param string query: The address or query you wish to geocode.
|
81 |
|
82 |
:param bool exactly_one: Return one result or a list of results, if
|
83 |
available.
|
84 |
|
85 |
:param int timeout: Time, in seconds, to wait for the geocoding service
|
86 |
to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
|
87 |
exception. Set this only if you wish to override, on this call
|
88 |
only, the value set during the geocoder's initialization.
|
89 |
|
90 |
.. versionadded:: 0.97
|
91 |
"""
|
92 |
query_str = self.format_string % query
|
93 |
|
94 |
url = "?".join((self.api, urlencode({'address':query_str}))) |
95 |
logger.debug("%s.geocode: %s", self.__class__.__name__, url) |
96 |
if self.authenticated is True: |
97 |
auth = " ".join((
|
98 |
"Basic",
|
99 |
encodestring(":".join((self.username, self.password))\ |
100 |
.encode('utf-8')).strip().decode('utf-8') |
101 |
)) |
102 |
url = Request(url, headers={"Authorization": auth})
|
103 |
page = self._call_geocoder(url, timeout=timeout, raw=True) |
104 |
content = page.read().decode("utf-8") if py3k else page.read() # pylint: disable=E1101,E1103 |
105 |
places = [ |
106 |
r for r in csv.reader( |
107 |
[content, ] if not isinstance(content, list) |
108 |
else content
|
109 |
) |
110 |
] |
111 |
if not len(places): |
112 |
return None |
113 |
if exactly_one is True: |
114 |
return self._parse_result(places[0]) |
115 |
else:
|
116 |
result = [self._parse_result(res) for res in places] |
117 |
if None in result: # todo |
118 |
return None |
119 |
return result
|
120 |
|
121 |
@staticmethod
|
122 |
def _parse_result(result): |
123 |
"""
|
124 |
Parse individual results. Different, but lazy actually, so... ok.
|
125 |
"""
|
126 |
# turn x=y pairs ("lat=47.6", "long=-117.426")
|
127 |
# into dict key/value pairs:
|
128 |
place = dict(
|
129 |
[x.split('=') for x in result if len(x.split('=')) > 1] |
130 |
) |
131 |
if 'error' in place: |
132 |
if "couldn't find" in place['error']: |
133 |
return None |
134 |
|
135 |
address = [ |
136 |
place.get('number', None), |
137 |
place.get('prefix', None), |
138 |
place.get('street', None), |
139 |
place.get('type', None), |
140 |
place.get('suffix', None) |
141 |
] |
142 |
city = place.get('city', None) |
143 |
state = place.get('state', None) |
144 |
zip_code = place.get('zip', None) |
145 |
|
146 |
name = join_filter(", ", [
|
147 |
join_filter(" ", address),
|
148 |
city, |
149 |
join_filter(" ", [state, zip_code])
|
150 |
]) |
151 |
|
152 |
latitude = place.get('lat', None) |
153 |
longitude = place.get('long', None) |
154 |
if latitude and longitude: |
155 |
latlon = float(latitude), float(longitude) |
156 |
else:
|
157 |
return None |
158 |
return Location(name, latlon, place)
|