Skip to content

Commit a512d03

Browse files
committed
add endpoint covid_hosp_facility
- api udpated - all clients updated - added integration test which exercises the new endpoint in server and python client
1 parent 7cea647 commit a512d03

File tree

6 files changed

+405
-1
lines changed

6 files changed

+405
-1
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Integration tests for acquisition of COVID hospitalization facility."""
2+
3+
# standard library
4+
import unittest
5+
from unittest.mock import MagicMock
6+
7+
# first party
8+
from delphi.epidata.acquisition.covid_hosp.common.database import Database
9+
from delphi.epidata.acquisition.covid_hosp.common.test_utils import TestUtils
10+
from delphi.epidata.client.delphi_epidata import Epidata
11+
import delphi.operations.secrets as secrets
12+
13+
# py3tester coverage target (equivalent to `import *`)
14+
__test_target__ = 'delphi.epidata.acquisition.covid_hosp.facility.update'
15+
16+
17+
class AcquisitionTests(unittest.TestCase):
18+
19+
def setUp(self):
20+
"""Perform per-test setup."""
21+
22+
# configure test data
23+
self.test_utils = TestUtils(__file__)
24+
25+
# use the local instance of the Epidata API
26+
Epidata.BASE_URL = 'http://delphi_web_epidata/epidata/api.php'
27+
28+
# use the local instance of the epidata database
29+
secrets.db.host = 'delphi_database_epidata'
30+
secrets.db.epi = ('user', 'pass')
31+
32+
# clear relevant tables
33+
with Database.connect() as db:
34+
with db.new_cursor() as cur:
35+
cur.execute('truncate table covid_hosp_facility')
36+
cur.execute('truncate table covid_hosp_meta')
37+
38+
def test_acquire_dataset(self):
39+
"""Acquire a new dataset."""
40+
41+
# only mock out network calls to external hosts
42+
mock_network = MagicMock()
43+
mock_network.fetch_metadata.return_value = \
44+
self.test_utils.load_sample_metadata()
45+
mock_network.fetch_dataset.return_value = \
46+
self.test_utils.load_sample_dataset()
47+
48+
# make sure the data does not yet exist
49+
with self.subTest(name='no data yet'):
50+
response = Epidata.covid_hosp_facility(
51+
'450822', Epidata.range(20200101, 20210101))
52+
self.assertEqual(response['result'], -2)
53+
54+
# acquire sample data into local database
55+
with self.subTest(name='first acquisition'):
56+
acquired = Update.run(network=mock_network)
57+
self.assertTrue(acquired)
58+
59+
# make sure the data now exists
60+
with self.subTest(name='initial data checks'):
61+
response = Epidata.covid_hosp_facility(
62+
'450822', Epidata.range(20200101, 20210101))
63+
self.assertEqual(response['result'], 1)
64+
self.assertEqual(len(response['epidata']), 1)
65+
row = response['epidata'][0]
66+
self.assertEqual(row['hospital_pk'], '450822')
67+
self.assertEqual(row['collection_week'], 20201030)
68+
self.assertEqual(row['publication_date'], 20201208)
69+
self.assertEqual(row['previous_day_total_ed_visits_7_day_sum'], 536)
70+
self.assertAlmostEqual(row['total_beds_7_day_avg'], 69.3)
71+
self.assertEqual(
72+
row['previous_day_admission_influenza_confirmed_7_day_sum'], -999999)
73+
74+
# expect 94 fields per row (95 database columns, except `id`)
75+
self.assertEqual(len(row), 94)
76+
77+
# re-acquisition of the same dataset should be a no-op
78+
with self.subTest(name='second acquisition'):
79+
acquired = Update.run(network=mock_network)
80+
self.assertFalse(acquired)
81+
82+
# make sure the data still exists
83+
with self.subTest(name='final data checks'):
84+
response = Epidata.covid_hosp_facility(
85+
'450822', Epidata.range(20200101, 20210101))
86+
self.assertEqual(response['result'], 1)
87+
self.assertEqual(len(response['epidata']), 1)

src/client/delphi_epidata.R

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,25 @@ Epidata <- (function() {
566566
return(.request(params))
567567
}
568568

569+
# Fetch COVID hospitalization data for specific facilities
570+
covid_hosp_facility <- function(hospital_pks, collection_weeks, publication_dates) {
571+
# Check parameters
572+
if(missing(hospital_pks) || missing(collection_weeks)) {
573+
stop('`hospital_pks` and `collection_weeks` are both required')
574+
}
575+
# Set up request
576+
params <- list(
577+
source = 'covid_hosp_facility',
578+
hospital_pks = .list(hospital_pks),
579+
collection_weeks = .list(collection_weeks)
580+
)
581+
if(!missing(publication_dates)) {
582+
params$publication_dates <- .list(publication_dates)
583+
}
584+
# Make the API call
585+
return(.request(params))
586+
}
587+
569588
# Export the public methods
570589
return(list(
571590
range = range,
@@ -593,6 +612,7 @@ Epidata <- (function() {
593612
meta = meta,
594613
covidcast = covidcast,
595614
covidcast_meta = covidcast_meta,
596-
covid_hosp = covid_hosp
615+
covid_hosp = covid_hosp,
616+
covid_hosp_facility = covid_hosp_facility
597617
))
598618
})()

src/client/delphi_epidata.coffee

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,5 +404,20 @@ class Epidata
404404
# Make the API call
405405
_request(callback, params)
406406

407+
# Fetch COVID hospitalization data for specific facilities
408+
@covid_hosp_facility: (callback, hospital_pks, collection_weeks, publication_dates) ->
409+
# Check parameters
410+
unless hospital_pks? and collection_weeks?
411+
throw { msg: '`hospital_pks` and `collection_weeks` are both required' }
412+
# Set up request
413+
params =
414+
'source': 'covid_hosp_facility'
415+
'hospital_pks': _list(hospital_pks)
416+
'collection_weeks': _list(collection_weeks)
417+
if publication_dates?
418+
params.publication_dates = _list(publication_dates)
419+
# Make the API call
420+
_request(callback, params)
421+
407422
# Export the API to the global environment
408423
(exports ? window).Epidata = Epidata

src/client/delphi_epidata.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,32 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
635635
} // Make the API call
636636

637637

638+
return _request(callback, params);
639+
} // Fetch COVID hospitalization data for specific facilities
640+
641+
}, {
642+
key: "covid_hosp_facility",
643+
value: function covid_hosp_facility(callback, hospital_pks, collection_weeks, publication_dates) {
644+
var params; // Check parameters
645+
646+
if (!(hospital_pks != null && collection_weeks != null)) {
647+
throw {
648+
msg: '`hospital_pks` and `collection_weeks` are both required'
649+
};
650+
} // Set up request
651+
652+
653+
params = {
654+
'source': 'covid_hosp_facility',
655+
'hospital_pks': _list(hospital_pks),
656+
'collection_weeks': _list(collection_weeks)
657+
};
658+
659+
if (publication_dates != null) {
660+
params.publication_dates = _list(publication_dates);
661+
} // Make the API call
662+
663+
638664
return _request(callback, params);
639665
}
640666
}]);

src/client/delphi_epidata.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,3 +624,22 @@ def covid_hosp(states, dates, issues=None):
624624
params['issues'] = Epidata._list(issues)
625625
# Make the API call
626626
return Epidata._request(params)
627+
628+
# Fetch COVID hospitalization data for specific facilities
629+
@staticmethod
630+
def covid_hosp_facility(
631+
hospital_pks, collection_weeks, publication_dates=None):
632+
"""Fetch COVID hospitalization data for specific facilities."""
633+
# Check parameters
634+
if hospital_pks is None or collection_weeks is None:
635+
raise Exception('`hospital_pks` and `collection_weeks` are both required')
636+
# Set up request
637+
params = {
638+
'source': 'covid_hosp_facility',
639+
'hospital_pks': Epidata._list(hospital_pks),
640+
'collection_weeks': Epidata._list(collection_weeks),
641+
}
642+
if publication_dates is not None:
643+
params['publication_dates'] = Epidata._list(publication_dates)
644+
# Make the API call
645+
return Epidata._request(params)

0 commit comments

Comments
 (0)