Merge pull request #1 from CartoDB/adds-heremaps-module
Initial commit for heremaps module
This commit is contained in:
commit
35d4cf245f
0
lib/python/heremaps/__init__.py
Normal file
0
lib/python/heremaps/__init__.py
Normal file
22
lib/python/heremaps/heremapsexceptions.py
Normal file
22
lib/python/heremaps/heremapsexceptions.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/local/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
class BadGeocodingParams(Exception):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
def __str__(self):
|
||||||
|
return repr('Bad geocoding params: ' + json.dumps(value))
|
||||||
|
|
||||||
|
class NoGeocodingParams(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return repr('No params for geocoding specified')
|
||||||
|
|
||||||
|
class EmptyGeocoderResponse(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return repr('The request could not be geocoded')
|
||||||
|
|
||||||
|
class MalformedResult(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return repr('Result structure is malformed')
|
110
lib/python/heremaps/heremapsgeocoder.py
Normal file
110
lib/python/heremaps/heremapsgeocoder.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/local/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import json
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from heremaps.heremapsexceptions import BadGeocodingParams
|
||||||
|
from heremaps.heremapsexceptions import EmptyGeocoderResponse
|
||||||
|
from heremaps.heremapsexceptions import NoGeocodingParams
|
||||||
|
from heremaps.heremapsexceptions import MalformedResult
|
||||||
|
|
||||||
|
class Geocoder:
|
||||||
|
'A Here Maps Geocoder wrapper for python'
|
||||||
|
|
||||||
|
URL_GEOCODE_JSON = 'http://geocoder.api.here.com/6.2/geocode.json'
|
||||||
|
DEFAULT_MAXRESULTS = 1
|
||||||
|
DEFAULT_GEN = 9
|
||||||
|
|
||||||
|
ADDRESS_PARAMS = [
|
||||||
|
'city',
|
||||||
|
'country',
|
||||||
|
'county',
|
||||||
|
'district',
|
||||||
|
'housenumber',
|
||||||
|
'postalcode',
|
||||||
|
'searchtext',
|
||||||
|
'state',
|
||||||
|
'street'
|
||||||
|
]
|
||||||
|
|
||||||
|
ADMITTED_PARAMS = [
|
||||||
|
'additionaldata',
|
||||||
|
'app_id',
|
||||||
|
'app_code',
|
||||||
|
'bbox',
|
||||||
|
'countryfocus',
|
||||||
|
'gen',
|
||||||
|
'jsonattributes',
|
||||||
|
'jsoncallback',
|
||||||
|
'language',
|
||||||
|
'locationattributes',
|
||||||
|
'locationid',
|
||||||
|
'mapview',
|
||||||
|
'maxresults',
|
||||||
|
'pageinformation',
|
||||||
|
'politicalview',
|
||||||
|
'prox',
|
||||||
|
'strictlanguagemode'
|
||||||
|
] + ADDRESS_PARAMS
|
||||||
|
|
||||||
|
app_id = ''
|
||||||
|
app_code = ''
|
||||||
|
maxresults = ''
|
||||||
|
|
||||||
|
def __init__(self, app_id, app_code, maxresults=DEFAULT_MAXRESULTS, gen=DEFAULT_GEN):
|
||||||
|
self.app_id = app_id
|
||||||
|
self.app_code = app_code
|
||||||
|
self.maxresults = maxresults
|
||||||
|
self.gen = gen
|
||||||
|
|
||||||
|
def geocode(self, params):
|
||||||
|
if not set(params.keys()).issubset(set(self.ADDRESS_PARAMS)):
|
||||||
|
raise BadGeocodingParams(params)
|
||||||
|
|
||||||
|
response = self.perform_request(params)
|
||||||
|
|
||||||
|
try:
|
||||||
|
results = response['Response']['View'][0]['Result']
|
||||||
|
except IndexError:
|
||||||
|
raise EmptyGeocoderResponse()
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def perform_request(self, params):
|
||||||
|
request_params = {
|
||||||
|
'app_id' : self.app_id,
|
||||||
|
'app_code' : self.app_code,
|
||||||
|
'maxresults' : self.maxresults,
|
||||||
|
'gen' : self.gen
|
||||||
|
}
|
||||||
|
request_params.update(params)
|
||||||
|
|
||||||
|
encoded_request_params = urllib.urlencode(request_params)
|
||||||
|
|
||||||
|
response = json.load(
|
||||||
|
urllib.urlopen(self.URL_GEOCODE_JSON
|
||||||
|
+ '?'
|
||||||
|
+ encoded_request_params))
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def geocode_address(self, **kwargs):
|
||||||
|
params = {}
|
||||||
|
for key, value in kwargs.iteritems():
|
||||||
|
if value: params[key] = value
|
||||||
|
|
||||||
|
if not params: raise NoGeocodingParams()
|
||||||
|
|
||||||
|
return self.geocode(params)
|
||||||
|
|
||||||
|
def extract_lng_lat_from_result(self, result):
|
||||||
|
try:
|
||||||
|
location = result['Location']
|
||||||
|
except KeyError:
|
||||||
|
raise MalformedResult()
|
||||||
|
|
||||||
|
longitude = location['DisplayPosition']['Longitude']
|
||||||
|
latitude = location['DisplayPosition']['Latitude']
|
||||||
|
|
||||||
|
return [longitude, latitude]
|
0
lib/python/heremaps/tests/__init__.py
Normal file
0
lib/python/heremaps/tests/__init__.py
Normal file
126
lib/python/heremaps/tests/heremapsgeocoder_tests.py
Normal file
126
lib/python/heremaps/tests/heremapsgeocoder_tests.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/local/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from heremaps import heremapsgeocoder
|
||||||
|
from heremaps.heremapsexceptions import BadGeocodingParams
|
||||||
|
from heremaps.heremapsexceptions import EmptyGeocoderResponse
|
||||||
|
from heremaps.heremapsexceptions import NoGeocodingParams
|
||||||
|
from heremaps.heremapsexceptions import MalformedResult
|
||||||
|
|
||||||
|
from secrets import *
|
||||||
|
|
||||||
|
class GeocoderTestCase(unittest.TestCase):
|
||||||
|
EMPTY_RESPONSE = {
|
||||||
|
"Response":{
|
||||||
|
"MetaInfo":{
|
||||||
|
"Timestamp":"2015-11-04T16:31:57.273+0000"
|
||||||
|
},
|
||||||
|
"View":[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GOOD_RESPONSE = {
|
||||||
|
"Response": {
|
||||||
|
"MetaInfo": {
|
||||||
|
"Timestamp":"2015-11-04T16:30:32.187+0000"
|
||||||
|
},
|
||||||
|
"View":[{
|
||||||
|
"_type":"SearchResultsViewType",
|
||||||
|
"ViewId":0,
|
||||||
|
"Result":[{
|
||||||
|
"Relevance":0.89,
|
||||||
|
"MatchLevel":"street",
|
||||||
|
"MatchQuality":{
|
||||||
|
"City":1.0,
|
||||||
|
"Street":[1.0]
|
||||||
|
},
|
||||||
|
"Location":{
|
||||||
|
"LocationId":"NT_yyKB4r3mCWAX4voWgxPcuA",
|
||||||
|
"LocationType":"address",
|
||||||
|
"DisplayPosition":{
|
||||||
|
"Latitude":40.43433,
|
||||||
|
"Longitude":-3.70126
|
||||||
|
},
|
||||||
|
"NavigationPosition":[{
|
||||||
|
"Latitude":40.43433,
|
||||||
|
"Longitude":-3.70126
|
||||||
|
}],
|
||||||
|
"MapView":{
|
||||||
|
"TopLeft":{
|
||||||
|
"Latitude":40.43493,
|
||||||
|
"Longitude":-3.70404
|
||||||
|
},
|
||||||
|
"BottomRight":{
|
||||||
|
"Latitude":40.43373,
|
||||||
|
"Longitude":-3.69873
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Address":{
|
||||||
|
"Label":"Calle de Eloy Gonzalo, Madrid, España",
|
||||||
|
"Country":"ESP",
|
||||||
|
"State":"Comunidad de Madrid",
|
||||||
|
"County":"Madrid",
|
||||||
|
"City":"Madrid",
|
||||||
|
"District":"Trafalgar",
|
||||||
|
"Street":"Calle de Eloy Gonzalo",
|
||||||
|
"AdditionalData":[{
|
||||||
|
"value":"España",
|
||||||
|
"key":"CountryName"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value":"Comunidad de Madrid",
|
||||||
|
"key":"StateName"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value":"Madrid",
|
||||||
|
"key":"CountyName"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.geocoder = heremapsgeocoder.Geocoder(None, None)
|
||||||
|
|
||||||
|
def test_geocode_address_with_valid_params(self):
|
||||||
|
self.geocoder.perform_request = lambda x: self.GOOD_RESPONSE
|
||||||
|
response = self.geocoder.geocode_address(
|
||||||
|
searchtext='Calle Eloy Gonzalo 27',
|
||||||
|
city='Madrid',
|
||||||
|
country='España')
|
||||||
|
|
||||||
|
def test_geocode_address_with_invalid_params(self):
|
||||||
|
with self.assertRaises(BadGeocodingParams):
|
||||||
|
self.geocoder.geocode_address(
|
||||||
|
searchtext='Calle Eloy Gonzalo 27',
|
||||||
|
manolo='escobar')
|
||||||
|
|
||||||
|
def test_geocode_address_with_no_params(self):
|
||||||
|
with self.assertRaises(NoGeocodingParams):
|
||||||
|
self.geocoder.geocode_address()
|
||||||
|
|
||||||
|
def test_geocode_address_empty_response(self):
|
||||||
|
self.geocoder.perform_request = lambda x: self.EMPTY_RESPONSE
|
||||||
|
with self.assertRaises(EmptyGeocoderResponse):
|
||||||
|
self.geocoder.geocode_address(searchtext='lkajfñlasjfñ')
|
||||||
|
|
||||||
|
def test_extract_lng_lat_from_result(self):
|
||||||
|
result = self.GOOD_RESPONSE['Response']['View'][0]['Result'][0]
|
||||||
|
coordinates = self.geocoder.extract_lng_lat_from_result(result)
|
||||||
|
|
||||||
|
self.assertEqual(coordinates[0], -3.70126)
|
||||||
|
self.assertEqual(coordinates[1], 40.43433)
|
||||||
|
|
||||||
|
def test_extract_lng_lat_from_result_with_malformed_result(self):
|
||||||
|
result = {'manolo':'escobar'}
|
||||||
|
|
||||||
|
with self.assertRaises(MalformedResult):
|
||||||
|
self.geocoder.extract_lng_lat_from_result(result)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user