diff --git a/xarray/core/nputils.py b/xarray/core/nputils.py index ff54bccd3d2..7fcd4b34d95 100644 --- a/xarray/core/nputils.py +++ b/xarray/core/nputils.py @@ -185,8 +185,12 @@ def f(values, axis=None, **kwargs): and pycompat.mod_version("numbagg") >= Version("0.5.0") and OPTIONS["use_numbagg"] and isinstance(values, np.ndarray) - # numbagg uses ddof=1 only, but numpy uses ddof=0 by default - and (("var" in name or "std" in name) and kwargs.get("ddof", 0) == 1) + # numbagg<0.7.0 uses ddof=1 only, but numpy uses ddof=0 by default + and ( + pycompat.mod_version("numbagg") >= Version("0.7.0") + or ("var" not in name and "std" not in name) + or kwargs.get("ddof", 0) == 1 + ) # TODO: bool? and values.dtype.kind in "uifc" # and values.dtype.isnative @@ -196,9 +200,12 @@ def f(values, axis=None, **kwargs): nba_func = getattr(numbagg, name, None) if nba_func is not None: - # numbagg does not take care dtype, ddof + # numbagg does not use dtype kwargs.pop("dtype", None) - kwargs.pop("ddof", None) + # prior to 0.7.0, numbagg did not support ddof; we ensure it's limited + # to ddof=1 above. + if pycompat.mod_version("numbagg") < Version("0.7.0"): + kwargs.pop("ddof", None) return nba_func(values, axis=axis, **kwargs) if ( _BOTTLENECK_AVAILABLE diff --git a/xarray/tests/conftest.py b/xarray/tests/conftest.py index f153c2f4dc0..9c10bd6d18a 100644 --- a/xarray/tests/conftest.py +++ b/xarray/tests/conftest.py @@ -4,6 +4,7 @@ import pandas as pd import pytest +import xarray as xr from xarray import DataArray, Dataset from xarray.tests import create_test_data, requires_dask @@ -13,6 +14,19 @@ def backend(request): return request.param +@pytest.fixture(params=["numbagg", "bottleneck"]) +def compute_backend(request): + if request.param == "bottleneck": + options = dict(use_bottleneck=True, use_numbagg=False) + elif request.param == "numbagg": + options = dict(use_bottleneck=False, use_numbagg=True) + else: + raise ValueError + + with xr.set_options(**options): + yield request.param + + @pytest.fixture(params=[1]) def ds(request, backend): if request.param == 1: diff --git a/xarray/tests/test_rolling.py b/xarray/tests/test_rolling.py index 6db4d38b53e..79a5ba0a667 100644 --- a/xarray/tests/test_rolling.py +++ b/xarray/tests/test_rolling.py @@ -23,19 +23,6 @@ ] -@pytest.fixture(params=["numbagg", "bottleneck"]) -def compute_backend(request): - if request.param == "bottleneck": - options = dict(use_bottleneck=True, use_numbagg=False) - elif request.param == "numbagg": - options = dict(use_bottleneck=False, use_numbagg=True) - else: - raise ValueError - - with xr.set_options(**options): - yield request.param - - @pytest.mark.parametrize("func", ["mean", "sum"]) @pytest.mark.parametrize("min_periods", [1, 10]) def test_cumulative(d, func, min_periods) -> None: diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index a2ae1e61cf2..fb083586415 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -1754,7 +1754,8 @@ def test_reduce(self): v.mean(dim="x", axis=0) @requires_bottleneck - def test_reduce_use_bottleneck(self, monkeypatch): + @pytest.mark.parametrize("compute_backend", ["bottleneck"], indirect=True) + def test_reduce_use_bottleneck(self, monkeypatch, compute_backend): def raise_if_called(*args, **kwargs): raise RuntimeError("should not have been called")