From 59fb297c73cb439cd345fa2ca9d1cd1211fcfefa Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Fri, 6 Nov 2026 10:19:07 -0500 Subject: [PATCH 1/2] Remove the deprecated use_cuda, src_/tgt_vertical_crs and criterion_weights aliases (#3763) --- xrspatial/mcda/combine.py | 24 +--------- xrspatial/polygon_clip.py | 6 +-- xrspatial/rasterize.py | 21 --------- xrspatial/reproject/__init__.py | 46 ------------------- xrspatial/tests/test_mcda.py | 19 ++------ .../test_rasterize_coverage_2026_06_09.py | 4 +- .../tests/test_rasterize_geom_crs_3087.py | 4 +- .../tests/test_rasterize_gpu_alias_3089.py | 45 +++++------------- .../test_rasterize_nonfinite_burn_3085.py | 4 +- .../test_rasterize_nonfinite_burn_3088.py | 4 +- xrspatial/tests/test_reproject.py | 42 +++++------------ 11 files changed, 36 insertions(+), 183 deletions(-) diff --git a/xrspatial/mcda/combine.py b/xrspatial/mcda/combine.py index e13957cee..25b9deabf 100644 --- a/xrspatial/mcda/combine.py +++ b/xrspatial/mcda/combine.py @@ -6,7 +6,6 @@ from __future__ import annotations -import warnings import numpy as np import xarray as xr @@ -253,11 +252,9 @@ def wpm( def owa( criteria: xr.Dataset, - weights: dict[str, float] | None = None, + weights: dict[str, float], order_weights: list[float] | None = None, name: str = "owa", - *, - criterion_weights: dict[str, float] | None = None, ) -> xr.DataArray: """Ordered Weighted Averaging. @@ -272,37 +269,18 @@ def owa( weights : dict Criterion weights as ``{criterion_name: weight}``, must sum to ~1.0. Same convention as :func:`wlc` and :func:`wpm`. - Required; the ``None`` default exists only to support the - deprecated ``criterion_weights`` alias. order_weights : list of float Weights applied by rank position (index 0 = highest value). Must have the same length as the number of criteria and sum to ~1.0. name : str Name of the output DataArray. - criterion_weights : dict, optional - Deprecated alias for ``weights``. Emits ``DeprecationWarning``. Returns ------- xr.DataArray Composite suitability surface. """ - if criterion_weights is not None: - if weights is not None: - raise TypeError( - "owa() got values for both 'weights' and its deprecated " - "alias 'criterion_weights'" - ) - warnings.warn( - "The 'criterion_weights' argument of owa() is deprecated; " - "use 'weights' instead.", - DeprecationWarning, - stacklevel=2, - ) - weights = criterion_weights - if weights is None: - raise TypeError("owa() missing required argument: 'weights'") if order_weights is None: raise TypeError("owa() missing required argument: 'order_weights'") diff --git a/xrspatial/polygon_clip.py b/xrspatial/polygon_clip.py index f916b6a19..095b1ec05 100644 --- a/xrspatial/polygon_clip.py +++ b/xrspatial/polygon_clip.py @@ -220,11 +220,7 @@ def clip_polygon( # the task graph that xarray.where then has to align (#3191). kw.setdefault('chunks', (max(rc), max(cc))) if has_cuda_and_cupy() and is_dask_cupy(raster): - # Respect a legacy ``use_cuda`` passed via rasterize_kw -- - # defaulting ``gpu`` as well would make rasterize() see both - # names and raise. - if 'use_cuda' not in kw: - kw.setdefault('gpu', True) + kw.setdefault('gpu', True) mask = rasterize(geom_pairs, **kw) diff --git a/xrspatial/rasterize.py b/xrspatial/rasterize.py index 7aa6185e5..c7315d9bc 100644 --- a/xrspatial/rasterize.py +++ b/xrspatial/rasterize.py @@ -4139,7 +4139,6 @@ def rasterize( chunks: Optional[Union[int, Tuple[int, int]]] = None, max_pixels: int = MAX_PIXELS_DEFAULT, check_crs: bool = True, - use_cuda: Optional[bool] = None, ) -> xr.DataArray: """Rasterize vector geometries into a 2D DataArray. @@ -4337,10 +4336,6 @@ def rasterize( them yourself to match the template. Pass ``check_crs=False`` to skip the comparison (the output still inherits the template CRS). The check is a no-op when either side lacks a CRS. - use_cuda : bool, optional - Deprecated alias for ``gpu``; emits a ``DeprecationWarning`` - when passed. Passing both ``gpu=True`` and ``use_cuda`` raises - ``TypeError``. Returns ------- @@ -4374,22 +4369,6 @@ def rasterize( >>> density = rasterize(gdf, width=100, height=100, ... column='pop', merge='sum', fill=0) """ - # Deprecation shim: ``use_cuda`` was renamed to ``gpu`` so the GPU - # opt-in matches ``open_geotiff(gpu=True)`` (issue #3089). The old - # keyword still works but warns; asking for both is ambiguous. - if use_cuda is not None: - if gpu: - raise TypeError( - "rasterize() got both 'gpu' and its deprecated alias " - "'use_cuda'; pass only 'gpu'") - warnings.warn( - "rasterize(use_cuda=...) is deprecated; use gpu=... instead " - "(same convention as open_geotiff).", - DeprecationWarning, - stacklevel=2, - ) - gpu = use_cuda - # Fail early with a clear message if the optional ``vector`` extra # (shapely) is not installed, rather than deep inside a helper. _require_shapely() diff --git a/xrspatial/reproject/__init__.py b/xrspatial/reproject/__init__.py index c9c22ec92..250e39ae3 100644 --- a/xrspatial/reproject/__init__.py +++ b/xrspatial/reproject/__init__.py @@ -67,34 +67,6 @@ 'ellipsoidal': 4979, # WGS 84 (3D, ellipsoidal height) } -# Sentinel marking the deprecated ``src_vertical_crs`` / ``tgt_vertical_crs`` -# kwargs as "not passed". Distinct from None so we can tell an explicit -# ``src_vertical_crs=None`` apart from the default and only warn when the -# caller actually used the old name. -_DEPRECATED = object() - - -def _resolve_deprecated_vertical_kwarg(old_name, old_val, new_name, new_val): - """Map a deprecated vertical-CRS kwarg onto its renamed replacement. - - Emits a ``DeprecationWarning`` when the old name is used and rejects - passing both the old and new spellings at once. - """ - if old_val is _DEPRECATED: - return new_val - import warnings - warnings.warn( - f"reproject(): {old_name!r} is deprecated, use {new_name!r} instead.", - DeprecationWarning, - stacklevel=3, - ) - if new_val is not None: - raise TypeError( - f"reproject(): pass either {new_name!r} or the deprecated " - f"{old_name!r}, not both." - ) - return old_val - def _find_spatial_dims(raster): """Find the y and x dimension names, handling multi-band rasters. @@ -725,8 +697,6 @@ def reproject( source_vertical_crs=None, target_vertical_crs=None, bounds_policy="auto", - src_vertical_crs=_DEPRECATED, - tgt_vertical_crs=_DEPRECATED, ): """Reproject a raster DataArray to a new coordinate reference system. @@ -788,12 +758,6 @@ def reproject( target_vertical_crs : str or None Target vertical datum. Same options as *source_vertical_crs*. Both must be set to trigger a vertical transformation. - src_vertical_crs : str or None - Deprecated alias for *source_vertical_crs*. Passing it emits a - ``DeprecationWarning``. - tgt_vertical_crs : str or None - Deprecated alias for *target_vertical_crs*. Passing it emits a - ``DeprecationWarning``. bounds_policy : {"auto", "raw", "clamp", "percentile"}, default "auto" How to derive the output extent from the source extent when ``bounds`` is not supplied. Only relevant when projecting near a @@ -868,16 +832,6 @@ def reproject( >>> result.attrs['crs'].startswith(('PROJCRS', 'PROJCS')) True """ - # Back-compat shim for the old abbreviated kwarg names. These were - # renamed to source_vertical_crs / target_vertical_crs to match the - # source_crs / target_crs spelling used by the rest of the signature. - source_vertical_crs = _resolve_deprecated_vertical_kwarg( - 'src_vertical_crs', src_vertical_crs, - 'source_vertical_crs', source_vertical_crs) - target_vertical_crs = _resolve_deprecated_vertical_kwarg( - 'tgt_vertical_crs', tgt_vertical_crs, - 'target_vertical_crs', target_vertical_crs) - _validate_raster(raster, func_name='reproject', name='raster', ndim=(2, 3)) diff --git a/xrspatial/tests/test_mcda.py b/xrspatial/tests/test_mcda.py index 0ba2187c1..71e81386f 100644 --- a/xrspatial/tests/test_mcda.py +++ b/xrspatial/tests/test_mcda.py @@ -2391,8 +2391,8 @@ def test_error_message_names_dimensions_and_count( class TestOWAWeightsParam3148: - """owa() takes its criterion-weight dict as `weights` like wlc/wpm, - with `criterion_weights` kept as a deprecated alias.""" + """owa() takes its criterion-weight dict as `weights` like wlc/wpm. + The `criterion_weights` alias was removed in 1.0.0 (#3763).""" def test_weights_keyword(self, criteria_dataset, weights_3): result = owa( @@ -2401,21 +2401,10 @@ def test_weights_keyword(self, criteria_dataset, weights_3): expected = owa(criteria_dataset, weights_3, [0.5, 0.3, 0.2]) np.testing.assert_allclose(result.values, expected.values) - def test_criterion_weights_deprecated(self, criteria_dataset, weights_3): - with pytest.warns(DeprecationWarning, match="criterion_weights"): - result = owa( - criteria_dataset, - criterion_weights=weights_3, - order_weights=[0.5, 0.3, 0.2], - ) - expected = owa(criteria_dataset, weights_3, [0.5, 0.3, 0.2]) - np.testing.assert_allclose(result.values, expected.values) - - def test_both_names_raise(self, criteria_dataset, weights_3): - with pytest.raises(TypeError, match="both"): + def test_criterion_weights_removed(self, criteria_dataset, weights_3): + with pytest.raises(TypeError, match="criterion_weights"): owa( criteria_dataset, - weights=weights_3, criterion_weights=weights_3, order_weights=[0.5, 0.3, 0.2], ) diff --git a/xrspatial/tests/test_rasterize_coverage_2026_06_09.py b/xrspatial/tests/test_rasterize_coverage_2026_06_09.py index 4cec975b5..6722aeb33 100644 --- a/xrspatial/tests/test_rasterize_coverage_2026_06_09.py +++ b/xrspatial/tests/test_rasterize_coverage_2026_06_09.py @@ -80,10 +80,10 @@ def _materialise(result): _BACKENDS = [ pytest.param('numpy', {}, id='numpy'), - pytest.param('cupy', {'use_cuda': True}, marks=skip_no_cuda, id='cupy'), + pytest.param('cupy', {'gpu': True}, marks=skip_no_cuda, id='cupy'), pytest.param('dask_numpy', {'chunks': (3, 3)}, marks=skip_no_dask, id='dask_numpy'), - pytest.param('dask_cupy', {'use_cuda': True, 'chunks': (3, 3)}, + pytest.param('dask_cupy', {'gpu': True, 'chunks': (3, 3)}, marks=[skip_no_cuda, skip_no_dask], id='dask_cupy'), ] diff --git a/xrspatial/tests/test_rasterize_geom_crs_3087.py b/xrspatial/tests/test_rasterize_geom_crs_3087.py index 2aff6eb48..ff82eaa4b 100644 --- a/xrspatial/tests/test_rasterize_geom_crs_3087.py +++ b/xrspatial/tests/test_rasterize_geom_crs_3087.py @@ -167,7 +167,7 @@ def test_dask_numpy_backend(self): def test_cupy_backend(self): result = rasterize( _gdf(crs='EPSG:32610'), width=10, height=10, - bounds=(0, 0, 10, 10), column='value', fill=0, use_cuda=True, + bounds=(0, 0, 10, 10), column='value', fill=0, gpu=True, ) assert result.attrs.get('crs') == 32610 @@ -177,6 +177,6 @@ def test_dask_cupy_backend(self): result = rasterize( _gdf(crs='EPSG:32610'), width=10, height=10, bounds=(0, 0, 10, 10), column='value', fill=0, - use_cuda=True, chunks=5, + gpu=True, chunks=5, ) assert result.attrs.get('crs') == 32610 diff --git a/xrspatial/tests/test_rasterize_gpu_alias_3089.py b/xrspatial/tests/test_rasterize_gpu_alias_3089.py index 297592bb4..a0c828e8b 100644 --- a/xrspatial/tests/test_rasterize_gpu_alias_3089.py +++ b/xrspatial/tests/test_rasterize_gpu_alias_3089.py @@ -1,11 +1,9 @@ """Issue #3089: rasterize() renamed its GPU opt-in from ``use_cuda`` to ``gpu`` to match ``open_geotiff(gpu=True)``. -``use_cuda`` stays as a deprecated keyword alias: it still selects the GPU -backend but emits a ``DeprecationWarning``, and combining it with -``gpu=True`` raises ``TypeError``. These tests pin the shim and the -positional-compatibility guarantee (``gpu`` occupies the slot ``use_cuda`` -used to, so positional callers are unaffected). +The ``use_cuda`` alias was deprecated through 0.10.x and removed in 1.0.0 +(#3763). These tests pin the positional-compatibility guarantee (``gpu`` +occupies the slot ``use_cuda`` used to) and that the old name is gone. """ import inspect import warnings @@ -59,8 +57,7 @@ def test_gpu_is_tenth_positional_param(): positional callers keep selecting the GPU backend.""" params = list(inspect.signature(rasterize).parameters) assert params[9] == 'gpu' - # the deprecated alias is appended last so it shifts nothing - assert params[-1] == 'use_cuda' + assert 'use_cuda' not in params def test_default_emits_no_deprecation_warning(): @@ -69,17 +66,10 @@ def test_default_emits_no_deprecation_warning(): rasterize(_pairs(), **_kw()) -def test_use_cuda_false_warns_and_runs_cpu(): - with pytest.warns(DeprecationWarning, match='use gpu='): - result = rasterize(_pairs(), use_cuda=False, **_kw()) - assert isinstance(result.data, np.ndarray) - - -def test_gpu_true_and_use_cuda_raises(): - with pytest.raises(TypeError, match="deprecated alias"): - rasterize(_pairs(), gpu=True, use_cuda=True, **_kw()) - with pytest.raises(TypeError, match="deprecated alias"): - rasterize(_pairs(), gpu=True, use_cuda=False, **_kw()) +def test_use_cuda_removed(): + """The 0.x alias is gone in 1.0: plain unexpected-keyword TypeError.""" + with pytest.raises(TypeError, match="use_cuda"): + rasterize(_pairs(), use_cuda=False, **_kw()) @requires_gpu @@ -91,28 +81,15 @@ def test_gpu_true_matches_numpy(): @requires_gpu -def test_use_cuda_true_warns_and_matches_gpu_true(): - expected = rasterize(_pairs(), gpu=True, **_kw()) - with pytest.warns(DeprecationWarning, match='use gpu='): - result = rasterize(_pairs(), use_cuda=True, **_kw()) - assert isinstance(result.data, cupy.ndarray) - np.testing.assert_array_equal(_to_numpy(result), _to_numpy(expected)) - - -@requires_gpu -def test_dask_cupy_via_gpu_and_alias(): +def test_dask_cupy_via_gpu(): import dask.array as da + expected = rasterize(_pairs(), gpu=True, **_kw()) lazy = rasterize(_pairs(), gpu=True, chunks=5, **_kw()) assert isinstance(lazy.data, da.Array) assert isinstance(lazy.data._meta, cupy.ndarray) - - with pytest.warns(DeprecationWarning, match='use gpu='): - lazy_alias = rasterize(_pairs(), use_cuda=True, chunks=5, **_kw()) - assert isinstance(lazy_alias.data._meta, cupy.ndarray) - np.testing.assert_array_equal( - _to_numpy(lazy.compute()), _to_numpy(lazy_alias.compute())) + _to_numpy(lazy.compute()), _to_numpy(expected)) @requires_gpu diff --git a/xrspatial/tests/test_rasterize_nonfinite_burn_3085.py b/xrspatial/tests/test_rasterize_nonfinite_burn_3085.py index f9dcf418e..2a646eef5 100644 --- a/xrspatial/tests/test_rasterize_nonfinite_burn_3085.py +++ b/xrspatial/tests/test_rasterize_nonfinite_burn_3085.py @@ -182,7 +182,7 @@ def test_nan_burn_int_raises_cupy(): with pytest.raises(ValueError, match=_MATCH): rasterize([(box(0, 0, 5, 5), np.nan)], width=4, height=4, bounds=(0, 0, 5, 5), - fill=0, dtype=np.int32, use_cuda=True) + fill=0, dtype=np.int32, gpu=True) @skip_no_shapely @@ -193,4 +193,4 @@ def test_nan_burn_int_raises_dask_cupy(): with pytest.raises(ValueError, match=_MATCH): rasterize([(box(0, 0, 5, 5), np.nan)], width=4, height=4, bounds=(0, 0, 5, 5), - fill=0, dtype=np.int32, use_cuda=True, chunks=2) + fill=0, dtype=np.int32, gpu=True, chunks=2) diff --git a/xrspatial/tests/test_rasterize_nonfinite_burn_3088.py b/xrspatial/tests/test_rasterize_nonfinite_burn_3088.py index 32e4c323b..d3ad5ae2a 100644 --- a/xrspatial/tests/test_rasterize_nonfinite_burn_3088.py +++ b/xrspatial/tests/test_rasterize_nonfinite_burn_3088.py @@ -132,7 +132,7 @@ def test_nan_burn_int_dtype_raises_cupy(): with pytest.raises(ValueError, match="cannot be represented"): rasterize([(box(2, 2, 8, 8), float('nan'))], width=10, height=10, bounds=(0, 0, 10, 10), - fill=0, dtype=np.int32, use_cuda=True) + fill=0, dtype=np.int32, gpu=True) @skip_no_shapely @@ -143,7 +143,7 @@ def test_nan_burn_int_dtype_raises_dask_cupy(): with pytest.raises(ValueError, match="cannot be represented"): rasterize([(box(2, 2, 8, 8), float('nan'))], width=10, height=10, bounds=(0, 0, 10, 10), - fill=0, dtype=np.int32, use_cuda=True, chunks=5) + fill=0, dtype=np.int32, gpu=True, chunks=5) @skip_no_shapely diff --git a/xrspatial/tests/test_reproject.py b/xrspatial/tests/test_reproject.py index 4addbb312..131d063b8 100644 --- a/xrspatial/tests/test_reproject.py +++ b/xrspatial/tests/test_reproject.py @@ -3699,39 +3699,19 @@ def test_unknown_vertical_crs_raises(self): source_vertical_crs='egm96', # case-sensitive target_vertical_crs='ellipsoidal') - def test_deprecated_vertical_kwargs_still_work(self): - """Old src_/tgt_vertical_crs names map to the new ones with a warning. - - Renamed to source_/target_vertical_crs for consistency with the - source_crs/target_crs spelling (#2613). The old names stay working - through a deprecation shim. - """ - from xrspatial.reproject import reproject - raster = self._ny_raster(value=100.0) - new = reproject(raster, 'EPSG:4326', - source_vertical_crs='EGM96', - target_vertical_crs='ellipsoidal') - with pytest.warns(DeprecationWarning, match="src_vertical_crs"): - old_src = reproject(raster, 'EPSG:4326', - src_vertical_crs='EGM96', - target_vertical_crs='ellipsoidal') - with pytest.warns(DeprecationWarning, match="tgt_vertical_crs"): - old_tgt = reproject(raster, 'EPSG:4326', - source_vertical_crs='EGM96', - tgt_vertical_crs='ellipsoidal') - np.testing.assert_array_equal(old_src.values, new.values) - np.testing.assert_array_equal(old_tgt.values, new.values) - - def test_deprecated_and_new_vertical_kwarg_conflict(self): - """Passing both the old and new spelling for one side is an error.""" + def test_old_vertical_kwarg_names_removed(self): + """src_/tgt_vertical_crs were deprecated in 0.10.x (#2613) and + removed in 1.0.0 (#3763); they now fail like any unknown kwarg.""" from xrspatial.reproject import reproject raster = self._ny_raster(value=100.0) - with pytest.warns(DeprecationWarning): - with pytest.raises(TypeError, match="not both"): - reproject(raster, 'EPSG:4326', - source_vertical_crs='EGM96', - src_vertical_crs='EGM96', - target_vertical_crs='ellipsoidal') + with pytest.raises(TypeError, match="src_vertical_crs"): + reproject(raster, 'EPSG:4326', + src_vertical_crs='EGM96', + target_vertical_crs='ellipsoidal') + with pytest.raises(TypeError, match="tgt_vertical_crs"): + reproject(raster, 'EPSG:4326', + source_vertical_crs='EGM96', + tgt_vertical_crs='ellipsoidal') def test_dask_backend_matches_numpy(self): """Dask-backed input must apply the vertical shift correctly (#2025). From 6dfc6f4f7e2396d5269981d33ce518e1625bbf16 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Fri, 6 Nov 2026 10:20:31 -0500 Subject: [PATCH 2/2] Make owa() order_weights required like weights, per review (#3763) --- xrspatial/mcda/combine.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/xrspatial/mcda/combine.py b/xrspatial/mcda/combine.py index 25b9deabf..8ec64227f 100644 --- a/xrspatial/mcda/combine.py +++ b/xrspatial/mcda/combine.py @@ -253,7 +253,7 @@ def wpm( def owa( criteria: xr.Dataset, weights: dict[str, float], - order_weights: list[float] | None = None, + order_weights: list[float], name: str = "owa", ) -> xr.DataArray: """Ordered Weighted Averaging. @@ -281,9 +281,6 @@ def owa( xr.DataArray Composite suitability surface. """ - if order_weights is None: - raise TypeError("owa() missing required argument: 'order_weights'") - _validate_criteria(criteria) _validate_weights(weights, criteria)