Skip to content

Commit 1be9af5

Browse files
authored
Merge pull request #188 from Turreted/master
Make Population a Property of Location Object
2 parents 6255e1e + 6d664f5 commit 1be9af5

File tree

7 files changed

+91
-39
lines changed

7 files changed

+91
-39
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,7 @@ coverage.xml
6363
docs/_build/
6464

6565
# PyBuilder
66-
target/
66+
target/
67+
68+
# OSX Stuff
69+
.DS_Store

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ __Sample response__
128128
"id": 39,
129129
"country": "Norway",
130130
"country_code": "NO",
131+
"country_population": 5009150,
131132
"province": "",
132133
"county": "",
133134
"last_updated": "2020-03-21T06:59:11.315422Z",
@@ -173,6 +174,7 @@ __Sample response__
173174
"id": 0,
174175
"country": "Thailand",
175176
"country_code": "TH",
177+
"country_population": 67089500,
176178
"province": "",
177179
"county": "",
178180
"last_updated": "2020-03-21T06:59:11.315422Z",
@@ -251,6 +253,7 @@ __Sample Response__
251253
"id": 16,
252254
"country": "Italy",
253255
"country_code": "IT",
256+
"country_population": 60340328,
254257
"province": "",
255258
"county": "",
256259
"last_updated": "2020-03-23T13:32:23.913872Z",
@@ -290,6 +293,7 @@ __Sample Response__
290293
"id": 0,
291294
"country": "US",
292295
"country_code": "US",
296+
"country_population": 310232863,
293297
"province": "New York",
294298
"state": "New York",
295299
"county": "New York",
@@ -308,6 +312,7 @@ __Sample Response__
308312
"id": 1,
309313
"country": "US",
310314
"country_code": "US",
315+
"country_population": 310232863,
311316
"province": "New York",
312317
"state": "New York",
313318
"county": "Westchester",

app/location/__init__.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from ..coordinates import Coordinates
22
from ..utils import countrycodes
3+
from ..utils.populations import country_population
34

45
class Location:
56
"""
@@ -25,9 +26,22 @@ def __init__(self, id, country, province, coordinates, last_updated, confirmed,
2526
def country_code(self):
2627
"""
2728
Gets the alpha-2 code represention of the country. Returns 'XX' if none is found.
29+
30+
:returns: The country code.
31+
:rtype: str
2832
"""
2933
return (countrycodes.country_code(self.country) or countrycodes.default_code).upper()
3034

35+
@property
36+
def country_population(self):
37+
"""
38+
Gets the population of this location.
39+
40+
:returns: The population.
41+
:rtype: int
42+
"""
43+
return country_population(self.country_code)
44+
3145
def serialize(self):
3246
"""
3347
Serializes the location into a dict.
@@ -37,10 +51,11 @@ def serialize(self):
3751
"""
3852
return {
3953
# General info.
40-
'id' : self.id,
41-
'country' : self.country,
42-
'country_code': self.country_code,
43-
'province' : self.province,
54+
'id' : self.id,
55+
'country' : self.country,
56+
'country_code' : self.country_code,
57+
'country_population': self.country_population,
58+
'province' : self.province,
4459

4560
# Coordinates.
4661
'coordinates': self.coordinates.serialize(),
@@ -93,4 +108,4 @@ def serialize(self, timelines = False):
93108
}})
94109

95110
# Return the serialized location.
96-
return serialized
111+
return serialized

app/models/location.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Location(BaseModel):
1010
id: int
1111
country: str
1212
country_code: str
13+
country_population: int = None
1314
county: str = ''
1415
province: str = ''
1516
last_updated: str # TODO use datetime.datetime type.

app/utils/countrycodes.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from itertools import chain
2+
13
# Default country code.
24
default_code = "XX"
35

@@ -364,12 +366,14 @@ def country_code(country):
364366
Return two letter country code (Alpha-2) according to https://en.wikipedia.org/wiki/ISO_3166-1
365367
Defaults to "XX".
366368
"""
369+
# Look in synonyms if not found.
370+
if not country in is_3166_1 and country in synonyms:
371+
country = synonyms[country]
372+
373+
# Return code if country was found.
367374
if country in is_3166_1:
368375
return is_3166_1[country]
369-
else:
370-
if country in synonyms:
371-
synonym = synonyms[country]
372-
return is_3166_1[synonym]
373-
else:
374-
print ("No country_code found for '" + country + "'. Using '" + default_code + "'")
375-
return default_code
376+
377+
# Default to default_code.
378+
print ("No country_code found for '" + country + "'. Using '" + default_code + "'")
379+
return default_code

