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 / placefinder.py @ 545

History | View | Annotate | Download (6.08 KB)

1
"""
2
:class:`.YahooPlaceFinder` geocoder.
3
"""
4

    
5
try:
6
    from requests import get
7
    from requests_oauthlib import OAuth1
8
    requests_missing = False
9
except ImportError:
10
    requests_missing = True
11

    
12
from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT
13
from geopy.exc import GeocoderParseError
14
from geopy.location import Location
15
from geopy.compat import string_compare, py3k
16

    
17

    
18
__all__ = ("YahooPlaceFinder", )
19

    
20

    
21
class YahooPlaceFinder(Geocoder): # pylint: disable=W0223
22
    """
23
    Geocoder that utilizes the Yahoo! BOSS PlaceFinder API. Documentation at:
24
        https://developer.yahoo.com/boss/geo/docs/
25
    """
26

    
27
    def __init__(
28
            self,
29
            consumer_key,
30
            consumer_secret,
31
            timeout=DEFAULT_TIMEOUT,
32
            proxies=None
33
        ):  # pylint: disable=R0913
34
        """
35
        :param string consumer_key: Key provided by Yahoo.
36

37
        :param string consumer_secret: Secret corresponding to the key
38
            provided by Yahoo.
39

40
        :param int timeout: Time, in seconds, to wait for the geocoding service
41
            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
42
            exception.
43

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

49
            .. versionadded:: 0.96
50
        """
51
        if requests_missing:
52
            raise ImportError(
53
                'requests-oauthlib is needed for YahooPlaceFinder.'
54
                ' Install with `pip install geopy -e ".[placefinder]"`.'
55
            )
56
        super(YahooPlaceFinder, self).__init__(
57
            timeout=timeout, proxies=proxies
58
        )
59
        self.consumer_key = (
60
            unicode(consumer_key)
61
            if not py3k
62
            else str(consumer_key)
63
        )
64
        self.consumer_secret = (
65
            unicode(consumer_secret)
66
            if not py3k
67
            else str(consumer_secret)
68
        )
69
        self.auth = OAuth1(
70
            client_key=self.consumer_key,
71
            client_secret=self.consumer_secret,
72
            signature_method="HMAC-SHA1",
73
            signature_type="AUTH_HEADER",
74
        )
75
        self.api = "https://yboss.yahooapis.com/geo/placefinder"
76

    
77
    @staticmethod
78
    def _filtered_results(results, min_quality, valid_country_codes):
79
        """
80
        Returns only the results that meet the minimum quality threshold
81
        and are located in expected countries.
82
        """
83
        if min_quality:
84
            results = [
85
                loc
86
                for loc in results
87
                if int(loc.raw["quality"]) > min_quality
88
            ]
89

    
90
        if valid_country_codes:
91
            results = [
92
                loc
93
                for loc in results
94
                if loc.raw["countrycode"] in valid_country_codes
95
            ]
96

    
97
        return results
98

    
99
    def _parse_response(self, content):
100
        """
101
        Returns the parsed result of a PlaceFinder API call.
102
        """
103
        try:
104
            placefinder = (
105
                content["bossresponse"]["placefinder"]
106
            )
107
            if not len(placefinder) or not len(placefinder.get("results", [])):
108
                return None
109
            results = [
110
                Location(
111
                    self.humanize(place),
112
                    (float(place["latitude"]), float(place["longitude"])),
113
                    raw=place
114
                )
115
                for place in placefinder["results"]
116
            ]
117
        except (KeyError, ValueError):
118
            raise GeocoderParseError("Error parsing PlaceFinder result")
119

    
120
        return results
121

    
122
    @staticmethod
123
    def humanize(location):
124
        """
125
        Returns a human readable representation of a raw PlaceFinder location
126
        """
127
        return ", ".join([
128
            location[line]
129
            for line in ["line1", "line2", "line3", "line4"]
130
            if location[line]
131
        ])
132

    
133
    def geocode(
134
            self,
135
            query,
136
            exactly_one=True,
137
            timeout=None,
138
            min_quality=0,
139
            reverse=False,
140
            valid_country_codes=None,
141
        ):  # pylint: disable=W0221,R0913
142
        """
143
        Geocode a location query.
144

145
        :param string query: The address or query you wish to geocode.
146

147
        :param bool exactly_one: Return one result or a list of results, if
148
            available.
149

150
        :param int min_quality:
151

152
        :param bool reverse:
153

154
        :param valid_country_codes:
155
        :type valid_country_codes: list or tuple
156
        """
157
        params = {
158
            "location": query,
159
            "flags": "J", # JSON
160
        }
161

    
162
        if reverse is True:
163
            params["gflags"] = "R"
164
        if exactly_one is True:
165
            params["count"] = "1"
166

    
167
        response = self._call_geocoder(
168
            self.api,
169
            timeout=timeout,
170
            requester=get,
171
            params=params,
172
            auth=self.auth,
173
        )
174
        results = self._parse_response(response)
175
        if results is None:
176
            return None
177

    
178
        results = self._filtered_results(
179
            results,
180
            min_quality,
181
            valid_country_codes,
182
        )
183

    
184
        if exactly_one:
185
            return results[0]
186
        else:
187
            return results
188

    
189
    def reverse(self, query, exactly_one=True, timeout=None):
190
        """
191
        Returns a reverse geocoded location using Yahoo"s PlaceFinder API.
192

193
        :param query: The coordinates for which you wish to obtain the
194
            closest human-readable addresses.
195
        :type query: :class:`geopy.point.Point`, list or tuple of (latitude,
196
            longitude), or string as "%(latitude)s, %(longitude)s"
197

198
        :param bool exactly_one: Return one result or a list of results, if
199
            available.
200
        """
201
        query = self._coerce_point_to_string(query)
202
        if isinstance(query, string_compare):
203
            query = query.replace(" ", "") # oauth signature failure; todo
204
        return self.geocode(
205
            query,
206
            exactly_one=exactly_one,
207
            timeout=timeout,
208
            reverse=True
209
        )