Skip to content

Commit 0a0c81f

Browse files
committed
enh: updates from Javier's review
1 parent f217c14 commit 0a0c81f

7 files changed

Lines changed: 104 additions & 38 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,19 @@ epidata.epidata_archive(
6464
source="nssp",
6565
signals="pct_ed_visits_influenza",
6666
geo_type="state",
67-
report_time_query="<2025-10-16",
67+
report_time="<2025-10-16",
6868
).df()
6969

70-
# Router: pass `report_time_query` (or `snapshot_date="*"`) for archive, `snapshot_date` for snapshot.
70+
# Router: pass `report_time` (or `snapshot_date="*"`) for archive, `snapshot_date` for snapshot.
7171
epidata.epidata(
7272
source="nssp",
7373
signals="pct_ed_visits_influenza",
7474
geo_type="state",
75-
report_time_query=EpiRange("2025-01-01", "2025-10-16"),
75+
report_time=EpiRange("2025-01-01", "2025-10-16"),
7676
).df()
7777
```
7878

79-
`geo_values`, `reference_time`, and an `EpiRange` `report_time_query` lower
79+
`geo_values`, `reference_time`, and an `EpiRange` `report_time` lower
8080
bound are filtered locally after the request.
8181

8282
## Development

epidatpy/_endpoints.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,7 +1534,7 @@ def epidata_snapshot(
15341534
geo_values: StringParam = "*",
15351535
reference_time: EpiRangeParam = "*",
15361536
fill_method: str | None = None,
1537-
snapshot_date: str | date | None = None,
1537+
snapshot_date: str | date | int | None = None,
15381538
) -> CALL_TYPE:
15391539
"""Fetch a snapshot of CAST-API signals as they appeared on `snapshot_date`.
15401540
@@ -1574,16 +1574,16 @@ def epidata_archive(
15741574
geo_values: StringParam = "*",
15751575
reference_time: EpiRangeParam = "*",
15761576
fill_method: str | None = None,
1577-
report_time_query: str | date | EpiRange | None = "*",
1577+
report_time: str | date | EpiRange | None = "*",
15781578
) -> CALL_TYPE:
15791579
"""Fetch the full report-time history of CAST-API signals.
15801580
1581-
`report_time_query` accepts an exact date, an operator-prefixed string
1581+
`report_time` accepts an exact date, an operator-prefixed string
15821582
(e.g. ``"<2025-10-16"``), or an :class:`EpiRange`. ``"*"`` (default)
15831583
requests all report times. `geo_values`, `reference_time`, and the
15841584
EpiRange lower bound are filtered locally after the API call.
15851585
"""
1586-
report_time_query_str = validate_report_time_query(report_time_query)
1586+
report_time_str = validate_report_time_query(report_time)
15871587

15881588
signal_str = signals if isinstance(signals, str) else ",".join(signals)
15891589

@@ -1594,14 +1594,14 @@ def epidata_archive(
15941594
"signal": signal_str,
15951595
"geo_type": geo_type,
15961596
"fill_method": fill_method,
1597-
"report_time_query": report_time_query_str,
1597+
"report_time": report_time_str,
15981598
},
15991599
_cast_signal_fields(),
16001600
api_version="cast",
16011601
post_filter=(
16021602
geo_values,
16031603
reference_time,
1604-
report_time_query if isinstance(report_time_query, EpiRange) else None,
1604+
report_time if isinstance(report_time, EpiRange) else None,
16051605
),
16061606
)
16071607

@@ -1613,28 +1613,28 @@ def epidata(
16131613
geo_values: StringParam = "*",
16141614
reference_time: EpiRangeParam = "*",
16151615
fill_method: str | None = None,
1616-
snapshot_date: str | date | None = None,
1617-
report_time_query: str | date | EpiRange | None = None,
1616+
snapshot_date: str | date | int | None = None,
1617+
report_time: str | date | EpiRange | None = None,
16181618
) -> CALL_TYPE:
16191619
"""Router for CAST-API queries.
16201620
1621-
Dispatches to :meth:`epidata_archive` when ``report_time_query`` is
1621+
Dispatches to :meth:`epidata_archive` when ``report_time`` is
16221622
supplied or ``snapshot_date == "*"``; otherwise to
1623-
:meth:`epidata_snapshot`. ``report_time_query`` and ``snapshot_date``
1623+
:meth:`epidata_snapshot`. ``report_time`` and ``snapshot_date``
16241624
are mutually exclusive.
16251625
"""
1626-
if report_time_query is not None and snapshot_date is not None:
1627-
raise InvalidArgumentException("`report_time_query` and `snapshot_date` are mutually exclusive")
1626+
if report_time is not None and snapshot_date is not None:
1627+
raise InvalidArgumentException("`report_time` and `snapshot_date` are mutually exclusive")
16281628

1629-
if report_time_query is not None or snapshot_date == "*":
1629+
if report_time is not None or snapshot_date == "*":
16301630
return self.epidata_archive(
16311631
source=source,
16321632
signals=signals,
16331633
geo_type=geo_type,
16341634
geo_values=geo_values,
16351635
reference_time=reference_time,
16361636
fill_method=fill_method,
1637-
report_time_query=report_time_query if report_time_query is not None else "*",
1637+
report_time=report_time if report_time is not None else "*",
16381638
)
16391639
return self.epidata_snapshot(
16401640
source=source,

epidatpy/_parse.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,28 +77,31 @@ def parse_user_date_or_week(
7777
raise ValueError(f"Cannot parse date or week from {value}")
7878

7979

80-
def validate_report_time_query(report_time_query: str | int | date | Week | EpiRange | None) -> str | None:
81-
"""Format the `report_time_query` argument for the CAST API `report_time_query` parameter.
80+
def validate_report_time_query(report_time: str | int | date | Week | EpiRange | None) -> str | None:
81+
"""Format the `report_time` argument for the CAST API `report_time` parameter.
8282
8383
Accepts an exact date, an operator-prefixed string (e.g. ``"<2025-10-16"``),
8484
or an :class:`EpiRange` (upper bound becomes ``"<to"``; the lower bound is
8585
filtered locally). Returns ``None`` for ``None`` / ``"*"``.
8686
"""
8787
from ._model import EpiRange # avoid circular import
8888

89-
if report_time_query is None or report_time_query == "*":
89+
if report_time is None or report_time == "*":
9090
return None
9191

9292
operator = "="
9393
raw: str | int | date | Week
94-
if isinstance(report_time_query, str) and report_time_query[:1] in ("<", ">", "="):
95-
operator = report_time_query[0]
96-
raw = report_time_query[1:]
97-
elif isinstance(report_time_query, EpiRange):
94+
if isinstance(report_time, str) and report_time[:2] in ("<=", ">="):
95+
operator = report_time[:2]
96+
raw = report_time[2:]
97+
elif isinstance(report_time, str) and report_time[:1] in ("<", ">", "="):
98+
operator = report_time[0]
99+
raw = report_time[1:]
100+
elif isinstance(report_time, EpiRange):
98101
operator = "<"
99-
raw = report_time_query.end
102+
raw = report_time.end
100103
else:
101-
raw = report_time_query
104+
raw = report_time
102105

103106
parsed: date | None
104107
if isinstance(raw, date):
@@ -109,7 +112,7 @@ def validate_report_time_query(report_time_query: str | int | date | Week | EpiR
109112
parsed = parse_api_date(raw)
110113
if parsed is None:
111114
raise ValueError(
112-
"Invalid `report_time_query` format. Must be a single date, an `EpiRange`, "
115+
"Invalid `report_time` format. Must be a single date, an `EpiRange`, "
113116
"or a string with an operator (e.g., '<2025-10-16')."
114117
)
115118
return f"{operator}{parsed.strftime('%Y-%m-%d')}"

epidatpy/request.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ def with_base_url(self, base_url: str) -> EpiDataCall:
114114
self._session,
115115
self._endpoint,
116116
self._params,
117+
self.meta,
118+
self.only_supports_classic,
119+
self.use_cache,
120+
self.cache_max_age_days,
117121
api_version=self._api_version,
118122
post_filter=self._post_filter,
119123
)
@@ -124,6 +128,10 @@ def with_session(self, session: Session) -> EpiDataCall:
124128
session,
125129
self._endpoint,
126130
self._params,
131+
self.meta,
132+
self.only_supports_classic,
133+
self.use_cache,
134+
self.cache_max_age_days,
127135
api_version=self._api_version,
128136
post_filter=self._post_filter,
129137
)
@@ -276,15 +284,15 @@ def df(
276284
except (ValueError, TypeError):
277285
pass
278286

279-
if self._post_filter is not None:
280-
geo_values, reference_time, report_time = self._post_filter
281-
df = cast_filter(df, geo_values=geo_values, reference_time=reference_time, report_time=report_time)
282-
283287
if self.use_cache:
284288
with Cache(CACHE_DIRECTORY) as cache:
285289
cache_key = self._get_cache_key("df")
286290
cache.set(cache_key, df, expire=self.cache_max_age_days * 24 * 60 * 60)
287291

292+
if self._post_filter is not None:
293+
geo_values, reference_time, report_time = self._post_filter
294+
df = cast_filter(df, geo_values=geo_values, reference_time=reference_time, report_time=report_time)
295+
288296
return df
289297

290298

@@ -311,10 +319,22 @@ def __init__(
311319
self.cache_max_age_days = cache_max_age_days
312320

313321
def with_base_url(self, base_url: str) -> EpiDataContext:
314-
return EpiDataContext(base_url, self._session, cast_base_url=self._cast_base_url)
322+
return EpiDataContext(
323+
base_url,
324+
self._session,
325+
self.use_cache,
326+
self.cache_max_age_days,
327+
cast_base_url=self._cast_base_url,
328+
)
315329

316330
def with_session(self, session: Session) -> EpiDataContext:
317-
return EpiDataContext(self._base_url, session, cast_base_url=self._cast_base_url)
331+
return EpiDataContext(
332+
self._base_url,
333+
session,
334+
self.use_cache,
335+
self.cache_max_age_days,
336+
cast_base_url=self._cast_base_url,
337+
)
318338

319339
def _create_call(
320340
self,

test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def _():
1313
source="nssp",
1414
signals="pct_ed_visits_influenza",
1515
geo_type="state",
16-
report_time_query=EpiRange("2025-01-01", "2025-10-16"),
16+
report_time=EpiRange("2025-01-01", "2025-10-16"),
1717
).df()
1818
return (df,)
1919

tests/test_cast_endpoints.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_epidata_archive(self, source: str, signal: str, geo_type: str) -> None:
6363
assert pd.api.types.is_datetime64_any_dtype(df["report_time"])
6464

6565
def test_epidata_router_dispatch(self) -> None:
66-
# `snapshot_date="*"` routes to archive (no report_time_query sent);
66+
# `snapshot_date="*"` routes to archive (no report_time sent);
6767
# verify the archive's `report_time` column comes back.
6868
ctx = EpiDataContext()
6969
df = ctx.epidata(
@@ -74,14 +74,14 @@ def test_epidata_router_dispatch(self) -> None:
7474
).df()
7575
assert "report_time" in df.columns
7676

77-
def test_epidata_mutually_exclusive_report_time_query_and_snapshot_date(self) -> None:
77+
def test_epidata_mutually_exclusive_report_time_and_snapshot_date(self) -> None:
7878
with pytest.raises(InvalidArgumentException):
7979
EpiDataContext().epidata(
8080
source="nssp",
8181
signals="pct_ed_visits_influenza",
8282
geo_type="state",
8383
snapshot_date="2025-10-16",
84-
report_time_query="2025-10-16",
84+
report_time="2025-10-16",
8585
)
8686

8787
def test_epidata_snapshot_local_filters(self) -> None:

tests/test_parse.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import datetime
2+
3+
import pytest
4+
from epiweeks import Week
5+
6+
from epidatpy._model import EpiRange
7+
from epidatpy._parse import validate_report_time_query
8+
9+
10+
def test_validate_report_time_query_none() -> None:
11+
assert validate_report_time_query(None) is None
12+
assert validate_report_time_query("*") is None
13+
14+
15+
def test_validate_report_time_query_exact() -> None:
16+
assert validate_report_time_query("2025-10-16") == "=2025-10-16"
17+
assert validate_report_time_query(20251016) == "=2025-10-16"
18+
assert validate_report_time_query(datetime.date(2025, 10, 16)) == "=2025-10-16"
19+
assert validate_report_time_query("=2025-10-16") == "=2025-10-16"
20+
21+
22+
def test_validate_report_time_query_week() -> None:
23+
# Week resolves to its start date.
24+
assert validate_report_time_query(Week(2025, 1)) == f"={Week(2025, 1).startdate():%Y-%m-%d}"
25+
26+
27+
def test_validate_report_time_query_operators() -> None:
28+
assert validate_report_time_query("<2025-10-16") == "<2025-10-16"
29+
assert validate_report_time_query(">2025-10-16") == ">2025-10-16"
30+
assert validate_report_time_query("<=2025-10-16") == "<=2025-10-16"
31+
assert validate_report_time_query(">=2025-10-16") == ">=2025-10-16"
32+
33+
34+
def test_validate_report_time_query_epirange() -> None:
35+
# EpiRange upper bound becomes "<to"; lower bound filtered locally.
36+
assert validate_report_time_query(EpiRange(20251001, 20251016)) == "<2025-10-16"
37+
38+
39+
def test_validate_report_time_query_invalid() -> None:
40+
with pytest.raises(ValueError):
41+
validate_report_time_query("not-a-date")
42+
with pytest.raises(ValueError):
43+
validate_report_time_query("<garbage")

0 commit comments

Comments
 (0)