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