Skip to content

Commit 8e1d95e

Browse files
authored
Merge pull request #1229 from cmu-delphi/release/delphi-epidata-4.1.5
Release Delphi Epidata 4.1.5
2 parents b8d5600 + a85455a commit 8e1d95e

File tree

19 files changed

+353
-292
lines changed

19 files changed

+353
-292
lines changed

.bumpversion.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 4.1.4
2+
current_version = 4.1.5
33
commit = False
44
tag = False
55

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Dependabot auto-assign reviewer
2+
on: pull_request
3+
4+
permissions:
5+
pull-requests: write
6+
7+
jobs:
8+
dependabot:
9+
runs-on: ubuntu-latest
10+
env:
11+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
12+
if: ${{ github.actor == 'dependabot[bot]' }}
13+
steps:
14+
- name: Assign team to PR
15+
run: gh pr edit "$PR_URL" --add-reviewer "cmu-delphi/code-reviewers"
16+
env:
17+
PR_URL: ${{github.event.pull_request.html_url}}

dev/local/setup.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = Delphi Development
3-
version = 4.1.4
3+
version = 4.1.5
44

55
[options]
66
packages =

src/client/delphi_epidata.R

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Epidata <- (function() {
1515
# API base url
1616
BASE_URL <- getOption('epidata.url', default = 'https://api.delphi.cmu.edu/epidata/')
1717

18-
client_version <- '4.1.4'
18+
client_version <- '4.1.5'
1919

2020
auth <- getOption("epidata.auth", default = NA)
2121

src/client/delphi_epidata.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
}
2323
})(this, function (exports, fetchImpl, jQuery) {
2424
const BASE_URL = "https://api.delphi.cmu.edu/epidata/";
25-
const client_version = "4.1.4";
25+
const client_version = "4.1.5";
2626

2727
// Helper function to cast values and/or ranges to strings
2828
function _listitem(value) {

src/client/packaging/npm/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "delphi_epidata",
33
"description": "Delphi Epidata API Client",
44
"authors": "Delphi Group",
5-
"version": "4.1.4",
5+
"version": "4.1.5",
66
"license": "MIT",
77
"homepage": "https://github.com/cmu-delphi/delphi-epidata",
88
"bugs": {
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from .delphi_epidata import Epidata
22

33
name = 'delphi_epidata'
4-
__version__ = '4.1.4'
4+
__version__ = '4.1.5'

src/client/packaging/pypi/setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="delphi_epidata",
8-
version="4.1.4",
8+
version="4.1.5",
99
author="David Farrow",
1010
author_email="[email protected]",
1111
description="A programmatic interface to Delphi's Epidata API.",

src/common/covidcast_row.py

+31-13
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"value_updated_timestamp": "Int64",
2626
}
2727

28+
2829
@dataclass
2930
class CovidcastRow:
3031
"""A container for the values of a single covidcast database row.
@@ -35,7 +36,8 @@ class CovidcastRow:
3536
- converting from and to formats (dict, csv, df, kwargs)
3637
- creating consistent views, with consistent data types (dict, csv, df)
3738
38-
The rows are specified in 'v4_schema.sql'. The datatypes are made to match database. When writing to Pandas, the dtypes match the JIT model.py schema.
39+
The rows are specified in 'v4_schema.sql'. The datatypes are made to match
40+
database. When writing to Pandas, the dtypes match the JIT model.py schema.
3941
"""
4042

4143
# Arguments.
@@ -54,15 +56,20 @@ class CovidcastRow:
5456
missing_sample_size: int
5557
issue: int
5658
lag: int
57-
# The following three fields are only the database, but are not ingested at acquisition and not returned by the API.
59+
# The following three fields are only in the database, but are not ingested at
60+
# acquisition and not returned by the API.
5861
epimetric_id: Optional[int] = None
5962
direction: Optional[int] = None
6063
value_updated_timestamp: Optional[int] = 0
6164

6265
# Classvars.
6366
_db_row_ignore_fields: ClassVar = []
6467
_api_row_ignore_fields: ClassVar = ["epimetric_id", "value_updated_timestamp"]
65-
_api_row_compatibility_ignore_fields: ClassVar = _api_row_ignore_fields + ["source", "time_type", "geo_type"]
68+
_api_row_compatibility_ignore_fields: ClassVar = _api_row_ignore_fields + [
69+
"source",
70+
"time_type",
71+
"geo_type",
72+
]
6673

6774
_pandas_dtypes: ClassVar = PANDAS_DTYPES
6875

@@ -72,17 +79,22 @@ def as_dict(self, ignore_fields: Optional[List[str]] = None) -> dict:
7279
for key in ignore_fields:
7380
del d[key]
7481
return d
75-
82+
7683
def as_api_row_dict(self, ignore_fields: Optional[List[str]] = None) -> dict:
77-
"""Returns a dict view into the row with the fields returned by the API server."""
84+
"""Returns a dict view into the row with the fields returned by the API
85+
server."""
7886
return self.as_dict(ignore_fields=self._api_row_ignore_fields + (ignore_fields or []))
7987

8088
def as_api_compatibility_row_dict(self, ignore_fields: Optional[List[str]] = None) -> dict:
81-
"""Returns a dict view into the row with the fields returned by the old API server (the PHP server)."""
82-
return self.as_dict(ignore_fields=self._api_row_compatibility_ignore_fields + (ignore_fields or []))
89+
"""Returns a dict view into the row with the fields returned by the old
90+
API server (the PHP server)."""
91+
return self.as_dict(
92+
ignore_fields=self._api_row_compatibility_ignore_fields + (ignore_fields or [])
93+
)
8394

8495
def as_db_row_dict(self, ignore_fields: Optional[List[str]] = None) -> dict:
85-
"""Returns a dict view into the row with the fields returned by the database."""
96+
"""Returns a dict view into the row with the fields returned by the
97+
database."""
8698
return self.as_dict(ignore_fields=self._db_row_ignore_fields + (ignore_fields or []))
8799

88100
def as_dataframe(self, ignore_fields: Optional[List[str]] = None) -> pd.DataFrame:
@@ -92,15 +104,22 @@ def as_dataframe(self, ignore_fields: Optional[List[str]] = None) -> pd.DataFram
92104
return df
93105

94106
def as_api_row_df(self, ignore_fields: Optional[List[str]] = None) -> pd.DataFrame:
95-
"""Returns a dataframe view into the row with the fields returned by the API server."""
107+
"""Returns a dataframe view into the row with the fields returned by the
108+
API server."""
96109
return self.as_dataframe(ignore_fields=self._api_row_ignore_fields + (ignore_fields or []))
97110

111+
# fmt: off
98112
def as_api_compatibility_row_df(self, ignore_fields: Optional[List[str]] = None) -> pd.DataFrame:
99-
"""Returns a dataframe view into the row with the fields returned by the old API server (the PHP server)."""
100-
return self.as_dataframe(ignore_fields=self._api_row_compatibility_ignore_fields + (ignore_fields or []))
113+
"""Returns a dataframe view into the row with the fields returned by the
114+
old API server (the PHP server)."""
115+
# fmt: on
116+
return self.as_dataframe(
117+
ignore_fields=self._api_row_compatibility_ignore_fields + (ignore_fields or [])
118+
)
101119

102120
def as_db_row_df(self, ignore_fields: Optional[List[str]] = None) -> pd.DataFrame:
103-
"""Returns a dataframe view into the row with the fields returned by an all-field database query."""
121+
"""Returns a dataframe view into the row with the fields returned by an
122+
all-field database query."""
104123
return self.as_dataframe(ignore_fields=self._db_row_ignore_fields + (ignore_fields or []))
105124

106125
def signal_pair(self):
@@ -113,7 +132,6 @@ def time_pair(self):
113132
return f"{self.time_type}:{self.time_value}"
114133

115134

116-
117135
def check_valid_dtype(dtype):
118136
try:
119137
pd.api.types.pandas_dtype(dtype)

src/common/logger.py

+6-11
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import threading
55
import structlog
66

7+
78
def handle_exceptions(logger):
89
"""Handle exceptions using the provided logger."""
10+
911
def exception_handler(etype, value, traceback):
10-
logger.exception("Top-level exception occurred",
11-
exc_info=(etype, value, traceback))
12+
logger.exception("Top-level exception occurred", exc_info=(etype, value, traceback))
1213

1314
def multithread_exception_handler(args):
1415
exception_handler(args.exc_type, args.exc_value, args.exc_traceback)
@@ -17,9 +18,7 @@ def multithread_exception_handler(args):
1718
threading.excepthook = multithread_exception_handler
1819

1920

20-
def get_structured_logger(name=__name__,
21-
filename=None,
22-
log_exceptions=True):
21+
def get_structured_logger(name=__name__, filename=None, log_exceptions=True):
2322
"""Create a new structlog logger.
2423
2524
Use the logger returned from this in indicator code using the standard
@@ -49,11 +48,7 @@ def get_structured_logger(name=__name__,
4948
else:
5049
log_level = logging.INFO
5150

52-
logging.basicConfig(
53-
format="%(message)s",
54-
level=log_level,
55-
handlers=handlers
56-
)
51+
logging.basicConfig(format="%(message)s", level=log_level, handlers=handlers)
5752

5853
def add_pid(logger, method_name, event_dict):
5954
"""
@@ -85,7 +80,7 @@ def add_pid(logger, method_name, event_dict):
8580
# Decode unicode characters
8681
structlog.processors.UnicodeDecoder(),
8782
# Render as JSON
88-
structlog.processors.JSONRenderer()
83+
structlog.processors.JSONRenderer(),
8984
],
9085
# Use a dict class for keeping track of data.
9186
context_class=dict,

src/server/_config.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
load_dotenv()
99

10-
VERSION = "4.1.4"
10+
VERSION = "4.1.5"
1111

1212
MAX_RESULTS = int(10e6)
1313
MAX_COMPATIBILITY_RESULTS = int(3650)

src/server/_printer.py

+11-7
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@ def __init__(self):
4646
self.result: int = -1
4747
self._max_results: int = MAX_COMPATIBILITY_RESULTS if is_compatibility_mode() else MAX_RESULTS
4848

49-
def make_response(self, gen):
49+
def make_response(self, gen, headers=None):
5050
return Response(
5151
gen,
5252
mimetype="application/json",
53+
headers=headers,
5354
)
5455

55-
def __call__(self, generator: Iterable[Dict[str, Any]]) -> Response:
56+
def __call__(self, generator: Iterable[Dict[str, Any]], headers=None) -> Response:
5657
def gen():
5758
self.result = -2 # no result, default response
5859
began = False
@@ -84,7 +85,7 @@ def gen():
8485
if r is not None:
8586
yield r
8687

87-
return self.make_response(stream_with_context(gen()))
88+
return self.make_response(stream_with_context(gen()), headers=headers)
8889

8990
@property
9091
def remaining_rows(self) -> int:
@@ -223,8 +224,11 @@ def __init__(self, filename: Optional[str] = "epidata"):
223224
super(CSVPrinter, self).__init__()
224225
self._filename = filename
225226

226-
def make_response(self, gen):
227-
headers = {"Content-Disposition": f"attachment; filename={self._filename}.csv"} if self._filename else {}
227+
def make_response(self, gen, headers=None):
228+
if headers is None:
229+
headers = {}
230+
if self._filename:
231+
headers["Content-Disposition"] = f"attachment; filename={self._filename}.csv"
228232
return Response(gen, mimetype="text/csv; charset=utf8", headers=headers)
229233

230234
def _begin(self):
@@ -296,8 +300,8 @@ class JSONLPrinter(APrinter):
296300
a printer class writing in JSONLines format
297301
"""
298302

299-
def make_response(self, gen):
300-
return Response(gen, mimetype=" text/plain; charset=utf8")
303+
def make_response(self, gen, headers=None):
304+
return Response(gen, mimetype=" text/plain; charset=utf8", headers=headers)
301305

302306
def _begin(self):
303307
if show_hard_api_key_warning():

0 commit comments

Comments
 (0)