resample: reject empty rasters with a clear ValueError#2665
Merged
Conversation
Dedupe duplicate module rows (last-write-wins by last_inspected) and collapse multi-line notes to single physical lines. The notes had embedded newlines, which the merge=union .gitattributes strategy splits record-by-record, corrupting the file into a 156-column phantom row on parallel-agent appends. One line per record keeps union merges safe.
brendancol
commented
May 29, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
PR Review: resample: reject empty rasters with a clear ValueError
Blockers (must fix before merge)
None.
Suggestions (should fix, not blocking)
None.
Nits (optional improvements)
- The PR diff shows
.claude/sweep-test-coverage-state.csvas changed, but that is a stale-base artifact: the branch forked from 0f8df57 and origin/main has since advanced past it. The fix commit only touches resample.py and the test file. Merging main into the branch in the conflict-resolution step clears it from the diff. - The
resampledocstring's Raises section did not mention the empty-raster case. Documented it in a follow-up commit so the new ValueError condition is listed alongside the others.
What looks good
- The guard sits right after
_validate_raster()and before any scale math, so the error is raised up front as intended (resample.py:1329-1333). - Negative indexing (
shape[-2],shape[-1]) targets the spatial axes correctly for both 2D and 3D input, so the 3D per-band path is covered too. - The new check does not overlap with the existing
target_resolutionminimum-size guard at resample.py:1359; that path keeps its own stricter "at least 2 pixels" message for 1-row/1-col input. - The error message names the parameter and reports the actual shape, matching the style of the surrounding validation messages.
- The coverage tests now assert ValueError specifically with a message match, closing the IndexError-or-ValueError loophole.
Checklist
- Algorithm matches reference/paper: n/a (input validation)
- All implemented backends produce consistent results: validation runs on the public entry point before backend dispatch, so it applies to all four backends
- NaN handling is correct: n/a
- Edge cases are covered by tests: zero rows and zero cols both tested
- Dask chunk boundaries handled correctly: n/a (guard runs before dispatch)
- No premature materialization: the check reads only
agg.shape - Benchmark exists or is not needed: not needed (validation)
- README feature matrix updated: not needed (no new function)
- Docstrings present and accurate: yes (Raises section now lists the empty-raster case)
brendancol
commented
May 29, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
Follow-up review (post-fix)
Both nits from the first pass are resolved.
Disposition
- Stale CSV artifact: fixed. Merged origin/main, then realigned
.claude/sweep-test-coverage-state.csvto main's version so the PR diff carries only the code change. The diff now listsxrspatial/resample.pyandxrspatial/tests/test_resample_coverage_2026_05_27.pyonly. - Docstring gap: fixed. The
resampleRaises section now lists the zero-length spatial dimension case.
Verification
- flake8 clean on both changed files.
- 295 tests pass across
test_resample_coverage_2026_05_27.pyandtest_resample.py, including the twoTestEmptyRasterRejectedcases that now assert ValueError with a message match. - PR reports MERGEABLE with no conflicts against main.
No remaining blockers, suggestions, or open nits.
# Conflicts: # xrspatial/resample.py
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 #2661
resample()validated dimensionality and dtype but never checked for zero-sized spatial axes. On thescale_factorpath, an empty raster (0 rows or 0 columns) reached the output-coordinate rebuild and surfaced an opaqueIndexErrorinstead of a clear error. Thetarget_resolutionpath already had a minimum-size guard; thescale_factorpath did not.Changes:
resample()right after_validate_raster(), raising a clearValueErrorthat names the parameter and reports the shape. The guard runs before any scale math, so it covers both thescale_factorandtarget_resolutionpaths.TestEmptyRasterRejectedcoverage tests to expectValueErrorspecifically (with a message match) instead of accepting eitherIndexErrororValueError.Backend coverage: the validation runs on the public entry point before backend dispatch, so it applies to all four backends (numpy, cupy, dask+numpy, dask+cupy).
Test plan:
TestEmptyRasterRejectedpasses (zero rows and zero cols)