Skip to content

Commit 3648a74

Browse files
committed
1. put the geo validation in GeoSet class constructor, and show which geo_value is invalid in the message
2. move the valid FIPS and MSA codes to test_utils.py, and import them when needed. 3. fix other failed places related to this change
1 parent a6cc058 commit 3648a74

File tree

7 files changed

+98
-97
lines changed

7 files changed

+98
-97
lines changed

integrations/client/test_delphi_epidata.py

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,10 @@
1212
# third party
1313
import delphi.operations.secrets as secrets
1414
from delphi.epidata.acquisition.covidcast.covidcast_meta_cache_updater import main as update_covidcast_meta_cache
15-
from delphi.epidata.acquisition.covidcast.test_utils import CovidcastBase, CovidcastTestRow
15+
from delphi.epidata.acquisition.covidcast.test_utils import CovidcastBase, CovidcastTestRow, FIPS, MSA
1616
from delphi.epidata.client.delphi_epidata import Epidata
1717
from delphi_utils import Nans
1818

19-
20-
# TODO replace these real geo_values with fake values, and use patch and mock to mock the return values of
21-
# delphi_utils.geomap.GeoMapper().get_geo_values(geo_type) in parse_geo_sets() of _params.py
22-
23-
global fips, msa # add two global lists of valid geo_values of these types to pass the validation in parse_geo_sets() of _params.py
24-
25-
fips = ['04019', '19143', '29063'] # Example list of valid FIPS codes as strings
26-
msa = ['40660', '44180', '48620'] # Example list of valid MSAs as strings
27-
2819
# py3tester coverage target
2920
__test_target__ = 'delphi.epidata.client.delphi_epidata'
3021
# all the Nans we use here are just one value, so this is a shortcut to it:
@@ -59,11 +50,11 @@ def test_covidcast(self):
5950

6051
# insert placeholder data: three issues of one signal, one issue of another
6152
rows = [
62-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], issue=2020_02_02 + i, value=i, lag=i)
53+
CovidcastTestRow.make_default_row(issue=2020_02_02 + i, value=i, lag=i)
6354
for i in range(3)
6455
]
6556
row_latest_issue = rows[-1]
66-
rows.append(CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], signal="sig2"))
57+
rows.append(CovidcastTestRow.make_default_row(signal="sig2"))
6758
self._insert_rows(rows)
6859

6960
with self.subTest(name='request two signals'):
@@ -227,10 +218,10 @@ def test_geo_value(self):
227218
# insert placeholder data: three counties, three MSAs
228219
N = 3
229220
rows = [
230-
CovidcastTestRow.make_default_row(geo_type="fips", geo_value=fips[i], value=i)
221+
CovidcastTestRow.make_default_row(geo_type="fips", geo_value=FIPS[i], value=i)
231222
for i in range(N)
232223
] + [
233-
CovidcastTestRow.make_default_row(geo_type="msa", geo_value=msa[i], value=i*10)
224+
CovidcastTestRow.make_default_row(geo_type="msa", geo_value=MSA[i], value=i*10)
234225
for i in range(N)
235226
]
236227
self._insert_rows(rows)
@@ -250,26 +241,29 @@ def fetch(geo):
250241
self.assertEqual(request['message'], 'success')
251242
self.assertEqual(request['epidata'], counties)
252243
# test fetch a specific region
253-
request = fetch('{}'.format(fips[0]))
244+
request = fetch([FIPS[0]])
254245
self.assertEqual(request['message'], 'success')
255246
self.assertEqual(request['epidata'], [counties[0]])
256247
# test fetch a specific yet not existing region
257248
request = fetch('55555')
258-
self.assertEqual(request['message'], 'invalid geo_value for the requested geo_type')
249+
self.assertEqual(request['message'], 'Invalid geo_value(s) 55555 for the requested geo_type fips')
259250
# test fetch a multiple regions
260-
request = fetch(['{}'.format(fips[0]), '{}'.format(fips[1])])
251+
request = fetch([FIPS[0], FIPS[1]])
261252
self.assertEqual(request['message'], 'success')
262253
self.assertEqual(request['epidata'], [counties[0], counties[1]])
263254
# test fetch a multiple regions in another variant
264-
request = fetch(['{}'.format(fips[0]), '{}'.format(fips[2])])
255+
request = fetch([FIPS[0], FIPS[2]])
265256
self.assertEqual(request['message'], 'success')
266257
self.assertEqual(request['epidata'], [counties[0], counties[2]])
267258
# test fetch a multiple regions but one is not existing
268-
request = fetch(['{}'.format(fips[0]), '55555'])
269-
self.assertEqual(request['message'], 'invalid geo_value for the requested geo_type')
259+
request = fetch([FIPS[0], '55555'])
260+
self.assertEqual(request['message'], 'Invalid geo_value(s) 55555 for the requested geo_type fips')
270261
# test fetch a multiple regions but specify no region
271262
request = fetch([])
272-
self.assertEqual(request['message'], 'invalid geo_value for the requested geo_type')
263+
self.assertEqual(request['message'], 'geo_value is empty for the requested geo_type fips!')
264+
# test fetch a region with no results
265+
request = fetch([FIPS[3]])
266+
self.assertEqual(request['message'], 'no results')
273267

