Validate viewshed max_distance (reject negative / non-finite)#2874
Merged
Conversation
…#2855) A negative, NaN, or infinite max_distance fell through the windowing math and raised confusing internal errors that never mentioned the argument. Validate at the public viewshed() entry point, before backend dispatch, so all four backends are covered, and raise a clear ValueError. Add tests for the rejected values and confirm finite values >= 0 still work.
brendancol
commented
Jun 2, 2026
Contributor
Author
brendancol
left a comment
There was a problem hiding this comment.
PR Review: Validate viewshed max_distance (reject negative / non-finite)
Blockers (must fix before merge)
None.
Suggestions (should fix, not blocking)
None.
Nits (optional improvements)
- xrspatial/viewshed.py:1721 and 1729: there are now two back-to-back
if max_distance is not None:blocks. You could fold the validation into the existing block, but keeping them separate reads fine too (validation first, windowing dispatch under its own comment). Optional.
What looks good
- Validation sits at the public entry point before backend dispatch, so all four backends (numpy, cupy, dask+numpy, dask+cupy) are covered by one check. The test docstring spells out that reasoning.
- The error message names the argument and echoes the bad value, which is the point of the fix.
- The
try/except (TypeError, ValueError)also turns a non-numericmax_distanceinto the same clear message instead of a rawnp.isfiniteTypeError. - Tests cover -1.0, -0.5, NaN, +inf, -inf and confirm 0.0 and 3.0 still work on numpy and dask.
- Docstring updated to state the contract.
Checklist
- Validation runs before dispatch, so all backends behave the same
- NaN / inf / negative handled with a clear ValueError
- Edge cases (0.0, +inf, -inf, non-numeric) covered
- No new materialization or copies
- No new public API, so README matrix and user guide are not needed
- Docstring present and accurate
Address review nit: merge the two consecutive 'if max_distance is not None' blocks so the check and the windowed dispatch share one branch.
brendancol
commented
Jun 2, 2026
Contributor
Author
brendancol
left a comment
There was a problem hiding this comment.
Follow-up review (after 9104c38)
The one nit from the first pass is resolved: the validation and the windowed dispatch now share a single if max_distance is not None: branch (xrspatial/viewshed.py:1721). Behavior is unchanged and the 24 max_distance tests still pass.
No remaining Blockers, Suggestions, or Nits.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2855
viewshed()didn't validatemax_distance. Negative, NaN, and infinitevalues fell through to the windowing math and raised internal errors that
never mentioned the argument (for example "zero-size array to reduction
operation minimum" for -1.0 and "cannot convert float NaN to integer" for
NaN).
What changed:
max_distanceat the publicviewshed()entry point, beforebackend dispatch, and raise
ValueError("max_distance must be a finite number >= 0, ...")for negative or non-finite values.max_distanceparameter.Backend coverage: the check runs before dispatch, so it applies to all
four backends (numpy, cupy, dask+numpy, dask+cupy).
Test plan:
ValueErrorfor -1.0, -0.5, NaN, +inf, -inf.test_viewshed.pypasses (72 passed, 1 xfailed).Skipped the user-guide-notebook and README-matrix steps: this is a pure
input-validation bug fix with no new public API and no change to backend
support.