Skip to content

Commit 73c0553

Browse files
committed
2016-08-08
1. Improved sort by distance method. 2. Add new test case for multiple sort_by keywords.
1 parent 08b1d2d commit 73c0553

File tree

4 files changed

+133
-83
lines changed

4 files changed

+133
-83
lines changed

source/index.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ You can search zipcode by city name.
143143
'Vienna'
144144
145145
146+
**uszipcode also provide a internal method to help you find correct city name**::
147+
148+
.. code-block: python
149+
150+
>>> search._find_city("phonix", bes_match=True)
151+
['Phoenix']
152+
153+
# Find city in kensas state, state name is also typo tolerant
154+
>>> search._find_city("kersen", state="kensas", best_match=False)
155+
city_expected = ["Nickerson", ]
156+
157+
146158
.. _by_state:
147159

148160
Search by State

tests/test_searchengine.py

Lines changed: 74 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33

44
import pytest
5+
from collections import OrderedDict
56
from uszipcode.searchengine import Zipcode, ZipcodeSearchEngine
67
from uszipcode.packages.haversine import great_circle
78

@@ -11,17 +12,19 @@ def is_all_ascending(array):
1112
"""
1213
for i, j in zip(array[1:], array[:-1]):
1314
if (i is not None) and (j is not None):
14-
assert i - j >= 0
15+
assert i >= j
16+
1517

1618
def is_all_descending(array):
1719
"""Assert that this is a strictly desceding array.
1820
"""
1921
for i, j in zip(array[1:], array[:-1]):
2022
if (i is not None) and (j is not None):
21-
assert i - j <= 0
23+
assert i <= j
2224

2325

2426
class TestZipcode(object):
27+
2528
def test_init(self):
2629
z = Zipcode(Zipcode="10001")
2730
assert z.Zipcode == "10001"
@@ -69,6 +72,7 @@ def test_output(self):
6972

7073

7174
class TestZipcodeSearchEngine(object):
75+
7276
def test_sql_create_order_by(self):
7377
with ZipcodeSearchEngine() as search:
7478
sql = search._sql_create_order_by("Zipcode", True)
@@ -94,17 +98,18 @@ def test_sql_create_lower_upper(self):
9498
with pytest.raises(ValueError):
9599
sql = search._sql_create_lower_upper("Population", None, None)
96100
with pytest.raises(ValueError):
97-
sql = search._sql_create_lower_upper("Population", "SQL", "SQL")
98-
101+
sql = search._sql_create_lower_upper(
102+
"Population", "SQL", "SQL")
103+
99104
sql = search._sql_create_lower_upper("Population", 0, None)
100105
assert sql == "Population >= 0"
101-
106+
102107
sql = search._sql_create_lower_upper("Population", None, 999999)
103108
assert sql == "Population <= 999999"
104-
109+
105110
sql = search._sql_create_lower_upper("Population", 0, 999999)
106111
assert sql == "Population >= 0 AND Population <= 999999"
107-
112+
108113
def test_search_by_zipcode(self):
109114
with ZipcodeSearchEngine() as search:
110115
for zipcode in [10001, "10001"]:
@@ -120,50 +125,59 @@ def test_search_by_coordinate(self):
120125
with ZipcodeSearchEngine() as search:
121126
# 在马里兰选一个坐标, 返回1000条, 但实际上不到1000条
122127
lat, lng = 39.114407, -77.205758
123-
128+
124129
# 返回的结果必须按照距离是从小到大的
125130
res1 = search.by_coordinate(lat, lng, ascending=True, returns=1000)
126131
len(res1) < 1000
127-
dist_array = [great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res1]
132+
dist_array = [
133+
great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res1]
128134
is_all_ascending(dist_array)
129-
130-
res2 = search.by_coordinate(lat, lng, ascending=False, returns=1000)
131-
dist_array = [great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res2]
135+
136+
res2 = search.by_coordinate(
137+
lat, lng, ascending=False, returns=1000)
138+
dist_array = [
139+
great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res2]
132140
is_all_descending(dist_array)
133-
141+
134142
# 当returns = 0时, 返回所有符合条件的
135143
res3 = search.by_coordinate(lat, lng, returns=0)
136144
assert len(res1) == len(res3)
137145

138146
# 当没有符合条件的zipcode时, 返回空列表
139147
res3 = search.by_coordinate(lat, lng, radius=-1)
140148
assert len(res3) == 0
141-
149+
142150
def test_find_state(self):
143151
with ZipcodeSearchEngine() as search:
144152
assert search._find_state("mary", best_match=True) == ["MD", ]
145-
153+
146154
result = set(search._find_state("virgin", best_match=False))
147155
assert result == set(["VI", "WV", "VA"])
148-
156+
149157
assert search._find_state("newyork", best_match=False) == ["NY", ]
150-
158+
151159
with pytest.raises(ValueError):
152160
search._find_state("THIS IS NOT A STATE!", best_match=True)
153-
161+
154162
with pytest.raises(ValueError):
155163
search._find_state("THIS IS NOT A STATE!", best_match=False)
156-
164+
157165
def test_find_city(self):
158166
with ZipcodeSearchEngine() as search:
159-
assert search._find_city("phonix", best_match=True) == [
160-
"Phoenix", ]
161-
assert search._find_city("kerson", best_match=False) == [
162-
"Dickerson Run", "Dickerson", "Nickerson", "Emerson", "Everson"
163-
]
164-
assert search._find_city("kersen", state="kensas", best_match=False) == [
165-
"Nickerson", ]
166-
167+
city_result = search._find_city("phonix", best_match=True)
168+
city_expected = ["Phoenix", ]
169+
assert city_result == city_expected
170+
171+
city_result = search._find_city("kerson", best_match=False)
172+
city_result.sort()
173+
city_expected = ["Dickerson", "Dickerson Run", "Emerson", "Ericson", "Everson", "Nickerson"]
174+
for city in city_result:
175+
assert city in city_expected
176+
177+
city_result = search._find_city("kersen", state="kensas", best_match=False)
178+
city_expected = ["Nickerson", ]
179+
assert city_result == city_expected
180+
167181
def test_by_city_and_state(self):
168182
with ZipcodeSearchEngine() as search:
169183
# Arlington, VA
@@ -172,11 +186,11 @@ def test_by_city_and_state(self):
172186
z.City == "Arlington"
173187
z.State == "VA"
174188
assert len(res) == 5
175-
189+
176190
# There's no city in VI
177191
with pytest.raises(ValueError):
178192
search.by_city_and_state(city="Arlington", state="vi")
179-
193+
180194
def test_by_city(self):
181195
with ZipcodeSearchEngine() as search:
182196
res = search.by_city("vienna")
@@ -185,7 +199,7 @@ def test_by_city(self):
185199
assert z.City == "Vienna"
186200
s.add(z.State)
187201
assert s == set(["ME", "MD", "VA"])
188-
202+
189203
def test_by_state(self):
190204
with ZipcodeSearchEngine() as search:
191205
res = search.by_state("RI")
@@ -204,7 +218,7 @@ def test_by_prefix(self):
204218
sort_by=sort_key, ascending=True, returns=0)
205219
l = list()
206220
for z in res:
207-
assert z.Zipcode.startswith(prefix) # example prefix
221+
assert z.Zipcode.startswith(prefix) # example prefix
208222
l.append(z[sort_key])
209223
l_sorted = list(l)
210224
l_sorted.sort()
@@ -253,16 +267,33 @@ def test_by_house(self):
253267
res = search.by_house(lower=20000,
254268
sort_by="HouseOfUnits", ascending=False, returns=0)
255269
assert len(res) == 741
256-
257-
def test_find(self):
270+
271+
def test_sort_by_multiple_keywords(self):
272+
with ZipcodeSearchEngine() as search:
273+
res = search.by_state(
274+
state="CA", sort_by=["City", "Zipcode"], ascending=[True, True], returns=1000)
275+
276+
stat = OrderedDict()
277+
for zipcode in res:
278+
try:
279+
stat[zipcode.City].append(zipcode.Zipcode)
280+
except:
281+
stat[zipcode.City] = [zipcode.Zipcode, ]
282+
283+
city_list = list(stat.keys())
284+
is_all_ascending(city_list)
285+
for zipcode_list in stat.values():
286+
is_all_ascending(list(zipcode_list))
287+
288+
def test_find(self):
258289
with ZipcodeSearchEngine() as search:
259290
# Find most people living zipcode in New York
260291
res = search.find(
261292
city="new york",
262293
sort_by="Population", ascending=False,
263294
)
264295
is_all_descending([z.Population for z in res])
265-
296+
266297
# Find all zipcode in California that prefix is "999"
267298
res = search.find(
268299
state="califor",
@@ -275,28 +306,29 @@ def test_find(self):
275306
assert z.State == "CA"
276307
assert z.Zipcode.startswith("95")
277308
is_all_descending([z.HouseOfUnits for z in res])
278-
309+
279310
# Find top 10 richest zipcode near Silicon Valley
280311
lat, lng = 37.391184, -122.082235
281312
radius = 100
282313
res = search.find(
283-
lat=lat,
314+
lat=lat,
284315
lng=lng,
285316
radius=radius,
286317
sort_by="Wealthy", ascending=False,
287318
returns=10,
288319
)
289320
assert len(res) == 10
290321
for z in res:
291-
assert great_circle((lat, lng), (z.Latitude, z.Longitude)) <= radius
322+
assert great_circle(
323+
(lat, lng), (z.Latitude, z.Longitude)) <= radius
292324
is_all_descending([z.Wealthy for z in res])
293-
294-
# Find zipcode that average personal annual income greater than
295-
# 100000 near Silicon Valley, order by distance
325+
326+
# Find zipcode that average personal annual income greater than
327+
# 100000 near Silicon Valley, order by distance
296328
lat, lng = 37.391184, -122.082235
297329
radius = 100
298330
res = search.find(
299-
lat=lat,
331+
lat=lat,
300332
lng=lng,
301333
radius=radius,
302334
wealthy_lower=60000,
@@ -309,7 +341,7 @@ def test_find(self):
309341
is_all_ascending([
310342
great_circle((lat, lng), (z.Latitude, z.Longitude)) for z in res
311343
])
312-
344+
313345
def test_edge_case(self):
314346
with ZipcodeSearchEngine() as search:
315347
zipcode = search.by_zipcode(00000)

uszipcode/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
print(e)
99

1010

11-
__version__ = "0.1.2"
11+
__version__ = "0.1.3"
1212
__short_description__ = ("USA zipcode programmable database, includes "
1313
"up-to-date census and geometry information.")
1414
__license__ = "MIT"

0 commit comments

Comments
 (0)