Skip to content

Commit 1dd136f

Browse files
committed
fix(nwis): handle empty peaks response instead of raising KeyError
nwis.get_discharge_peaks / get_record(service="peaks") against a site with no annual-peak data returns a peaks RDB body of comment lines only, which read_rdb parses to a column-less empty DataFrame. format_response runs preformat_peaks_response before its own empty-frame check, and that function's first statement pops "peak_dt", so the empty case raised KeyError('peak_dt') instead of returning an empty frame. This is the same empty-result contract fixed for the other services in issue #171; peaks was missed because it is preformatted first. Return the frame unchanged when peak_dt is absent so the empty-frame path in format_response handles it and callers can check df.empty. Adds a regression test alongside the existing #171 coverage. Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
1 parent 6baa4ab commit 1dd136f

2 files changed

Lines changed: 25 additions & 0 deletions

File tree

dataretrieval/nwis.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,13 @@ def preformat_peaks_response(df: pd.DataFrame) -> pd.DataFrame:
196196
The formatted data frame
197197
198198
"""
199+
if "peak_dt" not in df.columns:
200+
# An empty peaks response (e.g. "No sites found") parses to a
201+
# column-less frame, so there is no peak_dt to reformat. Return it
202+
# unchanged and let format_response's empty-frame path handle it,
203+
# matching how the other services treat empty results (issue #171).
204+
return df
205+
199206
df["datetime"] = pd.to_datetime(df.pop("peak_dt"), errors="coerce")
200207
df.dropna(subset=["datetime"], inplace=True)
201208
return df

tests/nwis_test.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from dataretrieval.nwis import (
1212
NWIS_Metadata,
1313
_read_rdb,
14+
format_response,
1415
get_discharge_measurements,
1516
get_gwlevels,
1617
get_iv,
@@ -303,3 +304,20 @@ def test_no_sites_flows_through_format_response(self):
303304
df = _read_rdb(no_sites_rdb)
304305
assert isinstance(df, pd.DataFrame)
305306
assert df.empty
307+
308+
def test_no_peaks_flows_through_format_response(self):
309+
"""The 'peaks' service takes an extra formatting step
310+
(preformat_peaks_response) before the empty-frame check, so an empty
311+
peaks response has to survive that too. Previously this raised
312+
KeyError('peak_dt'); now it returns an empty frame like the other
313+
services (same empty-result contract as issue #171).
314+
"""
315+
no_peaks_rdb = (
316+
"# //Output-Format: RDB\n"
317+
"# //Response-Status: OK\n"
318+
"# //Response-Message: No sites found matching all criteria\n"
319+
)
320+
df = _read_rdb(no_peaks_rdb)
321+
df = format_response(df, service="peaks")
322+
assert isinstance(df, pd.DataFrame)
323+
assert df.empty

0 commit comments

Comments
 (0)