diff --git a/doc/whats-new.rst b/doc/whats-new.rst index f6618e060c7..880dea3381a 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -17,7 +17,9 @@ New Features Breaking Changes ~~~~~~~~~~~~~~~~ - +- Disable using bottleneck by default, as certain operations are less numerically + stable than the equivalent numpy functions. + By `Thomas Kluyver `_. Deprecations ~~~~~~~~~~~~ diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index d7c16e0b3c8..5806236c7b8 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -100,6 +100,7 @@ is_duck_dask_array, is_scalar, maybe_wrap_array, + module_available, parse_dims_as_set, ) from xarray.core.variable import ( @@ -8447,11 +8448,8 @@ def rank( ranked : Dataset Variables that do not depend on `dim` are dropped. """ - if not OPTIONS["use_bottleneck"]: - raise RuntimeError( - "rank requires bottleneck to be enabled." - " Call `xr.set_options(use_bottleneck=True)` to enable it." - ) + if not module_available("bottleneck"): + raise ImportError("rank requires bottleneck to be installed.") if dim not in self.dims: raise ValueError( diff --git a/xarray/core/options.py b/xarray/core/options.py index b43e4ff3b09..d7955025812 100644 --- a/xarray/core/options.py +++ b/xarray/core/options.py @@ -103,7 +103,7 @@ class T_Options(TypedDict): "keep_attrs": "default", "netcdf_engine_order": ("netcdf4", "h5netcdf", "scipy"), "warn_for_unclosed_files": False, - "use_bottleneck": True, + "use_bottleneck": False, "use_flox": True, "use_new_combine_kwarg_defaults": False, "use_numbagg": True, diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 1b5e0d4ff69..1ea86254d35 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -2093,11 +2093,8 @@ def rank(self, dim, pct=False): Dataset.rank, DataArray.rank """ # This could / should arguably be implemented at the DataArray & Dataset level - if not OPTIONS["use_bottleneck"]: - raise RuntimeError( - "rank requires bottleneck to be enabled." - " Call `xr.set_options(use_bottleneck=True)` to enable it." - ) + if not module_available("bottleneck"): + raise ImportError("rank requires bottleneck to be installed.") import bottleneck as bn diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index d1934ebbaa5..a7178bba512 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -6518,12 +6518,6 @@ def test_rank(self) -> None: ): x.rank("invalid_dim") - def test_rank_use_bottleneck(self) -> None: - ds = Dataset({"a": ("x", [0, np.nan, 2]), "b": ("y", [4, 6, 3, 4])}) - with xr.set_options(use_bottleneck=False): - with pytest.raises(RuntimeError): - ds.rank("x") - def test_count(self) -> None: ds = Dataset({"x": ("a", [np.nan, 1]), "y": 0, "z": np.nan}) expected = Dataset({"x": 1, "y": 1, "z": 0}) diff --git a/xarray/tests/test_rolling.py b/xarray/tests/test_rolling.py index 05f65d24507..26068cdb098 100644 --- a/xarray/tests/test_rolling.py +++ b/xarray/tests/test_rolling.py @@ -460,7 +460,7 @@ def test_rolling_bottleneck_dask_dtype_matches_numpy( .rolling(t=72, min_periods=72, center=center) ) - with set_options(use_numbagg=False): + with set_options(use_numbagg=False, use_bottleneck=True): expected = getattr(unchunked, name)() actual = getattr(chunked, name)() actual_block = actual.data.blocks[0, 0].compute() diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index b493d943bb2..c2bc73f70b9 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -2018,12 +2018,6 @@ def test_rank_dask(self): ): v.rank("x") - def test_rank_use_bottleneck(self): - v = Variable(["x"], [3.0, 1.0, np.nan, 2.0, 4.0]) - with set_options(use_bottleneck=False): - with pytest.raises(RuntimeError): - v.rank("x") - @requires_bottleneck def test_rank(self): import bottleneck as bn