Skip to content

Commit

Permalink
2016-08-08
Browse files Browse the repository at this point in the history
1. Improved sort by distance method.
2. Add new test case for multiple sort_by keywords.
  • Loading branch information
MacHu-GWU committed Aug 8, 2016
1 parent 08b1d2d commit 73c0553
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 83 deletions.
12 changes: 12 additions & 0 deletions source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ You can search zipcode by city name.
'Vienna'
**uszipcode also provide a internal method to help you find correct city name**::

.. code-block: python
>>> search._find_city("phonix", bes_match=True)
['Phoenix']
# Find city in kensas state, state name is also typo tolerant
>>> search._find_city("kersen", state="kensas", best_match=False)
city_expected = ["Nickerson", ]
.. _by_state:

Search by State
Expand Down
116 changes: 74 additions & 42 deletions tests/test_searchengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-

import pytest
from collections import OrderedDict
from uszipcode.searchengine import Zipcode, ZipcodeSearchEngine
from uszipcode.packages.haversine import great_circle

Expand All @@ -11,17 +12,19 @@ def is_all_ascending(array):
"""
for i, j in zip(array[1:], array[:-1]):
if (i is not None) and (j is not None):
assert i - j >= 0
assert i >= j


def is_all_descending(array):
"""Assert that this is a strictly desceding array.
"""
for i, j in zip(array[1:], array[:-1]):
if (i is not None) and (j is not None):
assert i - j <= 0
assert i <= j


class TestZipcode(object):

def test_init(self):
z = Zipcode(Zipcode="10001")
assert z.Zipcode == "10001"
Expand Down Expand Up @@ -69,6 +72,7 @@ def test_output(self):


class TestZipcodeSearchEngine(object):

def test_sql_create_order_by(self):
with ZipcodeSearchEngine() as search:
sql = search._sql_create_order_by("Zipcode", True)
Expand All @@ -94,17 +98,18 @@ def test_sql_create_lower_upper(self):
with pytest.raises(ValueError):
sql = search._sql_create_lower_upper("Population", None, None)
with pytest.raises(ValueError):
sql = search._sql_create_lower_upper("Population", "SQL", "SQL")

sql = search._sql_create_lower_upper(
"Population", "SQL", "SQL")

sql = search._sql_create_lower_upper("Population", 0, None)
assert sql == "Population >= 0"

sql = search._sql_create_lower_upper("Population", None, 999999)
assert sql == "Population <= 999999"

sql = search._sql_create_lower_upper("Population", 0, 999999)
assert sql == "Population >= 0 AND Population <= 999999"

def test_search_by_zipcode(self):
with ZipcodeSearchEngine() as search:
for zipcode in [10001, "10001"]:
Expand All @@ -120,50 +125,59 @@ def test_search_by_coordinate(self):
with ZipcodeSearchEngine() as search:
# 在马里兰选一个坐标, 返回1000条, 但实际上不到1000条
lat, lng = 39.114407, -77.205758

# 返回的结果必须按照距离是从小到大的
res1 = search.by_coordinate(lat, lng, ascending=True, returns=1000)
len(res1) < 1000
dist_array = [great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res1]
dist_array = [
great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res1]
is_all_ascending(dist_array)

res2 = search.by_coordinate(lat, lng, ascending=False, returns=1000)
dist_array = [great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res2]

res2 = search.by_coordinate(
lat, lng, ascending=False, returns=1000)
dist_array = [
great_circle((lat, lng), (z.Latitude, z.Longitude), miles=True) for z in res2]
is_all_descending(dist_array)

# 当returns = 0时, 返回所有符合条件的
res3 = search.by_coordinate(lat, lng, returns=0)
assert len(res1) == len(res3)

# 当没有符合条件的zipcode时, 返回空列表
res3 = search.by_coordinate(lat, lng, radius=-1)
assert len(res3) == 0

def test_find_state(self):
with ZipcodeSearchEngine() as search:
assert search._find_state("mary", best_match=True) == ["MD", ]

result = set(search._find_state("virgin", best_match=False))
assert result == set(["VI", "WV", "VA"])

assert search._find_state("newyork", best_match=False) == ["NY", ]

with pytest.raises(ValueError):
search._find_state("THIS IS NOT A STATE!", best_match=True)

with pytest.raises(ValueError):
search._find_state("THIS IS NOT A STATE!", best_match=False)

def test_find_city(self):
with ZipcodeSearchEngine() as search:
assert search._find_city("phonix", best_match=True) == [
"Phoenix", ]
assert search._find_city("kerson", best_match=False) == [
"Dickerson Run", "Dickerson", "Nickerson", "Emerson", "Everson"
]
assert search._find_city("kersen", state="kensas", best_match=False) == [
"Nickerson", ]

city_result = search._find_city("phonix", best_match=True)
city_expected = ["Phoenix", ]
assert city_result == city_expected

city_result = search._find_city("kerson", best_match=False)
city_result.sort()
city_expected = ["Dickerson", "Dickerson Run", "Emerson", "Ericson", "Everson", "Nickerson"]
for city in city_result:
assert city in city_expected

city_result = search._find_city("kersen", state="kensas", best_match=False)
city_expected = ["Nickerson", ]
assert city_result == city_expected

def test_by_city_and_state(self):
with ZipcodeSearchEngine() as search:
# Arlington, VA
Expand All @@ -172,11 +186,11 @@ def test_by_city_and_state(self):
z.City == "Arlington"
z.State == "VA"
assert len(res) == 5

# There's no city in VI
with pytest.raises(ValueError):
search.by_city_and_state(city="Arlington", state="vi")

def test_by_city(self):
with ZipcodeSearchEngine() as search:
res = search.by_city("vienna")
Expand All @@ -185,7 +199,7 @@ def test_by_city(self):
assert z.City == "Vienna"
s.add(z.State)
assert s == set(["ME", "MD", "VA"])

def test_by_state(self):
with ZipcodeSearchEngine() as search:
res = search.by_state("RI")
Expand All @@ -204,7 +218,7 @@ def test_by_prefix(self):
sort_by=sort_key, ascending=True, returns=0)
l = list()
for z in res:
assert z.Zipcode.startswith(prefix) # example prefix
assert z.Zipcode.startswith(prefix) # example prefix
l.append(z[sort_key])
l_sorted = list(l)
l_sorted.sort()
Expand Down Expand Up @@ -253,16 +267,33 @@ def test_by_house(self):
res = search.by_house(lower=20000,
sort_by="HouseOfUnits", ascending=False, returns=0)
assert len(res) == 741

def test_find(self):

def test_sort_by_multiple_keywords(self):
with ZipcodeSearchEngine() as search:
res = search.by_state(
state="CA", sort_by=["City", "Zipcode"], ascending=[True, True], returns=1000)

stat = OrderedDict()
for zipcode in res:
try:
stat[zipcode.City].append(zipcode.Zipcode)
except:
stat[zipcode.City] = [zipcode.Zipcode, ]

city_list = list(stat.keys())
is_all_ascending(city_list)
for zipcode_list in stat.values():
is_all_ascending(list(zipcode_list))

def test_find(self):
with ZipcodeSearchEngine() as search:
# Find most people living zipcode in New York
res = search.find(
city="new york",
sort_by="Population", ascending=False,
)
is_all_descending([z.Population for z in res])

# Find all zipcode in California that prefix is "999"
res = search.find(
state="califor",
Expand All @@ -275,28 +306,29 @@ def test_find(self):
assert z.State == "CA"
assert z.Zipcode.startswith("95")
is_all_descending([z.HouseOfUnits for z in res])

# Find top 10 richest zipcode near Silicon Valley
lat, lng = 37.391184, -122.082235
radius = 100
res = search.find(
lat=lat,
lat=lat,
lng=lng,
radius=radius,
sort_by="Wealthy", ascending=False,
returns=10,
)
assert len(res) == 10
for z in res:
assert great_circle((lat, lng), (z.Latitude, z.Longitude)) <= radius
assert great_circle(
(lat, lng), (z.Latitude, z.Longitude)) <= radius
is_all_descending([z.Wealthy for z in res])
# Find zipcode that average personal annual income greater than
# 100000 near Silicon Valley, order by distance

# Find zipcode that average personal annual income greater than
# 100000 near Silicon Valley, order by distance
lat, lng = 37.391184, -122.082235
radius = 100
res = search.find(
lat=lat,
lat=lat,
lng=lng,
radius=radius,
wealthy_lower=60000,
Expand All @@ -309,7 +341,7 @@ def test_find(self):
is_all_ascending([
great_circle((lat, lng), (z.Latitude, z.Longitude)) for z in res
])

def test_edge_case(self):
with ZipcodeSearchEngine() as search:
zipcode = search.by_zipcode(00000)
Expand Down
2 changes: 1 addition & 1 deletion uszipcode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
print(e)


__version__ = "0.1.2"
__version__ = "0.1.3"
__short_description__ = ("USA zipcode programmable database, includes "
"up-to-date census and geometry information.")
__license__ = "MIT"
Expand Down
Loading

0 comments on commit 73c0553

Please sign in to comment.