Skip to content

Commit dd5e00e

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix/stats-pagination
# Conflicts: # tests/waterdata_utils_test.py
2 parents af00705 + 98b3057 commit dd5e00e

5 files changed

Lines changed: 71 additions & 24 deletions

File tree

dataretrieval/nldi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ def _validate_data_source(data_source: str):
486486
def _validate_navigation_mode(navigation_mode: str):
487487
navigation_mode = navigation_mode.upper()
488488
if navigation_mode not in ("UM", "DM", "UT", "DD"):
489-
raise TypeError(f"Invalid navigation mode '{navigation_mode}'")
489+
raise ValueError(f"Invalid navigation mode '{navigation_mode}'")
490490

491491

492492
def _validate_feature_source_comid(

dataretrieval/waterdata/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -905,11 +905,13 @@ def _handle_stats_nesting(
905905
# otherwise return a geodataframe
906906
if not geopd:
907907
df = pd.json_normalize(body["features"]).drop(
908-
columns=["type", "properties.data"]
908+
columns=["type", "properties.data"], errors="ignore"
909909
)
910910
df.columns = df.columns.str.split(".").str[-1]
911911
else:
912-
df = gpd.GeoDataFrame.from_features(body["features"]).drop(columns=["data"])
912+
df = gpd.GeoDataFrame.from_features(body["features"]).drop(
913+
columns=["data"], errors="ignore"
914+
)
913915

914916
# Unnest json features, properties, data, and values while retaining necessary
915917
# metadata to merge with main dataframe.

dataretrieval/wqp.py

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -127,31 +127,23 @@ def get_results(
127127
kwargs = _check_kwargs(kwargs)
128128

129129
if legacy is True:
130-
if (
131-
"dataProfile" in kwargs
132-
and kwargs["dataProfile"] not in result_profiles_legacy
133-
):
134-
raise TypeError(
135-
f"dataProfile {kwargs['dataProfile']} is not a legacy profile.",
136-
f"Valid options are {result_profiles_legacy}.",
137-
)
138-
130+
valid_profiles = result_profiles_legacy
131+
kind = "legacy"
139132
url = wqp_url("Result")
140-
141133
else:
142-
if (
143-
"dataProfile" in kwargs
144-
and kwargs["dataProfile"] not in result_profiles_wqx3
145-
):
146-
raise TypeError(
147-
f"dataProfile {kwargs['dataProfile']} is not a valid WQX3.0"
148-
f"profile. Valid options are {result_profiles_wqx3}.",
149-
)
150-
else:
151-
kwargs["dataProfile"] = "fullPhysChem"
152-
134+
valid_profiles = result_profiles_wqx3
135+
kind = "WQX3.0"
153136
url = wqx3_url("Result")
154137

138+
profile = kwargs.get("dataProfile")
139+
if profile is not None and profile not in valid_profiles:
140+
raise ValueError(
141+
f"dataProfile {profile!r} is not a valid {kind} profile. "
142+
f"Valid options are {valid_profiles}."
143+
)
144+
if legacy is not True and profile is None:
145+
kwargs["dataProfile"] = "fullPhysChem"
146+
155147
response = query(url, kwargs, delimiter=";", ssl_check=ssl_check)
156148

157149
df = pd.read_csv(StringIO(response.text), delimiter=",", low_memory=False)

tests/waterdata_utils_test.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from dataretrieval.waterdata.utils import (
88
GEOPANDAS,
99
_get_args,
10+
_handle_stats_nesting,
1011
_walk_pages,
1112
get_stats_data,
1213
)
@@ -250,3 +251,33 @@ def test_get_stats_data_preserves_geometry_across_pages():
250251
assert isinstance(df, gpd.GeoDataFrame)
251252
assert len(df) == 2
252253
assert df.geometry.notna().all()
254+
255+
256+
def test_handle_stats_nesting_tolerates_missing_drop_columns():
257+
"""If the upstream stats response shape ever changes such that one of
258+
the columns we try to drop ("type", "properties.data") is absent, the
259+
function should still return a DataFrame instead of raising KeyError.
260+
"""
261+
body = {
262+
"next": None,
263+
"features": [
264+
{
265+
"properties": {
266+
"monitoring_location_id": "USGS-12345",
267+
"data": [
268+
{
269+
"parameter_code": "00060",
270+
"unit_of_measure": "ft^3/s",
271+
"parent_time_series_id": "ts-1",
272+
"values": [{"statistic_id": "mean", "value": 10.0}],
273+
}
274+
],
275+
},
276+
}
277+
],
278+
}
279+
280+
df = _handle_stats_nesting(body, geopd=False)
281+
282+
assert len(df) == 1
283+
assert df["monitoring_location_id"].iloc[0] == "USGS-12345"

tests/wqp_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,25 @@ def test_check_kwargs():
216216
kwargs = {"mimeType": "foo"}
217217
with pytest.raises(ValueError):
218218
kwargs = _check_kwargs(kwargs)
219+
220+
221+
def test_get_results_wqx3_preserves_user_dataProfile(requests_mock):
222+
"""A valid user-supplied WQX3.0 profile must not be overwritten.
223+
224+
Regression: previously the `else` branch of the `dataProfile` validation
225+
triggered whenever the value was *not invalid*, including any valid
226+
user-supplied profile, silently overwriting it with 'fullPhysChem'.
227+
"""
228+
request_url = (
229+
"https://www.waterqualitydata.us/wqx3/Result/search?"
230+
"siteid=UTAHDWQ_WQX-4993795&mimeType=csv&dataProfile=narrow"
231+
)
232+
response_file_path = "tests/data/wqp3_results.txt"
233+
mock_request(requests_mock, request_url, response_file_path)
234+
235+
df, _md = get_results(
236+
legacy=False, siteid="UTAHDWQ_WQX-4993795", dataProfile="narrow"
237+
)
238+
assert isinstance(df, DataFrame)
239+
sent = requests_mock.request_history[-1]
240+
assert sent.qs.get("dataprofile") == ["narrow"]

0 commit comments

Comments
 (0)