Description
The two public convolution entry points in xrspatial/convolution.py do not validate their inputs, so bad arguments either raise an error the caller cannot map back to what they passed, or produce a wrong result with no error at all.
convolve_2d validates the raster but never the kernel:
- A non-array kernel (list),
None, or a 1D/3D array reaches the numba kernel and raises a TypingError naming a "reflected list" or "type none", internals the caller has no handle on.
- An even-sided kernel (for example
np.ones((2, 2))) is accepted silently and returns an off-center result with no error, even though custom_kernel already rejects even kernels as "improper dimensions". Same module, two different contracts.
convolution_2d never checks that agg is a DataArray. Passing a numpy array fails at agg.data with AttributeError: 'memoryview' object has no attribute 'astype', which points at an attribute the caller never touched.
Reproduction
import numpy as np
from xrspatial.convolution import convolve_2d, convolution_2d
data = np.arange(64, dtype=float).reshape(8, 8)
convolve_2d(data, [[0, 1, 0], [1, 1, 1], [0, 1, 0]]) # list -> numba TypingError
convolve_2d(data, None) # -> numba TypingError
convolve_2d(data, np.ones((2, 2))) # even sided -> silently off-center, no error
convolution_2d(data, np.ones((3, 3))) # numpy agg -> AttributeError on .astype
Fix
Add a _validate_kernel helper (2D, odd side lengths, duck-typed on ndim/shape so numpy and cupy kernels both pass) and call it from convolve_2d; add a _validate_raster call in convolution_2d. Even-sided kernels now raise, matching custom_kernel's long-standing odd-shape contract. Internal callers (focal, edge_detection, emerging_hotspots) all pass odd 2D arrays, so they are unaffected.
Description
The two public convolution entry points in
xrspatial/convolution.pydo not validate their inputs, so bad arguments either raise an error the caller cannot map back to what they passed, or produce a wrong result with no error at all.convolve_2dvalidates the raster but never the kernel:None, or a 1D/3D array reaches the numba kernel and raises aTypingErrornaming a "reflected list" or "type none", internals the caller has no handle on.np.ones((2, 2))) is accepted silently and returns an off-center result with no error, even thoughcustom_kernelalready rejects even kernels as "improper dimensions". Same module, two different contracts.convolution_2dnever checks thataggis a DataArray. Passing a numpy array fails atagg.datawithAttributeError: 'memoryview' object has no attribute 'astype', which points at an attribute the caller never touched.Reproduction
Fix
Add a
_validate_kernelhelper (2D, odd side lengths, duck-typed onndim/shapeso numpy and cupy kernels both pass) and call it fromconvolve_2d; add a_validate_rastercall inconvolution_2d. Even-sided kernels now raise, matchingcustom_kernel's long-standing odd-shape contract. Internal callers (focal, edge_detection, emerging_hotspots) all pass odd 2D arrays, so they are unaffected.