Set slope output units to 'degrees' instead of leaking input units#2904
Merged
Conversation
…2894) slope() returned degrees but copied the input DataArray's attrs verbatim, so a DEM with units='m' produced a slope array still labelled 'm'. That stale label made _infer_vertical_unit_type misclassify slope output as elevation. Override attrs['units'] to 'degrees' in the shared public wrapper (covers numpy, cupy, dask+numpy, dask+cupy and Dataset inputs), preserving all other attrs. Add a verify_attrs passthrough to the cross-backend equality helpers and use it in the slope tests whose attrs now legitimately differ. Add tests asserting the degrees override on every backend and the geodesic path.
brendancol
commented
Jun 3, 2026
Contributor
Author
brendancol
left a comment
There was a problem hiding this comment.
PR Review: Set slope output units to 'degrees' instead of leaking input units
Blockers (must fix before merge)
None.
Suggestions (should fix, not blocking)
- xrspatial/tests/test_slope.py: flipping the existing tests to
verify_attrs=Falsemeans they no longer confirm that the other input attrs (res,crs) surviveslope(). Onlytest_units_overridden_to_degrees_numpychecksres/crspropagation, and only on numpy. Worth having that numpy test assert the non-units attrs explicitly so the propagation contract stays covered now that the blanket attrs check is off.
Nits (optional improvements)
- None.
What looks good
- The override lives in the single shared wrapper, so all four backends and the Dataset path inherit it without per-backend edits. numpy/cupy/dask+numpy/dask+cupy and Dataset all report 'degrees'.
dict(agg.attrs)copies before mutating, so the input DataArray's attrs aren't touched; a test asserts the input still hasunits='m'.- The geodesic path is covered.
- The
verify_attrspassthrough on the shared equality helpers defaults to True, so no other module's tests change behavior.
Checklist
- slope is degrees, units now say degrees
- All implemented backends produce consistent results
- NaN handling unaffected by this change
- Edge cases covered (no-input-units case, geodesic path)
- Dask chunk boundaries unaffected
- No premature materialization or extra copies (one dict copy of attrs)
- Benchmark not needed
- README feature matrix not applicable (no new function)
- Docstring updated to note the units override
brendancol
commented
Jun 3, 2026
Contributor
Author
brendancol
left a comment
There was a problem hiding this comment.
Follow-up review
The one suggestion from the previous pass is addressed: test_units_overridden_to_degrees_dask_numpy now asserts res and crs survive slope() on the dask path, in addition to the numpy test. No blockers, suggestions, or nits remain.
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 #2894
slope()returns degrees but copied the input DataArray's attrs verbatim, so a DEM withunits='m'produced a slope array still labelledunits='m'._infer_vertical_unit_typereads that label and treated the slope output as elevation rather than an angle.Changes
attrs['units']to'degrees'in the shared public wrapper, so the fix applies to all backends and to Dataset inputs. All other input attrs carry through unchanged, and the input array is not mutated.verify_attrspassthrough to the cross-backend equality helpers ingeneral_checks.py; the slope tests whose attrs now legitimately differ passverify_attrs=False.Backend coverage
numpy, cupy, dask+numpy, dask+cupy (attrs are set once in the wrapper).
Test plan
pytest xrspatial/tests/test_slope.py xrspatial/tests/test_geodesic_slope.py(121 passed)