Skip to content

Commit

Permalink
tests: move xfail out of functions (#265)
Browse files Browse the repository at this point in the history
* tests: move xfail out of functions

* remove stray print

* Update tests/test_core.py

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* add engine in test_dtype

---------

Co-authored-by: Deepak Cherian <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 2, 2023
1 parent 11d5083 commit 528a645
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 62 deletions.
10 changes: 3 additions & 7 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import importlib
from contextlib import contextmanager
from contextlib import nullcontext

import numpy as np
import packaging.version
Expand Down Expand Up @@ -46,6 +46,7 @@ def LooseVersion(vstring):


has_dask, requires_dask = _importorskip("dask")
has_numba, requires_numba = _importorskip("numba")
has_xarray, requires_xarray = _importorskip("xarray")


Expand All @@ -67,15 +68,10 @@ def __call__(self, dsk, keys, **kwargs):
return dask.get(dsk, keys, **kwargs)


@contextmanager
def dummy_context():
yield None


def raise_if_dask_computes(max_computes=0):
# return a dummy context manager so that this can be used for non-dask objects
if not has_dask:
return dummy_context()
return nullcontext()
scheduler = CountingScheduler(max_computes)
return dask.config.set(scheduler=scheduler)

Expand Down
11 changes: 5 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import pytest

from . import requires_numba

@pytest.fixture(scope="module", params=["flox", "numpy", "numba"])

@pytest.fixture(
scope="module", params=["flox", "numpy", pytest.param("numba", marks=requires_numba)]
)
def engine(request):
if request.param == "numba":
try:
import numba # noqa
except ImportError:
pytest.xfail()
return request.param
63 changes: 37 additions & 26 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def test_alignment_error():


@pytest.mark.parametrize("dtype", (float, int))
@pytest.mark.parametrize("chunk", [False, True])
@pytest.mark.parametrize("chunk", [False, pytest.param(True, marks=requires_dask)])
# TODO: make this intp when python 3.8 is dropped
@pytest.mark.parametrize("expected_groups", [None, [0, 1, 2], np.array([0, 1, 2], dtype=np.int64)])
@pytest.mark.parametrize(
Expand Down Expand Up @@ -145,7 +145,7 @@ def test_groupby_reduce(
) -> None:
array = array.astype(dtype)
if chunk:
if not has_dask or expected_groups is None:
if expected_groups is None:
pytest.skip()
array = da.from_array(array, chunks=(3,) if array.ndim == 1 else (1, 3))
by = da.from_array(by, chunks=(3,) if by.ndim == 1 else (1, 3))
Expand All @@ -166,7 +166,7 @@ def test_groupby_reduce(
engine=engine,
)
# we use pd.Index(expected_groups).to_numpy() which is always int64
# for the values in this tests
# for the values in this test
if expected_groups is None:
g_dtype = by.dtype
elif isinstance(expected_groups, np.ndarray):
Expand All @@ -191,14 +191,20 @@ def gen_array_by(size, func):
return array, by


@pytest.mark.parametrize("chunks", [None, -1, 3, 4])
@pytest.mark.parametrize(
"chunks",
[
None,
pytest.param(-1, marks=requires_dask),
pytest.param(3, marks=requires_dask),
pytest.param(4, marks=requires_dask),
],
)
@pytest.mark.parametrize("nby", [1, 2, 3])
@pytest.mark.parametrize("size", ((12,), (12, 9)))
@pytest.mark.parametrize("add_nan_by", [True, False])
@pytest.mark.parametrize("func", ALL_FUNCS)
def test_groupby_reduce_all(nby, size, chunks, func, add_nan_by, engine):
if chunks is not None and not has_dask:
pytest.skip()
if "arg" in func and engine == "flox":
pytest.skip()

Expand Down Expand Up @@ -390,16 +396,16 @@ def test_numpy_reduce_nd_md():
def test_groupby_agg_dask(func, shape, array_chunks, group_chunks, add_nan, dtype, engine, reindex):
"""Tests groupby_reduce with dask arrays against groupby_reduce with numpy arrays"""

rng = np.random.default_rng(12345)
array = dask.array.from_array(rng.random(shape), chunks=array_chunks).astype(dtype)
array = dask.array.ones(shape, chunks=array_chunks)

if func in ["first", "last"]:
pytest.skip()

if "arg" in func and (engine == "flox" or reindex):
pytest.skip()

rng = np.random.default_rng(12345)
array = dask.array.from_array(rng.random(shape), chunks=array_chunks).astype(dtype)
array = dask.array.ones(shape, chunks=array_chunks)

labels = np.array([0, 0, 2, 2, 2, 1, 1, 2, 2, 1, 1, 0])
if add_nan:
labels = labels.astype(float)
Expand Down Expand Up @@ -612,7 +618,14 @@ def test_groupby_reduce_axis_subset_against_numpy(func, axis, engine):
assert_equal(actual, expected, tolerance)


@pytest.mark.parametrize("reindex,chunks", [(None, None), (False, (2, 2, 3)), (True, (2, 2, 3))])
@pytest.mark.parametrize(
"reindex, chunks",
[
(None, None),
pytest.param(False, (2, 2, 3), marks=requires_dask),
pytest.param(True, (2, 2, 3), marks=requires_dask),
],
)
@pytest.mark.parametrize(
"axis, groups, expected_shape",
[
Expand All @@ -624,8 +637,6 @@ def test_groupby_reduce_axis_subset_against_numpy(func, axis, engine):
def test_groupby_reduce_nans(reindex, chunks, axis, groups, expected_shape, engine):
def _maybe_chunk(arr):
if chunks:
if not has_dask:
pytest.skip()
return da.from_array(arr, chunks=chunks)
else:
return arr
Expand Down Expand Up @@ -739,7 +750,14 @@ def test_npg_nanarg_bug(func):
)
@pytest.mark.parametrize("method", ["cohorts", "map-reduce"])
@pytest.mark.parametrize("chunk_labels", [False, True])
@pytest.mark.parametrize("chunks", ((), (1,), (2,)))
@pytest.mark.parametrize(
"chunks",
(
(),
pytest.param((1,), marks=requires_dask),
pytest.param((2,), marks=requires_dask),
),
)
def test_groupby_bins(chunk_labels, kwargs, chunks, engine, method) -> None:
array = [1, 1, 1, 1, 1, 1]
labels = [0.2, 1.5, 1.9, 2, 3, 20]
Expand All @@ -748,8 +766,6 @@ def test_groupby_bins(chunk_labels, kwargs, chunks, engine, method) -> None:
pytest.xfail()

if chunks:
if not has_dask:
pytest.skip()
array = dask.array.from_array(array, chunks=chunks)
if chunk_labels:
labels = dask.array.from_array(labels, chunks=chunks)
Expand Down Expand Up @@ -825,16 +841,14 @@ def test_rechunk_for_cohorts(chunk_at, expected):
assert rechunked.chunks == expected


@pytest.mark.parametrize("chunks", [None, 3])
@pytest.mark.parametrize("chunks", [None, pytest.param(3, marks=requires_dask)])
@pytest.mark.parametrize("fill_value", [123, np.nan])
@pytest.mark.parametrize("func", ALL_FUNCS)
def test_fill_value_behaviour(func, chunks, fill_value, engine):
# fill_value = np.nan tests promotion of int counts to float
# This is used by xarray
if func in ["all", "any"] or "arg" in func:
pytest.skip()
if chunks is not None and not has_dask:
pytest.skip()

npfunc = _get_array_func(func)
by = np.array([1, 2, 3, 1, 2, 3])
Expand Down Expand Up @@ -1050,11 +1064,8 @@ def test_factorize_values_outside_bins():
assert_equal(expected, actual)


@pytest.mark.parametrize("chunk", [True, False])
@pytest.mark.parametrize("chunk", [pytest.param(True, marks=requires_dask), False])
def test_multiple_groupers_bins(chunk) -> None:
if chunk and not has_dask:
pytest.skip()

xp = dask.array if chunk else np
array_kwargs = {"chunks": 2} if chunk else {}
array = xp.ones((5, 2), **array_kwargs, dtype=np.int64)
Expand Down Expand Up @@ -1087,9 +1098,9 @@ def test_multiple_groupers_bins(chunk) -> None:
np.arange(2, 4).reshape(1, 2),
],
)
@pytest.mark.parametrize("chunk", [True, False])
@pytest.mark.parametrize("chunk", [pytest.param(True, marks=requires_dask), False])
def test_multiple_groupers(chunk, by1, by2, expected_groups) -> None:
if chunk and (not has_dask or expected_groups is None):
if chunk and expected_groups is None:
pytest.skip()

xp = dask.array if chunk else np
Expand Down Expand Up @@ -1233,7 +1244,7 @@ def test_dtype(func, dtype, engine):
pytest.skip()
arr = np.ones((4, 12), dtype=dtype)
labels = np.array(["a", "a", "c", "c", "c", "b", "b", "c", "c", "b", "b", "f"])
actual, _ = groupby_reduce(arr, labels, func=func, dtype=np.float64)
actual, _ = groupby_reduce(arr, labels, func=func, dtype=np.float64, engine=engine)
assert actual.dtype == np.dtype("float64")


Expand Down
32 changes: 9 additions & 23 deletions tests/test_xarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
dask.config.set(scheduler="sync")

try:
# Should test against legacy xarray implementation
# test against legacy xarray implementation
xr.set_options(use_flox=False)
except ValueError:
pass
Expand All @@ -31,15 +31,15 @@
@pytest.mark.parametrize("add_nan", [True, False])
@pytest.mark.parametrize("skipna", [True, False])
def test_xarray_reduce(skipna, add_nan, min_count, engine, reindex):
if skipna is False and min_count is not None:
pytest.skip()

arr = np.ones((4, 12))

if add_nan:
arr[1, ...] = np.nan
arr[[0, 2], [3, 4]] = np.nan

if skipna is False and min_count is not None:
pytest.skip()

labels = np.array(["a", "a", "c", "c", "c", "b", "b", "c", "c", "b", "b", "f"])
labels = np.array(labels)
labels2 = np.array([1, 2, 2, 1])
Expand Down Expand Up @@ -77,11 +77,8 @@ def test_xarray_reduce(skipna, add_nan, min_count, engine, reindex):

# TODO: sort
@pytest.mark.parametrize("pass_expected_groups", [True, False])
@pytest.mark.parametrize("chunk", (True, False))
@pytest.mark.parametrize("chunk", (pytest.param(True, marks=requires_dask), False))
def test_xarray_reduce_multiple_groupers(pass_expected_groups, chunk, engine):
if not has_dask and chunk:
pytest.skip()

if chunk and pass_expected_groups is False:
pytest.skip()

Expand Down Expand Up @@ -126,11 +123,8 @@ def test_xarray_reduce_multiple_groupers(pass_expected_groups, chunk, engine):


@pytest.mark.parametrize("pass_expected_groups", [True, False])
@pytest.mark.parametrize("chunk", (True, False))
@pytest.mark.parametrize("chunk", (pytest.param(True, marks=requires_dask), False))
def test_xarray_reduce_multiple_groupers_2(pass_expected_groups, chunk, engine):
if not has_dask and chunk:
pytest.skip()

if chunk and pass_expected_groups is False:
pytest.skip()

Expand Down Expand Up @@ -317,14 +311,12 @@ def test_multi_index_groupby_sum(engine):
assert_equal(expected, actual)


@pytest.mark.parametrize("chunks", (None, 2))
@pytest.mark.parametrize("chunks", (None, pytest.param(2, marks=requires_dask)))
def test_xarray_groupby_bins(chunks, engine):
array = xr.DataArray([1, 1, 1, 1, 1], dims="x")
labels = xr.DataArray([1, 1.5, 1.9, 2, 3], dims="x", name="labels")

if chunks:
if not has_dask:
pytest.skip()
array = array.chunk({"x": chunks})
labels = labels.chunk({"x": chunks})

Expand Down Expand Up @@ -472,11 +464,8 @@ def test_alignment_error():
@pytest.mark.parametrize("add_nan", [True, False])
@pytest.mark.parametrize("dtype_out", [np.float64, "float64", np.dtype("float64")])
@pytest.mark.parametrize("dtype", [np.float32, np.float64])
@pytest.mark.parametrize("chunk", (True, False))
@pytest.mark.parametrize("chunk", (pytest.param(True, marks=requires_dask), False))
def test_dtype(add_nan, chunk, dtype, dtype_out, engine):
if chunk and not has_dask:
pytest.skip()

xp = dask.array if chunk else np
data = xp.linspace(0, 1, 48, dtype=dtype).reshape((4, 12))

Expand Down Expand Up @@ -508,12 +497,9 @@ def test_dtype(add_nan, chunk, dtype, dtype_out, engine):
xr.testing.assert_allclose(expected, actual.transpose("labels", ...), **tolerance64)


@pytest.mark.parametrize("chunk", [True, False])
@pytest.mark.parametrize("chunk", [pytest.param(True, marks=requires_dask), False])
@pytest.mark.parametrize("use_flox", [True, False])
def test_dtype_accumulation(use_flox, chunk):
if chunk and not has_dask:
pytest.skip()

datetimes = pd.date_range("2010-01", "2015-01", freq="6H", inclusive="left")
samples = 10 + np.cos(2 * np.pi * 0.001 * np.arange(len(datetimes))) * 1
samples += np.random.randn(len(datetimes))
Expand Down

0 comments on commit 528a645

Please sign in to comment.