Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: move xfail out of functions #265

Merged
merged 6 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also nice!

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)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh nice!

)
def engine(request):
if request.param == "numba":
try:
import numba # noqa
except ImportError:
pytest.xfail()
return request.param
58 changes: 32 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,9 @@ 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 +761,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 +836,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 +1059,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 +1093,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 @@ -1228,7 +1234,7 @@ def grouped_median(group_idx, array, *, axis=-1, size=None, fill_value=None, dty

@pytest.mark.parametrize("func", ALL_FUNCS)
@pytest.mark.parametrize("dtype", [np.float32, np.float64])
def test_dtype(func, dtype, engine):
def test_dtype(func, dtype):
if "arg" in func or func in ["any", "all"]:
pytest.skip()
arr = np.ones((4, 12), dtype=dtype)
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