Skip to content

Commit bc3140c

Browse files
authored
Merge pull request #18 from what3words/update-readme
update tests with locale and handle the quota error
2 parents 25d6cb4 + b7c8e48 commit bc3140c

File tree

5 files changed

+119
-37
lines changed

5 files changed

+119
-37
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,4 @@ pyvenv.cfg
235235
pip-selfcheck.json
236236

237237
# End of https://www.toptal.com/developers/gitignore/api/python,macos,venv,git
238+
.vscode/*

README.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -88,33 +88,33 @@ Retrieves a list of the currently loaded and available 3 word address languages.
8888
The returned payload from the `available-languages` method is described in the [what3words REST API documentation](https://docs.what3words.com/api/v3/#available-languages).
8989

9090

91-
## isPossible3wa
91+
## is_possible_3wa
9292
This method takes a string as a parameter and returns whether the string is in the format of a 3WA (eg “filled.count.soap”). Return type is boolean. NOTE: Does not check if it is an actual existing 3WA.
9393

9494
```
95-
isPossible3wa(“filled.count.soap”) returns True
96-
isPossible3wa(“not a 3wa”) returns False
97-
isPossible3wa(“not.3wa address”) returns False
95+
is_possible_3wa(“filled.count.soap”) returns True
96+
is_possible_3wa(“not a 3wa”) returns False
97+
is_possible_3wa(“not.3wa address”) returns False
9898
```
9999

100-
## findPossible3wa
100+
## find_possible_3wa
101101

102102
This method takes a string as a parameter and searches the string for any possible instances of a 3WA - e.g. "leave in my porch at word.word.word." Likely to be the main method that is called on the delivery notes. Returns an array of matched items. Returns an empty array if no matches are found. NOTE: Does not check if it is an actual existing 3WA.
103103

104104
```
105-
findPossible3wa(“Please leave by my porch at filled.count.soap”) will return [‘filled.count.soap’]
106-
findPossible3wa(“Please leave by my porch at filled.count.soap or deed.tulip.judge”) will return [‘filled.count.soap’, ‘deed.tulip.judge’]
107-
findPossible3wa(“Please leave by my porch at”) will return []
105+
find_possible_3wa(“Please leave by my porch at filled.count.soap”) will return [‘filled.count.soap’]
106+
find_possible_3wa(“Please leave by my porch at filled.count.soap or deed.tulip.judge”) will return [‘filled.count.soap’, ‘deed.tulip.judge’]
107+
find_possible_3wa(“Please leave by my porch at”) will return []
108108
```
109109

110-
## isValid3wa
110+
## is_valid_3wa
111111

112-
This method takes a string as a parameter and first passes it through the W3W regex filter (akin to calling isPossible3wa() on the string) and then calls the W3W api to verify it is a real 3WA.
112+
This method takes a string as a parameter and first passes it through the W3W regex filter (akin to calling is_possible_3wa() on the string) and then calls the W3W api to verify it is a real 3WA.
113113

114114
```
115-
isValid3wa(“filled.count.soap”) returns True
116-
isValid3wa(“filled.count.”) returns False
117-
isValid3wa(“python.is.cool”) returns False
115+
is_valid_3wa(“filled.count.soap”) returns True
116+
is_valid_3wa(“filled.count.”) returns False
117+
is_valid_3wa(“python.is.cool”) returns False
118118
```
119119

120120
## Code examples
@@ -160,7 +160,7 @@ Anyone and everyone is welcome to contribute.
160160

161161

162162
# Revision History
163-
163+
* `v3.4.0` 28/11/24 - Support locale for the autosuggest and update the readme file
164164
* `v3.3.0` 30/09/24 - Support locale, update regex, format and tests
165165
* `v3.2.0` 08/03/22 - Added regex functions
166166
* `v3.1.1` 04/10/19 - Fix bugs related to setting default language value, and autosuggest input-type

tests/test_w3w.py

+76-16
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ def test_convert_to_coordinates(self):
3636

3737
def test_locale_with_convert_to_coordinates(self):
3838
# Test conversion to coordinates with a valid 3-word address and locale
39-
result = self.geocoder.convert_to_coordinates(addr)
39+
result = self.geocoder.convert_to_coordinates("напомена.илузија.дирљив")
40+
print(result)
4041
if "error" in result:
4142
print(f"API error code: {result['error']['code']}")
4243
# Handle the Quota Exceeded error specifically for this function
@@ -47,7 +48,7 @@ def test_locale_with_convert_to_coordinates(self):
4748
)
4849
else:
4950
self.assertEqual(result["language"], "oo")
50-
self.assertEqual(result["locale"], "oo_la")
51+
self.assertEqual(result["locale"], "oo_cy")
5152
self.assertEqual(result["coordinates"]["lat"], lat)
5253
self.assertEqual(result["coordinates"]["lng"], lng)
5354

@@ -77,6 +78,35 @@ def test_locale_with_convert_to_3wa(self):
7778
self.assertEqual(result["coordinates"]["lat"], lat)
7879
self.assertEqual(result["coordinates"]["lng"], lng)
7980

81+
def test_locale_with_autosuggest(self):
82+
# Test autosuggest with a valid partial 3-word address and a specific locale
83+
partial_address = "напомена.илузија.дирљи"
84+
locale = "oo_cy"
85+
86+
result = self.geocoder.autosuggest(partial_address, locale=locale, language=locale)
87+
print(result)
88+
89+
if "error" in result:
90+
print(f"API error code: {result['error']['code']}")
91+
# Handle the Quota Exceeded error specifically for this function
92+
self.assertEqual(
93+
result["error"]["code"],
94+
"QuotaExceeded",
95+
"Expected QuotaExceeded error for Autosuggest with locale",
96+
)
97+
else:
98+
# Validate the locale and language in the response
99+
self.assertIn("suggestions", result, "Expected 'suggestions' in the response")
100+
self.assertGreater(len(result["suggestions"]), 0, "Expected at least one suggestion")
101+
102+
# Check the language and locale of the first suggestion
103+
first_suggestion = result["suggestions"][0]
104+
self.assertEqual(first_suggestion["language"], "oo", "Language does not match the expected locale")
105+
self.assertTrue(
106+
first_suggestion["words"].startswith(partial_address),
107+
"First suggestion does not match the input partial address"
108+
)
109+
80110
def test_available_languages(self):
81111
# Test available languages
82112
result = self.geocoder.available_languages()
@@ -132,36 +162,64 @@ def test_autosuggest(self):
132162
)
133163

134164
def test_grid_section(self):
135-
# Test grid section functionality with a bounding box
136165
sw = Coordinates(52.208867, 0.117540)
137166
ne = Coordinates(52.207988, 0.116126)
138167
bb = BoundingBox(sw, ne)
139-
140168
result = self.geocoder.grid_section(bb)
141-
self.assertIsNotNone(result["lines"])
169+
print(result) # Debugging output
142170

143-
def test_invalid_address(self):
144-
# Test invalid address
145-
invalid_addr = "invalid.address.test"
146-
result = self.geocoder.convert_to_coordinates(invalid_addr)
147171
if "error" in result:
148-
print(f"API error code: {result['error']['code']}")
149-
# Handle the Quota Exceeded error specifically for this function
150172
self.assertEqual(
151173
result["error"]["code"],
152174
"QuotaExceeded",
153-
"Expected QuotaExceeded error for Convert to 3wa",
175+
"Expected QuotaExceeded error due to plan limitations or exceeded quota.",
154176
)
155177
else:
156-
self.assertEqual(result["error"]["code"], "BadWords")
178+
self.assertIn("lines", result, "Expected 'lines' in the response")
179+
self.assertIsNotNone(result["lines"])
180+
181+
def test_invalid_address(self):
182+
invalid_addr = "invalid.address"
183+
result = self.geocoder.convert_to_coordinates(invalid_addr)
184+
print(result) # Debugging output
185+
186+
if "error" in result:
187+
if result["error"]["code"] == "QuotaExceeded":
188+
self.assertEqual(
189+
result["error"]["code"],
190+
"QuotaExceeded",
191+
"Expected QuotaExceeded error due to exceeded quota or restricted API key.",
192+
)
193+
else:
194+
self.assertEqual(
195+
result["error"]["code"],
196+
"BadWords",
197+
"Expected BadWords error for invalid address.",
198+
)
199+
else:
200+
self.fail("Expected an error in the response, but none was returned.")
157201

158202
def test_invalid_coordinates(self):
159-
# Test invalid coordinates to 3-word address conversion
160203
invalid_lat = 100.0
161204
invalid_lng = 200.0
162205
result = self.geocoder.convert_to_3wa(Coordinates(invalid_lat, invalid_lng))
163-
self.assertIn("error", result)
164-
self.assertEqual(result["error"]["code"], "BadCoordinates")
206+
print(result) # Debugging output
207+
208+
if "error" in result:
209+
if result["error"]["code"] == "QuotaExceeded":
210+
self.assertEqual(
211+
result["error"]["code"],
212+
"QuotaExceeded",
213+
"Expected QuotaExceeded error due to plan limitations or exceeded quota.",
214+
)
215+
else:
216+
self.assertEqual(
217+
result["error"]["code"],
218+
"BadCoordinates",
219+
"Expected BadCoordinates error for invalid coordinates.",
220+
)
221+
else:
222+
self.fail("Expected an error in the response but got none.")
165223

166224
def test_partial_autosuggest(self):
167225
# Test partial autosuggest functionality
@@ -211,5 +269,7 @@ def test_did_you_mean(self):
211269
self.assertFalse(self.geocoder.did_you_mean(invalid_input))
212270

213271

272+
273+
214274
if __name__ == "__main__":
215275
unittest.main()

what3words/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.3.0"
1+
__version__ = "3.4.0"

what3words/what3words.py

+27-6
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ def convert_to_coordinates(
3838
Convert a 3 word address into coordinates.
3939
:param words: A 3 word address as a string
4040
:param format: Return data format type; can be 'json' (default) or 'geojson'
41+
:param locale: A supported locale as an ISO 639-1 2 letter code
4142
:return: Response as a dictionary
4243
"""
4344
params = {"words": words, "format": format, "locale": locale}
4445
if locale:
4546
params["locale"] = locale
46-
return self._request("/convert-to-coordinates", params)
47+
response = self._request("/convert-to-coordinates", params)
48+
if "error" in response:
49+
return {"error": response["error"]}
50+
return response
4751

4852
def convert_to_3wa(
4953
self,
@@ -57,6 +61,7 @@ def convert_to_3wa(
5761
:param coordinates: Coordinates object
5862
:param format: Return data format type; can be 'json' (default) or 'geojson'
5963
:param language: A supported 3 word address language as an ISO 639-1 2 letter code. Defaults to self.language
64+
:param locale: A supported locale as an ISO 639-1 2 letter code
6065
:return: Response as a dictionary
6166
"""
6267
params = {
@@ -67,7 +72,11 @@ def convert_to_3wa(
6772
}
6873
if locale:
6974
params["locale"] = locale
70-
return self._request("/convert-to-3wa", params)
75+
76+
response = self._request("/convert-to-3wa", params)
77+
if "error" in response:
78+
return {"error": response["error"]}
79+
return response
7180

7281
def grid_section(self, bounding_box: "BoundingBox", format: str = "json") -> Dict:
7382
"""
@@ -80,14 +89,20 @@ def grid_section(self, bounding_box: "BoundingBox", format: str = "json") -> Dic
8089
"bounding-box": f"{bounding_box.sw.lat},{bounding_box.sw.lng},{bounding_box.ne.lat},{bounding_box.ne.lng}",
8190
"format": format,
8291
}
83-
return self._request("/grid-section", params)
92+
response = self._request("/grid-section", params)
93+
if "error" in response:
94+
return {"error": response["error"]}
95+
return response
8496

8597
def available_languages(self) -> Dict:
8698
"""
8799
Retrieve a list of available 3 word languages.
88100
:return: Response as a dictionary
89101
"""
90-
return self._request("/available-languages")
102+
response = self._request("/available-languages")
103+
if "error" in response:
104+
return {"error": response["error"]}
105+
return response
91106

92107
def autosuggest(
93108
self,
@@ -102,6 +117,7 @@ def autosuggest(
102117
input_type: Optional[str] = None,
103118
language: Optional[str] = None,
104119
prefer_land: Optional[bool] = None,
120+
locale: Optional[str] = None,
105121
) -> Dict:
106122
"""
107123
Returns a list of 3 word addresses based on user input and other parameters.
@@ -116,6 +132,7 @@ def autosuggest(
116132
:param input_type: Specify voice input mode
117133
:param language: A supported 3 word address language as an ISO 639-1 2 letter code
118134
:param prefer_land: Makes autosuggest prefer results on land to those in the sea
135+
:param locale: A supported locale as an ISO 639-1 2 letter code
119136
:return: Response as a dictionary
120137
"""
121138
params = {"input": input, "language": language or self.language}
@@ -143,8 +160,12 @@ def autosuggest(
143160
params["input-type"] = input_type
144161
if prefer_land is not None:
145162
params["prefer-land"] = str(prefer_land).lower()
146-
147-
return self._request("/autosuggest", params)
163+
if locale:
164+
params["locale"] = locale
165+
response = self._request("/autosuggest", params)
166+
if "error" in response:
167+
return {"error": response["error"]}
168+
return response
148169

149170
def default_language(self, lang: Optional[str] = None) -> str:
150171
"""

0 commit comments

Comments
 (0)