Skip to content

Commit 89d6423

Browse files
Samuel ScullySamuel Scully
authored andcommitted
Reject out of bounds coordinates
1 parent d54dbf6 commit 89d6423

File tree

3 files changed

+69
-6
lines changed

3 files changed

+69
-6
lines changed

opencage/geocoder.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@ class InvalidInputError(OpenCageGeocodeError):
3030
"""
3131
There was a problem with the input you provided.
3232
33-
:var bad_value: The value that caused the problem
33+
:var message: Error message describing the bad input.
34+
:var bad_value: The value that caused the problem.
3435
"""
3536

36-
def __init__(self, bad_value):
37+
def __init__(self, message, bad_value=None):
3738
super().__init__()
39+
self.message = message
3840
self.bad_value = bad_value
3941

4042
def __unicode__(self):
41-
return "Input must be a unicode string, not "+repr(self.bad_value)[:100]
43+
return self.message
4244

4345
__str__ = __unicode__
4446

@@ -238,7 +240,11 @@ def reverse_geocode(self, lat, lng, **kwargs):
238240
:raises RateLimitExceededError: if you have exceeded the number of queries you can make.
239241
: Exception says when you can try again
240242
:raises UnknownError: if something goes wrong with the OpenCage API
243+
:raises InvalidInputError: if the latitude or longitude is out of bounds
241244
"""
245+
246+
self._validate_lat_lng(lat, lng)
247+
242248
return self.geocode(_query_for_reverse_geocoding(lat, lng), **kwargs)
243249

244250
async def reverse_geocode_async(self, lat, lng, **kwargs):
@@ -253,7 +259,11 @@ async def reverse_geocode_async(self, lat, lng, **kwargs):
253259
:rtype: dict
254260
:raises RateLimitExceededError: if exceeded number of queries you can make. You can try again
255261
:raises UnknownError: if something goes wrong with the OpenCage API
262+
:raises InvalidInputError: if the latitude or longitude is out of bounds
256263
"""
264+
265+
self._validate_lat_lng(lat, lng)
266+
257267
return await self.geocode_async(_query_for_reverse_geocoding(lat, lng), **kwargs)
258268

259269
@backoff.on_exception(
@@ -335,12 +345,33 @@ async def _opencage_async_request(self, params):
335345

336346
def _parse_request(self, query, params):
337347
if not isinstance(query, str):
338-
raise InvalidInputError(bad_value=query)
348+
error_message = "Input must be a unicode string, not " + repr(query)[:100]
349+
raise InvalidInputError(error_message, bad_value=query)
339350

340351
data = { 'q': query, 'key': self.key }
341352
data.update(params) # Add user parameters
342353
return data
343354

355+
def _validate_lat_lng(self, lat, lng):
356+
"""
357+
Validate latitude and longitude values.
358+
359+
Raises InvalidInputError if the values are out of bounds.
360+
"""
361+
try:
362+
lat_float = float(lat)
363+
if not -90 <= lat_float <= 90:
364+
raise InvalidInputError(f"Latitude must be a number between -90 and 90, not {lat}", bad_value=lat)
365+
except ValueError:
366+
raise InvalidInputError(f"Latitude must be a number between -90 and 90, not {lat}", bad_value=lat)
367+
368+
try:
369+
lng_float = float(lng)
370+
if not -180 <= lng_float <= 180:
371+
raise InvalidInputError(f"Longitude must be a number between -180 and 180, not {lng}", bad_value=lng)
372+
except ValueError:
373+
raise InvalidInputError(f"Longitude must be a number between -180 and 180, not {lng}", bad_value=lng)
374+
344375

345376
def _query_for_reverse_geocoding(lat, lng):
346377
"""

test/cli/test_cli_run.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def test_input_errors(capfd):
9090

9191
_, err = capfd.readouterr()
9292
# assert err == ''
93-
assert err.count("\n") == 6
93+
assert err.count("\n") == 7
9494
assert "Line 1 - Missing input column 2 in ['50.101010']" in err
9595
assert "Line 1 - Expected two comma-separated values for reverse geocoding, got ['50.101010']" in err
9696
assert "Line 3 - Empty line" in err
@@ -103,7 +103,7 @@ def test_input_errors(capfd):
103103
length=4,
104104
lines=[
105105
'50.101010,,',
106-
'-100,60.1,de,48153',
106+
'-100,60.1,,',
107107
',,',
108108
'a,b,,'
109109
]

test/test_error_invalid_input.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,35 @@ def test_must_be_unicode_string():
3333
geocoder.geocode(latin1_string)
3434
assert str(excinfo.value) == f"Input must be a unicode string, not {latin1_string!r}"
3535
assert excinfo.value.bad_value == latin1_string
36+
37+
@responses.activate
38+
def test_reject_out_of_bounds_coordinates():
39+
"""Test that reverse geocoding rejects out-of-bounds latitude and longitude values."""
40+
responses.add(
41+
responses.GET,
42+
geocoder.url,
43+
body='{"results":{}}',
44+
status=200
45+
)
46+
47+
# Valid coordinates should work
48+
geocoder.reverse_geocode(45.0, 90.0)
49+
geocoder.reverse_geocode(-45.0, -90.0)
50+
51+
# Invalid latitude values (outside -90 to 90)
52+
with pytest.raises(InvalidInputError) as excinfo:
53+
geocoder.reverse_geocode(91.0, 45.0)
54+
assert "Latitude must be a number between -90 and 90" in str(excinfo.value)
55+
56+
with pytest.raises(InvalidInputError) as excinfo:
57+
geocoder.reverse_geocode(-91.0, 45.0)
58+
assert "Latitude must be a number between -90 and 90" in str(excinfo.value)
59+
60+
# Invalid longitude values (outside -180 to 180)
61+
with pytest.raises(InvalidInputError) as excinfo:
62+
geocoder.reverse_geocode(45.0, 181.0)
63+
assert "Longitude must be a number between -180 and 180" in str(excinfo.value)
64+
65+
with pytest.raises(InvalidInputError) as excinfo:
66+
geocoder.reverse_geocode(45.0, -181.0)
67+
assert "Longitude must be a number between -180 and 180" in str(excinfo.value)

0 commit comments

Comments
 (0)