Skip to content

Commit

Permalink
Merge pull request #273 from DenisCarriere/feature_bbox_for_geonames
Browse files Browse the repository at this point in the history
Feature bbox for geonames
  • Loading branch information
DenisCarriere committed Aug 11, 2017
2 parents 6b15b98 + 99fe8bb commit a850780
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 12 deletions.
24 changes: 21 additions & 3 deletions docs/providers/GeoNames.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ They are all supported
Proximity
---------

Note the extra parameters 'east', 'west', 'north', 'south' : they provide the functionnality 'proximity that can be found on some other providers (e.g Mapbox)
Geomanes allows the extra parameters 'east', 'west', 'north', 'south' to restrict the query to the therefore defined box. They provide the functionnality 'proximity' that can be found on some other providers (e.g Mapbox)


.. code-block:: python
Expand All @@ -67,6 +67,22 @@ Note the extra parameters 'east', 'west', 'north', 'south' : they provide the fu
'United States'
For consistency purpose, geocoder also accepts a 'bbox' parameter. Follows an example where google provider is used first, and the resulting bbox is passed to make a query to geonames:


.. code-block:: python
>>> location = 'Ontario, Ottawa'
>>> google_result = geocoder.google(location, key='YOUR KEY')
>>> google_result.address
'Ottawa, ON, Canada'
>>> google_result.bbox
{'northeast': [45.5375801, -75.2465979], 'southwest': [44.962733, -76.35391589999999]}
>>> g = geocoder.geonames(location, key='YOUR USERNAME', bbox=google_result.bbox)
>>> g.address
'Ottawa'
Multiple values for some parameters
-----------------------------------

Expand All @@ -83,8 +99,8 @@ This is also supported by Geocoder, which will expect in these cases an array in
[('Paris', 'France'), ('Paris', 'United States'), ('Paris', 'France'), ('Paris', 'United States'), ('Paris', 'United States')]
Details (inc. timezone)
~~~~~~~~~~~~~~~~~~~~~~~
Details (inc. timezone, bbox)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This method requires a valid *geonames_id*, which you can get with the geocode method. It will fetchs all available information from geonames, including timezone and bbox.

Expand Down Expand Up @@ -145,6 +161,8 @@ This method requires a valid *geonames_id*, which you can get with the geocode m
-5
>>> g.dstOffset
-4
>>> g.bbox
{'northeast': [45.58753415000007, -75.07957784899992], 'southwest': [44.962202955000066, -76.35400795899994]}
Children and Hierarchy
~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
6 changes: 6 additions & 0 deletions geocoder/geonames.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ def _build_params(self, location, provider_key, **kwargs):
'username': provider_key,
'maxRows': kwargs.get('maxRows', 1),
}
# check out for bbox in kwargs
bbox = kwargs.pop('bbox', None)
if bbox is not None:
south, west = bbox['southwest']
north, east = bbox['northeast']
base_kwargs.update({'east': east, 'west': west, 'north': north, 'south': south})

# look out for valid extra kwargs
supported_kwargs = set((
Expand Down
9 changes: 9 additions & 0 deletions geocoder/geonames_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ def dstOffset(self):
if timezone:
return timezone.get('dstOffset')

@property
def bbox(self):
bbox = self.raw.get('bbox', {})
south = bbox.get('south')
west = bbox.get('west')
north = bbox.get('north')
east = bbox.get('east')
return self._get_bbox(south, west, north, east)


class GeonamesDetails(GeonamesQuery):
""" Details:
Expand Down
22 changes: 22 additions & 0 deletions tests/results/geonames_proximity.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"totalResultsCount": 134,
"geonames": [
{
"adminCode1": "08",
"lng": "-75.69812",
"geonameId": 6094817,
"toponymName": "Ottawa",
"countryId": "6251999",
"fcl": "P",
"population": 812129,
"countryCode": "CA",
"name": "Ottawa",
"fclName": "city, village,...",
"countryName": "Canada",
"fcodeName": "capital of a political entity",
"adminName1": "Ontario",
"lat": "45.41117",
"fcode": "PPLC"
}
]
}
45 changes: 36 additions & 9 deletions tests/test_geonames.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# coding: utf8

import logging
import json
import pytest
import geocoder
Expand Down Expand Up @@ -123,6 +123,9 @@ def test_details():
assert g.timeZoneName == "America/Toronto"
assert g.rawOffset == -5
assert g.dstOffset == -4
assert g.bbox == {
'northeast': [45.58753415000007, -75.07957784899992],
'southwest': [44.962202955000066, -76.35400795899994]}


def test_children():
Expand Down Expand Up @@ -165,18 +168,42 @@ def test_hierarchy():
data_file = 'tests/results/geonames_hierarchy.json'
with requests_mock.Mocker() as mocker, open(data_file, 'r') as input:
mocker.get(url, text=input.read())
g = geocoder.geonames(6094817, method='hierarchy', key='mock')
assert g.ok
assert repr(g) == '<[OK] Geonames - Hierarchy #5 results>'
assert len(g) == 5
assert g.status_code == 200
g = geocoder.geonames(6094817, method='hierarchy', key='mock')
assert g.ok
assert repr(g) == '<[OK] Geonames - Hierarchy #5 results>'
assert len(g) == 5
assert g.status_code == 200

expected_names = ["Earth", "North America",
"Canada", "Ontario", "Ottawa"]
assert expected_names == [res.address for res in g]

expected_names = ["Earth", "North America", "Canada", "Ontario", "Ottawa"]
assert expected_names == [res.address for res in g]

def test_geocoding_with_bbox():
# query google first to get a bbox
urls = [
# when testing locally
'https://maps.googleapis.com/maps/api/geocode/json?language=&address=Ottawa,%20Ontario&bounds=&components=&region=&key=mock',
# when building in Travis (secured connection implies ordered parameters)
'https://maps.googleapis.com/maps/api/geocode/json?client=[secure]&latlng=45.4215296%2C+-75.697193&sensor=false&signature=iXbq6odmrYN0XgcfB5EPcgEvR-I%3D'
]
data_file = 'tests/results/google.json'
with requests_mock.Mocker() as mocker, open(data_file, 'r') as input:
for url in urls:
mocker.get(url, text=input.read())
google = geocoder.google(location, client=None, key='mock')
# query geonames with bbox
url = 'http://api.geonames.org/searchJSON?q=Ottawa%2C+Ontario&fuzzy=0.8&username=mock&maxRows=1&east=-75.2465979&west=-76.3539158&north=45.5375801&south=44.962733'
data_file = 'tests/results/geonames_proximity.json'
with requests_mock.Mocker() as mocker, open(data_file, 'r') as input:
mocker.get(url, text=input.read())
g = geocoder.geonames(location, key='mock', bbox=google.bbox)
assert g.ok


def main():
test_geonames_geojson(geonames_response(None))
logging.basicConfig(level=logging.INFO)
test_geocoding_with_bbox()


if __name__ == '__main__':
Expand Down

0 comments on commit a850780

Please sign in to comment.