Skip to content

Fix cupy zonal_stats silently ignoring nodata_values=0 (#1227)#1228

Merged
brendancol merged 1 commit into
masterfrom
issue-1227
Apr 22, 2026
Merged

Fix cupy zonal_stats silently ignoring nodata_values=0 (#1227)#1228
brendancol merged 1 commit into
masterfrom
issue-1227

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

Fixes #1227. _stats_cupy used if nodata_values: to decide whether to apply the nodata filter. That's a truthiness check, so nodata_values=0 (a common sentinel for integer rasters) fell through the else branch and zeros were never dropped. Every other backend uses if nodata_values is not None:.

So zonal_stats(..., nodata_values=0) on a cupy DataArray returned different numbers than on numpy, dask+numpy, or dask+cupy, silently.

The fix

One-line change at xrspatial/zonal.py:547: is not None, to match the rest of the module.

Test coverage

Added test_stats_nodata_values_zero_across_backends_1227. It builds zones with one zero cell per zone that should be filtered out, runs stats(..., nodata_values=0, stats_funcs=['mean', 'sum', 'count']) on all four backends, and asserts the results match.

Before the fix the cupy case returns mean=[7.5, 15.0]; after, [10.0, 20.0] like the other backends.

Security sweep state

Added a zonal entry to .claude/sweep-security-state.json covering this HIGH finding and the MEDIUMs I didn't fix (int32 stride overflow in _strides, no _validate_raster call in hypsometric_integral, no memory guard on the numpy path of _regions_numpy).

Test plan

  • New regression test passes on all four backends locally
  • pytest xrspatial/tests/test_zonal.py fully passes (125 tests)
  • Confirmed the test fails without the fix (catches the exact bug)

`_stats_cupy` used `if nodata_values:` so passing 0 (a common
sentinel) fell through the else branch and kept the zero cells
in. Every other backend uses `is not None` and dropped them,
so the same call gave different answers depending on where it
ran.

Switch to `is not None`. Adds a regression test that runs the
same input through all four backends and asserts the results
match, plus a zonal entry in the security-sweep state file.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Apr 22, 2026
@brendancol brendancol merged commit 31fbe62 into master Apr 22, 2026
11 checks passed
@brendancol brendancol deleted the issue-1227 branch April 25, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zonal_stats cupy backend silently ignores nodata_values=0

1 participant