app/utils/populations.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import requests
2+
from io import StringIO, BytesIO
3+
from cachetools import cached, TTLCache
4+
from zipfile import ZipFile, ZipInfo
5+
from .countrycodes import country_code
6+
7+
# Fetching of the populations.
8+
def fetch_populations():
9+
"""
10+
Returns a dictionary containing the population of each country fetched from the GeoNames (https://www.geonames.org/).
11+
12+
:returns: The mapping of populations.
13+
:rtype: dict
14+
"""
15+
print ("Fetching populations...")
16+
17+
# Mapping of populations
18+
mappings = {}
19+
20+
# Fetch the countries.
21+
countries = requests.get("http://api.geonames.org/countryInfoJSON?username=dperic").json()['geonames']
22+
23+
# Go through all the countries and perform the mapping.
24+
for country in countries:
25+
mappings.update({ country["countryCode"]: int(country["population"]) or None })
26+
27+
# Finally, return the mappings.
28+
return mappings
29+
30+
# Mapping of alpha-2 codes country codes to population.
31+
populations = fetch_populations()
32+
33+
# Retrieving.
34+
def country_population(country_code, default=None):
35+
"""
36+
Fetches the population of the country with the provided country code.
37+
38+
:returns: The population.
39+
:rtype: int
40+
"""
41+
return populations.get(country_code, default)
42+
43+

tests/test_location.py

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@ def __init__(self, latest):
1010

1111
return TestTimeline(args[0])
1212

13-
@pytest.mark.parametrize("test_id, country, country_code, province, latitude, longitude, confirmed_latest, deaths_latest, recovered_latest", [
14-
(0, "Thailand", "TH", "", 15, 100, 1000, 1111, 22222),
15-
(1, "Deutschland", "DE", "", 15, 100, 1000, 1111, 22222),
16-
(2, "Cruise Ship", "XX", "", 15, 100, 1000, 1111, 22222)
13+
@pytest.mark.parametrize("test_id, country, country_code, country_population, province, latitude, longitude, confirmed_latest, deaths_latest, recovered_latest", [
14+
(0, "Thailand", "TH", 1000, "", 15, 100, 1000, 1111, 22222),
15+
(1, "Deutschland", "DE", 1000, "", 15, 100, 1000, 1111, 22222),
16+
(2, "Cruise Ship", "XX", 1000, "", 15, 100, 1000, 1111, 22222)
1717
])
1818
@mock.patch('app.timeline.Timeline', side_effect=mocked_timeline)
19-
def test_location_class(mocked_timeline, test_id, country, country_code, province, latitude, longitude, confirmed_latest, deaths_latest, recovered_latest):
19+
def test_location_class(mocked_timeline, test_id, country, country_code, country_population, province, latitude, longitude, confirmed_latest, deaths_latest, recovered_latest):
2020

2121
# id, country, province, coordinates, confirmed, deaths, recovered
2222
coords = coordinates.Coordinates(latitude=latitude, longitude=longitude)
2323

2424
# Timelines
2525
confirmed = timeline.Timeline(confirmed_latest)
26-
deaths = timeline.Timeline(deaths_latest)
26+
deaths = timeline.Timeline(deaths_latest)
2727
recovered = timeline.Timeline(recovered_latest)
2828

2929
# Date now.
@@ -37,23 +37,4 @@ def test_location_class(mocked_timeline, test_id, country, country_code, provinc
3737
})
3838

3939
assert location_obj.country_code == country_code
40-
41-
#validate serialize
42-
check_dict = {
43-
'id': test_id,
44-
'country': country,
45-
'country_code': country_code,
46-
'province': province,
47-
'last_updated': now,
48-
'coordinates': {
49-
'latitude': latitude,
50-
'longitude': longitude
51-
},
52-
'latest': {
53-
'confirmed': confirmed_latest,
54-
'deaths': deaths_latest,
55-
'recovered': recovered_latest
56-
}
57-
}
58-
59-
assert location_obj.serialize() == check_dict
40+
assert not location_obj.serialize() == None

0 commit comments

Comments
 (0)