Skip to content

Commit f8a6706

Browse files
committed
flusurv tests
1 parent 1e942a5 commit f8a6706

File tree

2 files changed

+185
-6
lines changed

2 files changed

+185
-6
lines changed

Diff for: src/acquisition/flusurv/flusurv.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ def get_data(location, seasonids):
253253
Fetch and parse flu data for the given location.
254254
255255
This method performs the following operations:
256-
- filters location-specific FluSurv data from CDC API response object
257-
- extracts and returns hospitalization rates
256+
- fetch location-specific FluSurv data from CDC API
257+
- extracts and returns hospitalization rates for each epiweek
258258
"""
259259
# fetch
260260
print("[fetching flusurv data...]")

Diff for: tests/acquisition/flusurv/test_flusurv.py

+183-4
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,102 @@
22

33
# standard library
44
import unittest
5-
from unittest.mock import MagicMock
6-
from unittest.mock import sentinel
5+
from unittest.mock import (MagicMock, sentinel, patch)
76

8-
from delphi.epidata.acquisition.flusurv.flusurv import fetch_json
7+
import delphi.epidata.acquisition.flusurv.flusurv as flusurv
98

109
# py3tester coverage target
1110
__test_target__ = "delphi.epidata.acquisition.flusurv.flusurv"
1211

1312

13+
# Example location-specific return JSON from CDC GRASP API. Contains
14+
# partial data for "network_all" location and season 49.
15+
network_all_example_data = {
16+
'default_data': [
17+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 1, 'rate': 20.7, 'weeklyrate': 0.0, 'mmwrid': 2519},
18+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 2, 'rate': 41.3, 'weeklyrate': 0.1, 'mmwrid': 2519},
19+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 1, 'sexid': 0, 'raceid': 0, 'rate': 42, 'weeklyrate': 0.5, 'mmwrid': 2519},
20+
21+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 1, 'rate': 4.3, 'weeklyrate': 1.7, 'mmwrid': 2493},
22+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 2, 'rate': 11.6, 'weeklyrate': 3.6, 'mmwrid': 2493},
23+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 3, 'rate': 12.8, 'weeklyrate': 4.8, 'mmwrid': 2493},
24+
25+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 1, 'rate': 20.6, 'weeklyrate': 0.1, 'mmwrid': 2516},
26+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 2, 'rate': 40.7, 'weeklyrate': 0.5, 'mmwrid': 2516},
27+
28+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 1, 'rate': 20.3, 'weeklyrate': 0.1, 'mmwrid': 2513},
29+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 2, 'rate': 39.6, 'weeklyrate': 0.3, 'mmwrid': 2513},
30+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 0, 'sexid': 0, 'raceid': 3, 'rate': 36.0, 'weeklyrate': 0.1, 'mmwrid': 2513},
31+
]
32+
}
33+
34+
# Example metadata response containing "master_lookup" element only, used
35+
# for mapping between valueids and strata descriptions
36+
master_lookup_metadata = {
37+
'master_lookup': [
38+
{'Variable': 'Age', 'valueid': 1, 'parentid': 97, 'Label': '0-4 yr', 'Color_HexValue': '#d19833', 'Enabled': True},
39+
{'Variable': 'Age', 'valueid': 2, 'parentid': 97, 'Label': '5-17 yr', 'Color_HexValue': '#707070', 'Enabled': True},
40+
{'Variable': 'Age', 'valueid': 3, 'parentid': 98, 'Label': '18-49 yr', 'Color_HexValue': '#44b3c6', 'Enabled': True},
41+
{'Variable': 'Age', 'valueid': 4, 'parentid': 98, 'Label': '50-64 yr', 'Color_HexValue': '#516889', 'Enabled': True},
42+
{'Variable': 'Age', 'valueid': 5, 'parentid': 98, 'Label': '65+ yr', 'Color_HexValue': '#cc5e56', 'Enabled': True},
43+
{'Variable': 'Age', 'valueid': 7, 'parentid': 5, 'Label': '65-74 yr', 'Color_HexValue': '#cc5e56', 'Enabled': True},
44+
{'Variable': 'Age', 'valueid': 8, 'parentid': 5, 'Label': '75-84 yr', 'Color_HexValue': '#cc5e56', 'Enabled': True},
45+
{'Variable': 'Age', 'valueid': 9, 'parentid': 5, 'Label': '85+', 'Color_HexValue': '#cc5e56', 'Enabled': True},
46+
{'Variable': 'Age', 'valueid': 10, 'parentid': 3, 'Label': '18-29 yr', 'Color_HexValue': '#44b3c6', 'Enabled': True},
47+
{'Variable': 'Age', 'valueid': 11, 'parentid': 3, 'Label': '30-39 yr', 'Color_HexValue': '#44b3c6', 'Enabled': True},
48+
{'Variable': 'Age', 'valueid': 12, 'parentid': 3, 'Label': '40-49 yr', 'Color_HexValue': '#44b3c6', 'Enabled': True},
49+
{'Variable': 'Age', 'valueid': 21, 'parentid': 2, 'Label': '5-11 yr', 'Color_HexValue': '#707070', 'Enabled': True},
50+
{'Variable': 'Age', 'valueid': 22, 'parentid': 2, 'Label': '12-17 yr', 'Color_HexValue': '#707070', 'Enabled': True},
51+
{'Variable': 'Age', 'valueid': 97, 'parentid': 0, 'Label': '< 18', 'Color_HexValue': '#000000', 'Enabled': True},
52+
{'Variable': 'Age', 'valueid': 98, 'parentid': 0, 'Label': '>= 18', 'Color_HexValue': '#000000', 'Enabled': True},
53+
54+
{'Variable': 'Race', 'valueid': 1, 'parentid': None, 'Label': 'White', 'Color_HexValue': '#516889', 'Enabled': True},
55+
{'Variable': 'Race', 'valueid': 2, 'parentid': None, 'Label': 'Black', 'Color_HexValue': '#44b3c6', 'Enabled': True},
56+
{'Variable': 'Race', 'valueid': 3, 'parentid': None, 'Label': 'Hispanic/Latino', 'Color_HexValue': '#d19833', 'Enabled': True},
57+
{'Variable': 'Race', 'valueid': 4, 'parentid': None, 'Label': 'Asian/Pacific Islander', 'Color_HexValue': '#cc5e56', 'Enabled': True},
58+
{'Variable': 'Race', 'valueid': 5, 'parentid': None, 'Label': 'American Indian/Alaska Native', 'Color_HexValue': '#007d8e', 'Enabled': True},
59+
60+
{'Variable': 'Sex', 'valueid': 1, 'parentid': None, 'Label': 'Male', 'Color_HexValue': '#44b3c6', 'Enabled': True},
61+
{'Variable': 'Sex', 'valueid': 2, 'parentid': None, 'Label': 'Female', 'Color_HexValue': '#F2775F', 'Enabled': True},
62+
63+
{'Variable': None, 'valueid': 0, 'parentid': 0, 'Label': 'Overall', 'Color_HexValue': '#000000', 'Enabled': True},
64+
],
65+
}
66+
67+
# Map derived from "master_lookup" dictionary above mapping between valueids
68+
# by type and cleaned-up descriptions (no spaces or capital letters, etc)
69+
id_label_map = {
70+
"Age": {
71+
1: "0t4",
72+
2: "5t17",
73+
3: "18t49",
74+
4: "50t64",
75+
5: "65+",
76+
7: "65t74",
77+
8: "75t84",
78+
9: "85+",
79+
10: "18t29",
80+
11: "30t39",
81+
12: "40t49",
82+
21: "5t11",
83+
22: "12t17",
84+
97: "<18",
85+
98: ">=18",
86+
},
87+
"Race": {
88+
1: "white",
89+
2: "black",
90+
3: "hispaniclatino",
91+
4: "asianpacificislander",
92+
5: "americanindianalaskanative",
93+
},
94+
"Sex": {
95+
1: "male",
96+
2: "female",
97+
},
98+
}
99+
100+
14101
class FunctionTests(unittest.TestCase):
15102
"""Tests each function individually."""
16103

@@ -28,6 +115,98 @@ def test_fetch_json(self):
28115
requests_impl = MagicMock()
29116
requests_impl.get.return_value = response_object
30117

31-
actual = fetch_json(path, payload, requests_impl=requests_impl)
118+
actual = flusurv.fetch_json(path, payload, requests_impl=requests_impl)
32119

33120
self.assertEqual(actual, sentinel.expected)
121+
122+
def test_mmwrid_to_epiweek(self):
123+
# Test epoch
124+
self.assertEqual(flusurv.mmwrid_to_epiweek(2179), 200340)
125+
126+
metadata = flusurv.fetch_flusurv_metadata()
127+
for mmwr in metadata["mmwr"]:
128+
self.assertEqual(flusurv.mmwrid_to_epiweek(mmwr["mmwrid"]), mmwr["yearweek"])
129+
130+
@patch(__test_target__ + ".fetch_flusurv_location")
131+
def test_get_data(self, MockFlusurvLocation):
132+
MockFlusurvLocation.return_value = network_all_example_data
133+
134+
self.assertEqual(flusurv.get_data("network_all", [30, 49]), {
135+
201014: {"rate_race_white": 0.0, "rate_race_black": 0.1, "rate_age_0": 0.5},
136+
200940: {"rate_race_white": 1.7, "rate_race_black": 3.6, "rate_race_hispaniclatino": 4.8},
137+
201011: {"rate_race_white": 0.1, "rate_race_black": 0.5},
138+
201008: {"rate_race_white": 0.1, "rate_race_black": 0.3, "rate_race_hispaniclatino": 0.1},
139+
}
140+
)
141+
142+
@patch(__test_target__ + ".fetch_flusurv_metadata")
143+
def test_group_by_epiweek(self, MockFlusurvMetadata):
144+
# Flusurv metadata is fetched by `make_id_label_map()`.
145+
MockFlusurvMetadata.return_value = master_lookup_metadata
146+
147+
input_data = network_all_example_data
148+
self.assertEqual(flusurv.group_by_epiweek(input_data), {
149+
201014: {"rate_race_white": 0.0, "rate_race_black": 0.1, "rate_age_0": 0.5},
150+
200940: {"rate_race_white": 1.7, "rate_race_black": 3.6, "rate_race_hispaniclatino": 4.8},
151+
201011: {"rate_race_white": 0.1, "rate_race_black": 0.5},
152+
201008: {"rate_race_white": 0.1, "rate_race_black": 0.3, "rate_race_hispaniclatino": 0.1},
153+
}
154+
)
155+
156+
duplicate_input_data = {
157+
'default_data': [
158+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 1, 'sexid': 0, 'raceid': 0, 'rate': 42, 'weeklyrate': 0.5, 'mmwrid': 2519},
159+
{'networkid': 1, 'catchmentid': 22, 'seasonid': 49, 'ageid': 1, 'sexid': 0, 'raceid': 0, 'rate': 42, 'weeklyrate': 54, 'mmwrid': 2519},
160+
]
161+
}
162+
163+
with self.assertWarnsRegex(Warning, "warning: Multiple rates seen for 201014"):
164+
flusurv.group_by_epiweek(duplicate_input_data)
165+
166+
with self.assertRaisesRegex(Exception, "no data found"):
167+
flusurv.group_by_epiweek({"default_data": []})
168+
169+
@patch('builtins.print')
170+
def test_group_by_epiweek_print_msgs(self, mock_print):
171+
input_data = network_all_example_data
172+
flusurv.group_by_epiweek(input_data)
173+
mock_print.assert_called_with("found data for 4 epiweeks")
174+
175+
def test_get_current_issue(self):
176+
input_data = {
177+
'loaddatetime': 'Sep 12, 2023'
178+
}
179+
self.assertEqual(flusurv.get_current_issue(input_data), 202337)
180+
181+
@patch(__test_target__ + ".fetch_flusurv_metadata")
182+
def test_make_id_label_map(self, MockFlusurvMetadata):
183+
MockFlusurvMetadata.return_value = master_lookup_metadata
184+
self.assertEqual(flusurv.make_id_label_map(), id_label_map)
185+
186+
def test_groupids_to_name(self):
187+
ids = (
188+
(1, 0, 0),
189+
(9, 0, 0),
190+
(0, 2, 0),
191+
(0, 0, 3),
192+
(0, 0, 5),
193+
(0, 0, 0),
194+
)
195+
expected_list = [
196+
"rate_age_0",
197+
"rate_age_7",
198+
"rate_sex_female",
199+
"rate_race_hispaniclatino",
200+
"rate_race_americanindianalaskanative",
201+
"rate_overall",
202+
]
203+
204+
for (ageid, sexid, raceid), expected in zip(ids, expected_list):
205+
self.assertEqual(flusurv.groupids_to_name(ageid, sexid, raceid, id_label_map), expected)
206+
207+
with self.assertRaisesRegex(ValueError, "Ageid cannot be 6"):
208+
flusurv.groupids_to_name(6, 0, 0, id_label_map)
209+
with self.assertRaisesRegex(AssertionError, "At most one groupid can be non-zero"):
210+
flusurv.groupids_to_name(1, 1, 0, id_label_map)
211+
flusurv.groupids_to_name(0, 1, 1, id_label_map)
212+
flusurv.groupids_to_name(1, 1, 1, id_label_map)

0 commit comments

Comments
 (0)