274268
def test_covidcast_meta(self):
275269
"""Test that the covidcast_meta endpoint returns expected data."""
@@ -333,10 +327,10 @@ def test_async_epidata(self):
333327
# insert placeholder data: three counties, three MSAs
334328
N = 3
335329
rows = [
336-
CovidcastTestRow.make_default_row(geo_type="fips", geo_value=fips[i-1], value=i)
330+
CovidcastTestRow.make_default_row(geo_type="fips", geo_value=FIPS[i-1], value=i)
337331
for i in range(N)
338332
] + [
339-
CovidcastTestRow.make_default_row(geo_type="msa", geo_value=msa[i-1], value=i*10)
333+
CovidcastTestRow.make_default_row(geo_type="msa", geo_value=MSA[i-1], value=i*10)
340334
for i in range(N)
341335
]
342336
self._insert_rows(rows)

integrations/server/test_covidcast.py

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,19 @@
33
# standard library
44
from typing import Callable
55
import unittest
6-
# from unittest.mock import MagicMock
7-
# from unittest.mock import patch
86

97
# third party
108
import mysql.connector
119
import requests
1210

1311
# first party
1412
from delphi_utils import Nans
15-
from delphi.epidata.acquisition.covidcast.test_utils import CovidcastBase, CovidcastTestRow
13+
from delphi.epidata.acquisition.covidcast.test_utils import CovidcastBase, CovidcastTestRow, FIPS, MSA
1614
from delphi.epidata.client.delphi_epidata import Epidata
1715

1816
# use the local instance of the Epidata API
1917
BASE_URL = 'http://delphi_web_epidata/epidata/api.php'
2018

21-
# TODO replace these real geo_values with fake values, and use patch and mock to mock the return values of
22-
# delphi_utils.geomap.GeoMapper().get_geo_values(geo_type) in parse_geo_sets() of _params.py
23-
24-
global fips, msa # add two global lists of valid geo_values of these types to pass the validation in parse_geo_sets() of _params.py
25-
26-
fips = ['04019', '19143', '29063'] # Example list of valid FIPS codes as strings
27-
msa = ['40660', '44180', '48620'] # Example list of valid MSAs as strings
28-
29-
3019
class CovidcastTests(CovidcastBase):
3120
"""Tests the `covidcast` endpoint."""
3221

@@ -42,52 +31,52 @@ def request_based_on_row(self, row: CovidcastTestRow, **kwargs):
4231
return response
4332

4433
def _insert_placeholder_set_one(self):
45-
row = CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0])
34+
row = CovidcastTestRow.make_default_row()
4635
self._insert_rows([row])
4736
return row
4837

4938
def _insert_placeholder_set_two(self):
5039
rows = [
51-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[i-1], value=i*1., stderr=i*10., sample_size=i*100.)
40+
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=MSA[i-1], value=i*1., stderr=i*10., sample_size=i*100.)
5241
for i in [1, 2, 3]
5342
] + [
54-
CovidcastTestRow.make_default_row(geo_type='fips', geo_value=fips[i-4], value=i*1., stderr=i*10., sample_size=i*100.)
43+
CovidcastTestRow.make_default_row(geo_type='fips', geo_value=FIPS[i-4], value=i*1., stderr=i*10., sample_size=i*100.)
5544
for i in [4, 5, 6]
5645
]
5746
self._insert_rows(rows)
5847
return rows
5948

