Skip to content

Commit 2171f37

Browse files
authored
Merge pull request #200 from CU-ESIIL/codex/fix-ci-failures-in-scheduled-run
PRISM: accept deprecated `aoi` mapping in loader; add pytest `download` mark
2 parents 3ff0e77 + ccb3430 commit 2171f37

2 files changed

Lines changed: 50 additions & 10 deletions

File tree

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ markers =
33
online: marks tests that require cubo/network access (deselect with '-m "not online"')
44
streaming: marks tests that exercise streaming-first code paths
55
integration: marks tests that hit external services or large data sources
6+
download: tests that download data artifacts
67
pythonpath = src .
78
addopts = -p no:zarr

src/cubedynamics/data/prism.py

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from typing import Hashable, Iterable, Mapping, Sequence
5+
from typing import Any, Hashable, Iterable, Mapping, Sequence
66

77
import warnings
88

@@ -25,6 +25,7 @@ def load_prism_cube(
2525
lat: float | None = None,
2626
lon: float | None = None,
2727
bbox: Sequence[float] | None = None,
28+
aoi: Mapping[str, Any] | None = None,
2829
aoi_geojson: Mapping[str, object] | None = None,
2930
start: str | pd.Timestamp | None = None,
3031
end: str | pd.Timestamp | None = None,
@@ -47,6 +48,9 @@ def load_prism_cube(
4748
fetched for the surrounding area.
4849
bbox : sequence of float, optional
4950
Bounding box defined as ``[min_lon, min_lat, max_lon, max_lat]``.
51+
aoi : mapping, optional
52+
Legacy mapping with ``min_lon``, ``min_lat``, ``max_lon``, and
53+
``max_lat`` keys. Deprecated in favor of ``bbox`` or ``aoi_geojson``.
5054
aoi_geojson : mapping, optional
5155
GeoJSON Feature/FeatureCollection describing the area of interest. A
5256
bounding box is derived from the geometry.
@@ -76,7 +80,8 @@ def load_prism_cube(
7680

7781
if legacy_args:
7882
if any(
79-
value is not None for value in (lat, lon, bbox, aoi_geojson, start, end, freq)
83+
value is not None
84+
for value in (lat, lon, bbox, aoi, aoi_geojson, start, end, freq)
8085
) or variables is not None:
8186
raise TypeError(
8287
"Cannot mix positional PRISM arguments with the keyword-only API."
@@ -112,6 +117,19 @@ def load_prism_cube(
112117
variable_spec = variable
113118
normalized_variables = _normalize_variables(variable_spec)
114119

120+
if aoi is not None:
121+
warnings.warn(
122+
"load_prism_cube(aoi=...) is deprecated; use bbox=(min_lon,min_lat,max_lon,max_lat) "
123+
"or aoi_geojson=... instead.",
124+
DeprecationWarning,
125+
stacklevel=2,
126+
)
127+
if any(value is not None for value in (lat, lon, bbox, aoi_geojson)):
128+
raise ValueError(
129+
"Specify only one AOI via lat/lon, bbox, aoi_geojson, or legacy aoi mapping."
130+
)
131+
bbox = _coerce_legacy_aoi_to_bbox(aoi)
132+
115133
aoi = _coerce_aoi(lat=lat, lon=lon, bbox=bbox, aoi_geojson=aoi_geojson)
116134

117135
return _load_prism_cube_impl(
@@ -258,6 +276,28 @@ def _normalize_variables(variable_spec: Iterable[str] | str) -> Sequence[str]:
258276
return [str(val) for val in values]
259277

260278

279+
def _coerce_legacy_aoi_to_bbox(aoi: Mapping[str, Any]) -> tuple[float, float, float, float]:
280+
if not isinstance(aoi, Mapping):
281+
raise ValueError("Legacy PRISM AOI must be a mapping with bounding box keys.")
282+
required_keys = {"min_lon", "max_lon", "min_lat", "max_lat"}
283+
if not required_keys.issubset(aoi.keys()):
284+
raise ValueError(
285+
"Legacy AOI missing bounding box keys: {0}".format(
286+
", ".join(sorted(required_keys - set(aoi.keys())))
287+
)
288+
)
289+
try:
290+
min_lon = float(aoi["min_lon"])
291+
min_lat = float(aoi["min_lat"])
292+
max_lon = float(aoi["max_lon"])
293+
max_lat = float(aoi["max_lat"])
294+
except (TypeError, ValueError) as exc:
295+
raise ValueError("Legacy PRISM AOI values must be numeric.") from exc
296+
if min_lon >= max_lon or min_lat >= max_lat:
297+
raise ValueError("Legacy PRISM AOI min values must be less than max values.")
298+
return (min_lon, min_lat, max_lon, max_lat)
299+
300+
261301
def _coerce_aoi(
262302
*,
263303
lat: float | None,
@@ -366,14 +406,13 @@ def _flatten_geojson_coords(coords: object) -> list[tuple[float, float]]:
366406
def _coerce_legacy_aoi(aoi: object) -> Mapping[str, float]:
367407
if not isinstance(aoi, Mapping):
368408
raise ValueError("Legacy PRISM AOI must be a mapping with bounding box keys.")
369-
required_keys = {"min_lon", "max_lon", "min_lat", "max_lat"}
370-
if not required_keys.issubset(aoi.keys()):
371-
raise ValueError(
372-
"Legacy AOI missing bounding box keys: {0}".format(
373-
", ".join(sorted(required_keys - set(aoi.keys())))
374-
)
375-
)
376-
return {key: float(aoi[key]) for key in required_keys}
409+
min_lon, min_lat, max_lon, max_lat = _coerce_legacy_aoi_to_bbox(aoi)
410+
return {
411+
"min_lon": min_lon,
412+
"min_lat": min_lat,
413+
"max_lon": max_lon,
414+
"max_lat": max_lat,
415+
}
377416

378417

379418
def _open_prism_streaming(

0 commit comments

Comments
 (0)