Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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