6049
def _insert_placeholder_set_three(self):
6150
rows = [
62-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], time_value=2000_01_01+i, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03, lag=2-i)
51+
CovidcastTestRow.make_default_row(geo_value=MSA[0], time_value=2000_01_01+i, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03, lag=2-i)
6352
for i in [1, 2, 3]
6453
] + [
6554
# time value intended to overlap with the time values above, with disjoint geo values
66-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=str(i)*5, time_value=2000_01_01+i-3, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03, lag=5-i)
55+
CovidcastTestRow.make_default_row(geo_value=str(i)*5, time_value=2000_01_01+i-3, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03, lag=5-i)
6756
for i in [4, 5, 6]
6857
]
6958
self._insert_rows(rows)
7059
return rows
7160

7261
def _insert_placeholder_set_four(self):
7362
rows = [
74-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], source='src1', signal=str(i)*5, value=i*1., stderr=i*10., sample_size=i*100.)
63+
CovidcastTestRow.make_default_row(source='src1', signal=str(i)*5, value=i*1., stderr=i*10., sample_size=i*100.)
7564
for i in [1, 2, 3]
7665
] + [
7766
# signal intended to overlap with the signal above
78-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], source='src2', signal=str(i-3)*5, value=i*1., stderr=i*10., sample_size=i*100.)
67+
CovidcastTestRow.make_default_row(source='src2', signal=str(i-3)*5, value=i*1., stderr=i*10., sample_size=i*100.)
7968
for i in [4, 5, 6]
8069
]
8170
self._insert_rows(rows)
8271
return rows
8372

8473
def _insert_placeholder_set_five(self):
8574
rows = [
86-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], time_value=2000_01_01, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03+i)
75+
CovidcastTestRow.make_default_row(time_value=2000_01_01, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03+i)
8776
for i in [1, 2, 3]
8877
] + [
8978
# different time_values, same issues
90-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], time_value=2000_01_01+i-3, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03+i-3)
79+
CovidcastTestRow.make_default_row(time_value=2000_01_01+i-3, value=i*1., stderr=i*10., sample_size=i*100., issue=2000_01_03+i-3)
9180
for i in [4, 5, 6]
9281
]
9382
self._insert_rows(rows)
@@ -317,30 +306,30 @@ def fetch(geo_value):
317306

318307
return response
319308

320-
self.maxDiff = None
321309
# test fetch a specific region
322-
r = fetch(msa[0])
310+
r = fetch(MSA[0])
323311
self.assertEqual(r['message'], 'success')
324312
self.assertEqual(r['epidata'], expected[0:1])
325313
# test fetch a specific yet not existing region
326314
r = fetch('11111')
327-
self.assertEqual(r['message'], 'invalid geo_value for the requested geo_type')
328-
315+
self.assertEqual(r['message'], 'Invalid geo_value(s) 11111 for the requested geo_type msa')
329316
# test fetch multiple regions
330-
r = fetch('{},{}'.format(msa[0], msa[1]))
317+
r = fetch('{},{}'.format(MSA[0], MSA[1]))
331318
self.assertEqual(r['message'], 'success')
332319
self.assertEqual(r['epidata'], expected[0:2])
333320
# test fetch multiple noncontiguous regions
334-
r = fetch('{},{}'.format(msa[0], msa[2]))
321+
r = fetch('{},{}'.format(MSA[0], MSA[2]))
335322
self.assertEqual(r['message'], 'success')
336323
self.assertEqual(r['epidata'], [expected[0], expected[2]])
337324
# test fetch multiple regions but one is not existing
338-
r = fetch('{},11111'.format(msa[0]))
339-
self.assertEqual(r['message'], 'invalid geo_value for the requested geo_type')
340-
325+
r = fetch('{},11111'.format(MSA[0]))
326+
self.assertEqual(r['message'], 'Invalid geo_value(s) 11111 for the requested geo_type msa')
341327
# test fetch empty region
342328
r = fetch('')
343-
self.assertEqual(r['message'], 'invalid geo_value for the requested geo_type')
329+
self.assertEqual(r['message'], 'geo_value is empty for the requested geo_type msa!')
330+
# test a region that has no results
331+
r = fetch(MSA[3])
332+
self.assertEqual(r['message'], 'no results')
344333

345334
def test_location_timeline(self):
346335
"""Select a timeline for a particular location."""
@@ -377,7 +366,7 @@ def test_nullable_columns(self):
377366
"""Missing values should be surfaced as null."""
378367

