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

History | View | Annotate | Download (5.2 KB)

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

    
5
from geopy.compat import urlencode
6

    
7
from geopy.geocoders.base import Geocoder, DEFAULT_TIMEOUT
8
from geopy.location import Location
9
from geopy.exc import (
10
    GeocoderServiceError,
11
    GeocoderParseError
12
)
13
from geopy.util import logger
14

    
15

    
16
__all__ = ("Yandex", )
17

    
18

    
19
class Yandex(Geocoder): # pylint: disable=W0223
20
    """
21
    Yandex geocoder, documentation at:
22
        http://api.yandex.com/maps/doc/geocoder/desc/concepts/input_params.xml
23
    """
24

    
25
    def __init__(
26
            self,
27
            api_key=None,
28
            lang=None,
29
            timeout=DEFAULT_TIMEOUT,
30
            proxies=None
31
        ):
32
        """
33
        Create a Yandex-based geocoder.
34

35
            .. versionadded:: 1.5.0
36

37
        :param string api_key: Yandex API key (not obligatory)
38
            http://api.yandex.ru/maps/form.xml
39

40
        :param string lang: response locale, the following locales are
41
            supported: "ru_RU" (default), "uk_UA", "be_BY", "en_US", "tr_TR"
42

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

47
        :param dict proxies: If specified, routes this geocoder's requests
48
            through the specified proxy. E.g., {"https": "192.0.2.0"}. For
49
            more information, see documentation on
50
            :class:`urllib2.ProxyHandler`.
51
        """
52
        super(Yandex, self).__init__(
53
            scheme='http', timeout=timeout, proxies=proxies
54
        )
55
        self.api_key = api_key
56
        self.lang = lang
57
        self.api = 'http://geocode-maps.yandex.ru/1.x/'
58

    
59
    def geocode(self, query, exactly_one=True, timeout=None): # pylint: disable=W0221
60
        """
61
        Geocode a location query.
62

63
        :param string query: The address or query you wish to geocode.
64

65
        :param bool exactly_one: Return one result or a list of results, if
66
            available.
67

68
        :param int timeout: Time, in seconds, to wait for the geocoding service
69
            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
70
            exception. Set this only if you wish to override, on this call
71
            only, the value set during the geocoder's initialization.
72
        """
73
        params = {
74
            'geocode': query,
75
            'format': 'json'
76
        }
77
        if not self.api_key is None:
78
            params['key'] = self.api_key
79
        if not self.lang is None:
80
            params['lang'] = self.lang
81
        if exactly_one is True:
82
            params['results'] = 1
83
        url = "?".join((self.api, urlencode(params)))
84
        logger.debug("%s.geocode: %s", self.__class__.__name__, url)
85
        return self._parse_json(
86
            self._call_geocoder(url, timeout=timeout),
87
            exactly_one,
88
        )
89

    
90
    def reverse(
91
            self,
92
            query,
93
            exactly_one=False,
94
            timeout=None,
95
        ):
96
        """
97
        Given a point, find an address.
98

99
        :param string query: The coordinates for which you wish to obtain the
100
            closest human-readable addresses.
101
        :type query: :class:`geopy.point.Point`, list or tuple of (latitude,
102
            longitude), or string as "%(latitude)s, %(longitude)s"
103

104
        :param boolean exactly_one: Return one result or a list of results, if
105
            available.
106

107
        :param int timeout: Time, in seconds, to wait for the geocoding service
108
            to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
109
            exception.
110

111
        """
112
        try:
113
            lat, lng = [
114
                x.strip() for x in
115
                self._coerce_point_to_string(query).split(',')
116
            ]
117
        except ValueError:
118
            raise ValueError("Must be a coordinate pair or Point")
119
        params = {
120
            'geocode': '{0},{1}'.format(lng, lat),
121
            'format': 'json'
122
        }
123
        if self.api_key is not None:
124
            params['key'] = self.api_key
125
        if self.lang is not None:
126
            params['lang'] = self.lang
127
        url = "?".join((self.api, urlencode(params)))
128
        logger.debug("%s.reverse: %s", self.__class__.__name__, url)
129
        return self._parse_json(
130
            self._call_geocoder(url, timeout=timeout),
131
            exactly_one
132
        )
133

    
134
    def _parse_json(self, doc, exactly_one):
135
        """
136
        Parse JSON response body.
137
        """
138
        if doc.get('error'):
139
            raise GeocoderServiceError(doc['error']['message'])
140

    
141
        try:
142
            places = doc['response']['GeoObjectCollection']['featureMember']
143
        except KeyError:
144
            raise GeocoderParseError('Failed to parse server response')
145

    
146
        def parse_code(place):
147
            """
148
            Parse each record.
149
            """
150
            try:
151
                place = place['GeoObject']
152
            except KeyError:
153
                raise GeocoderParseError('Failed to parse server response')
154

    
155
            longitude, latitude = [
156
                float(_) for _ in place['Point']['pos'].split(' ')
157
            ]
158

    
159
            location = place.get('description')
160

    
161
            return Location(location, (latitude, longitude), place)
162

    
163
        if exactly_one:
164
            return parse_code(places[0])
165
        else:
166
            return [parse_code(place) for place in places]