Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude/sweep-error-handling-state.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module,last_inspected,issue,severity_max,categories_found,notes
bump,2026-07-02,,HIGH,1;2;3;4,"bump() agg template unvalidated: plain ndarray -> ArrayTypeFunctionMapping 'Unsupported Array Type'; 3D/1D DataArray -> 'too many values to unpack'. count/spread unvalidated (internal numpy errors / silent). Added _validate_raster(agg,ndim=2) + _validate_scalar for count,spread. all 4 backends verified (CUDA present)."
9 changes: 9 additions & 0 deletions xrspatial/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class cupy(object):

from xrspatial.utils import (
ArrayTypeFunctionMapping,
_validate_raster,
_validate_scalar,
has_cuda_and_cupy,
is_cupy_array,
Expand Down Expand Up @@ -331,7 +332,15 @@ def heights(locations, src, src_range, height = 20):
Description: Example Bump Map
units: km
"""
_validate_scalar(spread, func_name='bump', name='spread',
dtype=int, min_val=0)
if count is not None:
_validate_scalar(count, func_name='bump', name='count',
dtype=int, min_val=0)

if agg is not None:
_validate_raster(agg, func_name='bump', name='agg', ndim=2,
numeric=False)
h, w = agg.shape
else:
_validate_scalar(width, func_name='bump', name='width',
Expand Down
51 changes: 51 additions & 0 deletions xrspatial/tests/test_bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,54 @@ def test_bump_dask_bypasses_raster_guard():
result = bump(agg=agg, count=10, spread=0)
assert result.shape == (100_000, 100_000)
assert isinstance(result.data, da.Array)


# --- Input-validation regression tests ---

def test_bump_agg_must_be_dataarray():
"""A plain ndarray template raises a clear TypeError naming `agg`,
not an inscrutable 'Unsupported Array Type' from the dispatcher."""
import pytest

with pytest.raises(TypeError, match=r"bump\(\): `agg` must be an "
r"xarray\.DataArray"):
bump(agg=np.zeros((10, 10)))


def test_bump_agg_must_be_2d():
"""A 3D or 1D template raises a clear ValueError naming `agg` and the
2D requirement, not 'too many values to unpack'."""
import pytest

with pytest.raises(ValueError, match=r"bump\(\): `agg` must be 2D"):
bump(agg=xr.DataArray(np.zeros((3, 10, 10)), dims=['b', 'y', 'x']))
with pytest.raises(ValueError, match=r"bump\(\): `agg` must be 2D"):
bump(agg=xr.DataArray(np.zeros(10), dims=['x']))


def test_bump_count_validated():
"""`count` gets the same clean validation as width/height instead of
surfacing raw numpy errors."""
import pytest

with pytest.raises(ValueError, match=r"bump\(\): `count` must be >= 0"):
bump(width=10, height=10, count=-5)
with pytest.raises(TypeError, match=r"bump\(\): `count` must be int"):
bump(width=10, height=10, count=5.0)


def test_bump_spread_validated():
"""`spread` is documented as int; negative and non-int values raise
instead of being silently ignored."""
import pytest

with pytest.raises(ValueError, match=r"bump\(\): `spread` must be >= 0"):
bump(width=10, height=10, spread=-3)
with pytest.raises(TypeError, match=r"bump\(\): `spread` must be int"):
bump(width=10, height=10, spread=2.5)


def test_bump_spread_zero_still_allowed():
"""spread=0 (single-pixel bumps) must remain valid."""
result = bump(width=10, height=10, count=5, spread=0)
assert result.shape == (10, 10)
Loading