379368
row = CovidcastTestRow.make_default_row(
380-
geo_type='msa', geo_value=msa[0], stderr=None, sample_size=None,
369+
stderr=None, sample_size=None,
381370
missing_stderr=Nans.OTHER.value, missing_sample_size=Nans.OTHER.value
382371
)
383372
self._insert_rows([row])
@@ -398,7 +387,7 @@ def test_temporal_partitioning(self):
398387

399388
# insert placeholder data
400389
rows = [
401-
CovidcastTestRow.make_default_row(geo_type='msa', geo_value=msa[0], time_type=tt)
390+
CovidcastTestRow.make_default_row(time_type=tt)
402391
for tt in "hour day week month year".split()
403392
]
404393
self._insert_rows(rows)

src/acquisition/covidcast/test_utils.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
# all the Nans we use here are just one value, so this is a shortcut to it:
1515
nmv = Nans.NOT_MISSING.value
1616

17+
# TODO replace these real geo_values with fake values, and use patch and mock to mock the return values of
18+
# delphi_utils.geomap.GeoMapper().get_geo_values(geo_type) in parse_geo_sets() of _params.py
19+
20+
FIPS = ['04019', '19143', '29063', '36083'] # Example list of valid FIPS codes as strings
21+
MSA = ['40660', '44180', '48620', '49420'] # Example list of valid MSA codes as strings
1722

1823
class CovidcastTestRow(CovidcastRow):
1924
@staticmethod
@@ -22,9 +27,9 @@ def make_default_row(**kwargs) -> "CovidcastTestRow":
2227
"source": "src",
2328
"signal": "sig",
2429
"time_type": "day",
25-
"geo_type": "county",
30+
"geo_type": "msa",
2631
"time_value": 2020_02_02,
27-
"geo_value": "01234",
32+
"geo_value": "40660", # a valid geo_value for msa
2833
"value": 10.0,
2934
"stderr": 10.0,
3035
"sample_size": 10.0,

src/server/_params.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ class GeoSet:
5454
geo_type: str
5555
geo_values: Union[bool, Sequence[str]]
5656

57+
def __init__(self, geo_type: str, geo_values: Union[bool, Sequence[str]]):
58+
if not isinstance(geo_values, bool):
59+
if geo_values == ['']:
60+
raise ValidationFailedException(f"geo_value is empty for the requested geo_type {geo_type}!")
61+
allowed_values = delphi_utils.geomap.GeoMapper().get_geo_values(geo_type)
62+
invalid_values = set(geo_values) - set(allowed_values)
63+
if invalid_values:
64+
raise ValidationFailedException(f"Invalid geo_value(s) {', '.join(invalid_values)} for the requested geo_type {geo_type}")
65+
self.geo_type = geo_type
66+
self.geo_values = geo_values
67+
5768
def matches(self, geo_type: str, geo_value: str) -> bool:
5869
return self.geo_type == geo_type and (self.geo_values is True or (not isinstance(self.geo_values, bool) and geo_value in self.geo_values))
5970

@@ -469,9 +480,9 @@ def parse_geo_sets() -> List[GeoSet]:
469480
if len(geo_values) == 1 and geo_values[0] == "*":
470481
return [GeoSet(geo_type, True)]
471482

472-
for geo_value in geo_values:
473-
if geo_value not in delphi_utils.geomap.GeoMapper().get_geo_values(geo_type):
474-
raise ValidationFailedException("invalid geo_value for the requested geo_type")
483+
# for geo_value in geo_values:
484+
# if geo_value not in delphi_utils.geomap.GeoMapper().get_geo_values(geo_type):
485+
# raise ValidationFailedException("invalid geo_value for the requested geo_type")
475486

476487
return [GeoSet(geo_type, geo_values)]
477488

tests/acquisition/covidcast/test_covidcast_row.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ class TestCovidcastRows(unittest.TestCase):
2222
"source": ["src"] * 10,
2323
"signal": ["sig_base"] * 5 + ["sig_other"] * 5,
2424
"time_type": ["day"] * 10,
25-
"geo_type": ["county"] * 10,
25+
"geo_type": ["msa"] * 10,
2626
"time_value": [2021_05_01 + i for i in range(5)] * 2,
27-
"geo_value": ["01234"] * 10,
27+
"geo_value": ["40660"] * 10,
2828
"value": range(10),
2929
"stderr": [10.0] * 10,
3030
"sample_size": [10.0] * 10,

0 commit comments

Comments
 (0)