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

Duckarray tests for constructors and properties #6903

Open
wants to merge 157 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
21696bf
add a initial, tiny draft of the automatic duckarray test machinery
keewis Feb 27, 2021
f14ba29
add missing comma
keewis Feb 27, 2021
90f9c41
fix the global marks
keewis Feb 27, 2021
aa4a457
don't try to apply marks if marks is None
keewis Feb 27, 2021
9fa2eca
only set pytestmark if the value is not None
keewis Feb 28, 2021
7994bad
skip the module if pint is not installed
keewis Feb 28, 2021
c4a35f0
filter UnitStrippedWarnings
keewis Feb 28, 2021
0efbbbb
also test sparse
keewis Feb 28, 2021
73499b5
add a test for the test extractor
keewis Mar 1, 2021
532f213
move the selector parsing code to a new function
keewis Mar 1, 2021
f44aafa
also skip the sparse tests
keewis Mar 1, 2021
d651438
move the utils tests into a different file
keewis Mar 1, 2021
f84894a
don't keep the utils tests in a test group
keewis Mar 1, 2021
0090db5
split apply_marks into two separate functions
keewis Mar 1, 2021
ef05c7d
add a mark which attaches marks to test variants
keewis Mar 6, 2021
20334d9
move the duckarray testing module to tests
keewis Mar 6, 2021
f7acc0f
move the utils to a separate module
keewis Mar 6, 2021
e41a15b
fix the existing tests
keewis Mar 6, 2021
1f095a1
completely isolate the apply_marks tests
keewis Mar 6, 2021
2503af7
add a test for applying marks to test variants
keewis Mar 6, 2021
b229645
skip failing test variants
keewis Mar 6, 2021
0723418
fix the import path
keewis Mar 6, 2021
6c4ccb0
rename the duckarray testing module
keewis Mar 9, 2021
c4aa05a
use Variable as example
keewis Mar 9, 2021
fc97e90
fix the skips
keewis Mar 9, 2021
31e577a
only use dimensionless for cumprod
keewis Mar 9, 2021
8d80212
also test dask wrapped by pint
keewis Mar 9, 2021
7c43e91
add a function to concatenate mappings
keewis Mar 9, 2021
b6a90df
add tests for preprocess_marks
keewis Mar 9, 2021
a95b5c4
fix the tests
keewis Mar 9, 2021
aa7caaa
show the duplicates in the error message
keewis Mar 9, 2021
6415be8
add back support for test marks
keewis Mar 9, 2021
de25594
allow passing a list of addition assert functions
keewis Mar 9, 2021
1b0f372
add some notes about the test suite
keewis Mar 9, 2021
706ee54
simplify the extra_assert function
keewis Mar 9, 2021
caf6308
Merge branch 'master' into duckarray-tests
keewis Mar 22, 2021
cd5aa70
convert to hypothesis
keewis Mar 24, 2021
08d72ed
add a marker to convert label-space parameters
keewis Mar 27, 2021
0649d59
add a dummy expect_error function
keewis Mar 27, 2021
c32cb5a
compute actual before expected
keewis Mar 27, 2021
440e0bd
pass a strategy instead of a single dtype
keewis Mar 27, 2021
f74a29c
set a default for expect_error
keewis Mar 27, 2021
d9346f8
add a test for clip
keewis Mar 27, 2021
75f584a
allow passing a separate "create_label" function
keewis Mar 31, 2021
b94c84d
draft the base class hierarchy tailored after pandas' extension array…
keewis Apr 10, 2021
7a150f8
make sure multiple dims are passed as a list
keewis Apr 12, 2021
a6eecb8
sort the dtypes differently
keewis Apr 12, 2021
dcb9fc0
add a strategy to generate a single axis
keewis Apr 12, 2021
0ee096d
add a function to compute the axes from the dims
keewis Apr 12, 2021
53debb2
move the call of the operation to a hook
keewis Apr 12, 2021
9b2c0a3
remove the arg* methods since they are not reducing anything
keewis Apr 12, 2021
a6efbe1
add a context manager to suppress specific warnings
keewis Apr 12, 2021
5d679bf
don't try to reduce along multiple dimensions
keewis Apr 12, 2021
50db3c3
demonstrate the new pattern using pint
keewis Apr 12, 2021
8114d2a
fix the sparse tests
keewis Apr 12, 2021
6afc7c3
Merge branch 'duckarray-testing-baseclasses' into duckarray-tests
keewis Apr 20, 2021
2f084d0
Merge branch 'master' into duckarray-tests
keewis Apr 20, 2021
14349f2
back to only raising for UnitStrippedWarning
keewis Apr 20, 2021
6a658ef
remove the old duckarray testing module
keewis Apr 22, 2021
d595cd6
rename the tests
keewis Apr 22, 2021
2b0dcba
add a mark to skip individual test nodes
keewis Apr 22, 2021
6b61900
skip the prod and std tests
keewis Apr 22, 2021
b9535a1
skip all sparse tests for now
keewis Apr 22, 2021
c675f8d
also skip var
keewis Apr 22, 2021
6e7c538
add a duckarray base class
keewis Apr 22, 2021
e0ee7a6
move the strategies to a separate file and add a variable strategy
keewis Apr 22, 2021
3feef1c
add a simple DataArray strategy and use it in the DataArray tests
keewis Apr 22, 2021
2a70c38
use the DataArray reduce tests with pint
keewis Apr 22, 2021
6a18acf
add a simple strategy to create Dataset objects
keewis Apr 22, 2021
835930c
fix the variable strategy
keewis Apr 23, 2021
0a5c487
adjust the dataset strategy
keewis Apr 23, 2021
d1184a4
parametrize the dataset strategy
keewis Apr 23, 2021
12b5527
fix some of the pint testing utils
keewis Apr 23, 2021
1f95318
use flatmap to define the data_vars strategy
keewis Apr 23, 2021
9800db5
add tests for dataset reduce
keewis Apr 23, 2021
c43f35e
demonstrate the use of the dataset reduce tests using pint
keewis Apr 23, 2021
d1b541e
simplify check_reduce
keewis Apr 23, 2021
19d9d96
remove apparently unnecessary skips
keewis Apr 23, 2021
69e0624
skip the tests if hypothesis is missing
keewis Apr 23, 2021
c7f6677
update the sparse tests
keewis Apr 23, 2021
396c2ba
add DataArray and Dataset tests for sparse
keewis Apr 23, 2021
ead706e
fix attach_units
keewis Apr 23, 2021
3cf9523
rename the test classes
keewis Apr 23, 2021
cd132c6
update a few strategies
keewis Apr 23, 2021
1c310b0
fix the strategies and utils
keewis Apr 23, 2021
7f879b0
use allclose instead of identical to compare
keewis Apr 23, 2021
ff91be8
don't provide a default for shape
keewis Apr 25, 2021
cb286ef
remove the function to generate dimension names
keewis Apr 25, 2021
438f8a5
simplify the generation of the dimension sizes
keewis Apr 25, 2021
01814ff
immediately draw the computed dimension sizes
keewis Apr 26, 2021
0f1222e
convert the sizes to a dict when making sure data vars are not dims
keewis Apr 26, 2021
a38a307
align the default maximum number of dimensions
keewis Apr 26, 2021
ea3d015
draw the data before passing it to DataArray
keewis Apr 26, 2021
afa33ac
directly generate the reduce dimensions
keewis Apr 28, 2021
566627a
Merge branch 'master' into duckarray-tests
keewis May 11, 2021
2e0c6bf
disable dim=[] / axis=() because that's not supported by all duckarrays
keewis May 11, 2021
01599b7
skip the sparse tests
keewis May 11, 2021
259e1d5
typo
keewis May 11, 2021
527b17c
use a single dtype for all variables of a dataset
keewis Jun 30, 2021
3437c3d
specify tolerances per dtype
keewis Jun 30, 2021
4866801
abandon the notion of single_dtype=True
keewis Jun 30, 2021
8019a20
limit the values and add dtype specific tolerances
keewis Jun 30, 2021
cc75b46
Merge branch 'main' into duckarray-tests
keewis Jul 1, 2021
566470b
Merge branch 'main' into duckarray-tests
keewis Aug 12, 2021
b0e94f1
disable bottleneck
keewis Aug 13, 2021
e57cd7b
Merge branch 'main' into duckarray-tests
keewis Aug 15, 2021
33f63a7
reduce the maximum number of dims, dim sizes, and variables
keewis Aug 15, 2021
11d41e3
disable bottleneck for the sparse tests
keewis Aug 15, 2021
71a37ba
try activating the sparse tests
keewis Aug 15, 2021
1d98fec
propagate the dtypes
keewis Aug 15, 2021
a826249
Merge remote-tracking branch 'upstream/main' into duckarray-tests
dcherian Nov 24, 2021
f2cd8a1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 24, 2021
21a5838
Merge branch 'main' into duckarray-tests
dcherian Jul 22, 2022
c747733
Turn off deadlines
dcherian Jul 22, 2022
3f81995
Disable float16 tests.
dcherian Jul 22, 2022
a282686
Use as_numpy in as_dense
dcherian Jul 22, 2022
ede0045
Merge branch 'main' into duckarray-tests
dcherian Jul 22, 2022
cbf408c
Merge branch 'main' into duckarray-tests
keewis Aug 3, 2022
f5b9bdc
move the hypothesis importorskip to before the strategy definitions
keewis Aug 3, 2022
ed68dc2
properly filter out float16 dtypes for sparse
keewis Aug 3, 2022
1e4f18e
also filter out complex64 because there seems to be a bug in sparse
keewis Aug 8, 2022
da2225f
Merge branch 'main' into duckarray-tests
dcherian Aug 8, 2022
37622c5
Merge branch 'main' into duckarray-tests
dcherian Aug 8, 2022
86377e6
Update xarray/tests/duckarrays/test_sparse.py
dcherian Aug 8, 2022
5af49d8
use the proper base to check the dtypes
keewis Aug 8, 2022
8d0a8c3
Merge branch 'main' into duckarray-tests
TomNicholas Aug 8, 2022
50151a4
make sure the importorskip call is before any hypothesis imports
keewis Aug 8, 2022
707aecb
remove the op parameter to create
keewis Aug 9, 2022
aa0f9c3
merge removal of ops arg
TomNicholas Aug 9, 2022
4b51ce4
strategy for creating duck array objects
TomNicholas Aug 9, 2022
a984718
base class for testing creation of Variable object
TomNicholas Aug 9, 2022
8711d46
proof-of-principle for testing creation of Variables wrapping sparse …
TomNicholas Aug 9, 2022
f40879f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 9, 2022
214084c
generalised generation of dimension names to nd
TomNicholas Aug 9, 2022
4c54984
Merge branch 'duckarray-tests-constructors' of https://github.com/Tom…
TomNicholas Aug 9, 2022
e0dd10d
test DataArray constructor with sparse arrays
TomNicholas Aug 9, 2022
b8af1e6
Merge branch 'main' into duckarray-tests-constructors
TomNicholas Dec 13, 2023
2aba7bc
move testing framework to testing module
TomNicholas Dec 13, 2023
9c38519
absolute imports
TomNicholas Dec 13, 2023
8b89911
test_units -> test_pint
TomNicholas Dec 13, 2023
ab64e5e
first variable constructor tests pass for numpy.array_api
TomNicholas Dec 14, 2023
f4dd250
constructor tests now don't use xarray strategies
TomNicholas Dec 14, 2023
626efdf
constructor tests for sparse
TomNicholas Dec 14, 2023
ff08473
use new strategies in reduce test and remove old code
TomNicholas Dec 14, 2023
5ab5a74
reinstate strategies module which I accidentally git rmed
TomNicholas Dec 14, 2023
ec7f726
reduce tests for numpy array api now pass
TomNicholas Dec 14, 2023
843217e
use suppress_warning utility
TomNicholas Dec 14, 2023
9d585ce
test sparse reductions
TomNicholas Dec 14, 2023
7dc832d
remove old utilities
TomNicholas Dec 14, 2023
32cbdc2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 14, 2023
a002d0b
remove pint tests for now
TomNicholas Dec 14, 2023
52682bd
Merge branch 'duckarray-tests-constructors' of https://github.com/Tom…
TomNicholas Dec 14, 2023
bfc3fe7
remove conftest stuff
TomNicholas Dec 14, 2023
d23eaec
single class can test variable/dataarray/dataset
TomNicholas Dec 17, 2023
8e3c655
test numpy outside of array API
TomNicholas Dec 17, 2023
c07c690
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 18, 2023
d2b35c5
narrow dtypes
TomNicholas Dec 31, 2023
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
145 changes: 145 additions & 0 deletions xarray/testing/duckarrays.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
from abc import abstractmethod
from typing import TYPE_CHECKING

import hypothesis.extra.numpy as npst
import hypothesis.strategies as st
import numpy as np
import numpy.testing as npt
import pytest
from hypothesis import given, note

import xarray as xr
import xarray.testing.strategies as xrst
from xarray.core.types import T_DuckArray
from xarray.testing.assertions import assert_identical

if TYPE_CHECKING:
from xarray.core.types import _DTypeLikeNested, _ShapeLike


__all__ = [
"ConstructorTests",
"ReduceTests",
]


class ArrayConstructorChecksMixin:
"""Mixin for checking results of Variable/DataArray constructors."""

def check(self, var, arr):
self.check_types(var, arr)
self.check_values(var, arr)
self.check_attributes(var, arr)

def check_types(self, var, arr):
# test type of wrapped array
assert isinstance(
var.data, type(arr)
), f"found {type(var.data)}, expected {type(arr)}"

def check_attributes(self, var, arr):
# test ndarray attributes are exposed correctly
assert var.ndim == arr.ndim
assert var.shape == arr.shape
assert var.dtype == arr.dtype
assert var.size == arr.size

def check_values(self, var, arr):
# test coercion to numpy
npt.assert_equal(var.to_numpy(), np.asarray(arr))


class ConstructorTests(ArrayConstructorChecksMixin):
shapes = npst.array_shapes()
dtypes = xrst.supported_dtypes()

@staticmethod
@abstractmethod
def array_strategy_fn(
*, shape: "_ShapeLike", dtype: "_DTypeLikeNested"
) -> st.SearchStrategy[T_DuckArray]:
# TODO can we just make this an attribute?
...

Comment on lines +56 to +63
Copy link
Member Author

Choose a reason for hiding this comment

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

I would like to just do this in the subclassed tests:

class VariableConstructorTests

    array_strategy_fn = ...

but then would I need to make array_strategy_fn an abstract property?

@given(st.data())
def test_construct_variable(self, data) -> None:
shape = data.draw(self.shapes)
dtype = data.draw(self.dtypes)
arr = data.draw(self.array_strategy_fn(shape=shape, dtype=dtype))
Copy link
Member Author

Choose a reason for hiding this comment

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

You can't use strategies.variables to test the constructor because strategies.variables has a call to the constructor inside it, so you end up not being able to access the original raw array that you want to use as the "expected" value.


dim_names = data.draw(
xrst.dimension_names(min_dims=len(shape), max_dims=len(shape))
)
var = xr.Variable(data=arr, dims=dim_names)

self.check(var, arr)


def is_real_floating(dtype):
return np.issubdtype(dtype, np.number) and np.issubdtype(dtype, np.floating)


class ReduceTests:
dtypes = xrst.supported_dtypes()

@staticmethod
@abstractmethod
def array_strategy_fn(
*, shape: "_ShapeLike", dtype: "_DTypeLikeNested"
) -> st.SearchStrategy[T_DuckArray]:
# TODO can we just make this an attribute?
...

def check_reduce(self, var, op, dim, *args, **kwargs):
actual = getattr(var, op)(dim=dim, *args, **kwargs)

data = np.asarray(var.data)
expected = getattr(var.copy(data=data), op)(*args, **kwargs)

# create expected result (using nanmean because arrays with Nans will be generated)
reduce_axes = tuple(var.get_axis_num(d) for d in dim)
data = np.asarray(var.data)
expected = getattr(var.copy(data=data), op)(*args, axis=reduce_axes, **kwargs)

note(f"actual:\n{actual}")
note(f"expected:\n{expected}")

assert_identical(actual, expected)

@pytest.mark.parametrize(
"method, dtype_assumption",

Check failure on line 110 in xarray/testing/duckarrays.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.10 all-but-dask

TestReductions.test_reduce_variable[sum-is_real_floating] AssertionError: Left and right Variable objects are not identical Differing values: L Array(1.008608e+08, dtype=float64) R array(1.008608e+08, dtype=float32) Falsifying example: test_reduce_variable( self=<xarray.tests.duckarrays.test_array_api.TestReductions object at 0x7fc1cfe85090>, method='sum', dtype_assumption=is_real_floating, data=data(...), ) Draw 1: <xarray.Variable (0: 3)> Array([33620276., 33620276., 33620276.], dtype=float32) Draw 2: ['0'] actual: <xarray.Variable ()> Array(1.00860828e+08, dtype=float64) expected: <xarray.Variable ()> array(1.0086083e+08, dtype=float32) You can reproduce this example by temporarily adding @reproduce_failure('6.92.2', b'AXicY2ZgZGQAAiYGCGBiZDQG0QABxwA/') as a decorator on your test case

Check failure on line 110 in xarray/testing/duckarrays.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.11

TestReductions.test_reduce_variable[sum-is_real_floating] AssertionError: Left and right Variable objects are not identical Differing values: L Array(16777225., dtype=float64) R array(16777224., dtype=float32) Falsifying example: test_reduce_variable( self=<xarray.tests.duckarrays.test_array_api.TestReductions object at 0x7f7662cf5c50>, method='sum', dtype_assumption=is_real_floating, data=data(...), ) Draw 1: <xarray.Variable (0: 5)> Array([3355445., 3355445., 3355445., 3355445., 3355445.], dtype=float32) Draw 2: ['0'] actual: <xarray.Variable ()> Array(16777225., dtype=float64) expected: <xarray.Variable ()> array(16777224., dtype=float32) You can reproduce this example by temporarily adding @reproduce_failure('6.92.2', b'AXicY2ZgZGQAAhYGKDA2NgVRAARrAKU=') as a decorator on your test case

Check failure on line 110 in xarray/testing/duckarrays.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.9

TestReductions.test_reduce_variable[max-is_real_floating] hypothesis.errors.FailedHealthCheck: It looks like your strategy is filtering out a lot of data. Health check found 50 filtered examples but only 9 good ones. This will make your tests much slower, and also will probably distort the data generation quite a lot. You should adapt your strategy to filter less. This can also be caused by a low max_leaves parameter in recursive() calls See https://hypothesis.readthedocs.io/en/latest/healthchecks.html for more information about this. If you want to disable just this health check, add HealthCheck.filter_too_much to the suppress_health_check settings for this test.

Check failure on line 110 in xarray/testing/duckarrays.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.9

TestReductions.test_reduce_variable[sum-is_real_floating] AssertionError: Left and right Variable objects are not identical Differing values: L Array(1.008608e+08, dtype=float64) R array(1.008608e+08, dtype=float32) Falsifying example: test_reduce_variable( self=<xarray.tests.duckarrays.test_array_api.TestReductions object at 0x7f7a2fd3b340>, method='sum', dtype_assumption=is_real_floating, data=data(...), ) Draw 1: <xarray.Variable (0: 3)> Array([33620276., 33620276., 33620276.], dtype=float32) Draw 2: ['0'] actual: <xarray.Variable ()> Array(1.00860828e+08, dtype=float64) expected: <xarray.Variable ()> array(1.0086083e+08, dtype=float32) You can reproduce this example by temporarily adding @reproduce_failure('6.92.2', b'AXicY2ZgZGQAAiYGCGBiZDQG0QABxwA/') as a decorator on your test case

Check failure on line 110 in xarray/testing/duckarrays.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.10 flaky

TestReductions.test_reduce_variable[sum-is_real_floating] AssertionError: Left and right Variable objects are not identical Differing values: L Array(16777217., dtype=float64) R array(16777216., dtype=float32) Falsifying example: test_reduce_variable( self=<xarray.tests.duckarrays.test_array_api.TestReductions object at 0x7f31cd511870>, method='sum', dtype_assumption=is_real_floating, data=data(...), ) Draw 1: <xarray.Variable (0: 2)> Array([1.6777216e+07, 1.0000000e+00], dtype=float32) Draw 2: ['0'] actual: <xarray.Variable ()> Array(16777217., dtype=float64) expected: <xarray.Variable ()> array(16777216., dtype=float32) You can reproduce this example by temporarily adding @reproduce_failure('6.92.2', b'AXicY2ZgZGQAAjABAYxwNowBAAEhAAo=') as a decorator on your test case

Check failure on line 110 in xarray/testing/duckarrays.py

View workflow job for this annotation

GitHub Actions / macos-latest py3.9

TestReductions.test_reduce_variable[sum-is_real_floating] AssertionError: Left and right Variable objects are not identical Differing values: L Array([16777221.], dtype=float64) R array([16777220.], dtype=float32) Falsifying example: test_reduce_variable( self=<xarray.tests.duckarrays.test_array_api.TestReductions object at 0x1564f4220>, method='sum', dtype_assumption=is_real_floating, data=data(...), ) Draw 1: <xarray.Variable (0: 3, 1: 1)> Array([[5592407.], [5592407.], [5592407.]], dtype=float32) Draw 2: ['0'] actual: <xarray.Variable (1: 1)> Array([16777221.], dtype=float64) expected: <xarray.Variable (1: 1)> array([16777220.], dtype=float32) You can reproduce this example by temporarily adding @reproduce_failure('6.92.2', b'AXicY2ZgZGRgABFAiokBBkJDw0GiDAwACTEBDQ==') as a decorator on your test case

Check failure on line 110 in xarray/testing/duckarrays.py

View workflow job for this annotation

GitHub Actions / macos-latest py3.11

TestReductions.test_reduce_variable[sum-is_real_floating] AssertionError: Left and right Variable objects are not identical Differing values: L Array(16777225., dtype=float64) R array(16777224., dtype=float32) Falsifying example: test_reduce_variable( self=<xarray.tests.duckarrays.test_array_api.TestReductions object at 0x15301e5d0>, method='sum', dtype_assumption=is_real_floating, data=data(...), ) Draw 1: <xarray.Variable (0: 5)> Array([3355445., 3355445., 3355445., 3355445., 3355445.], dtype=float32) Draw 2: ['0'] actual: <xarray.Variable ()> Array(16777225., dtype=float64) expected: <xarray.Variable ()> array(16777224., dtype=float32) You can reproduce this example by temporarily adding @reproduce_failure('6.92.2', b'AXicY2ZgZGQAAhYGKDA2NgVRAARrAKU=') as a decorator on your test case
(
("all", lambda x: True), # should work for any dtype
("any", lambda x: True), # should work for any dtype
# "cumprod", # not in array API
# "cumsum", # not in array API
("max", is_real_floating), # only in array API for real numeric dtypes
# "median", # not in array API
("min", is_real_floating), # only in array API for real numeric dtypes
("prod", is_real_floating), # only in array API for real numeric dtypes
# "std", # TypeError: std() got an unexpected keyword argument 'ddof'
("sum", is_real_floating), # only in array API for real numeric dtypes
# "var", # TypeError: std() got an unexpected keyword argument 'ddof'
),
)
@given(st.data())
def test_reduce_variable(self, method, dtype_assumption, data):
"""
Test that the reduction applied to an xarray Variable is always equal
to the same reduction applied to the underlying array.
"""

narrowed_dtypes = self.dtypes.filter(dtype_assumption)

var = data.draw(
xrst.variables(
array_strategy_fn=self.array_strategy_fn,
dims=xrst.dimension_names(min_dims=1),
dtype=narrowed_dtypes,
)
)

# specify arbitrary reduction along at least one dimension
reduce_dims = data.draw(xrst.unique_subset_of(var.dims, min_size=1))

self.check_reduce(var, method, dim=reduce_dims)
10 changes: 10 additions & 0 deletions xarray/testing/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import warnings
from contextlib import contextmanager


@contextmanager
def suppress_warning(category, message=""):
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=category, message=message)

yield
Empty file.
45 changes: 45 additions & 0 deletions xarray/tests/duckarrays/test_array_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from typing import TYPE_CHECKING

import hypothesis.strategies as st
from hypothesis.extra.array_api import make_strategies_namespace

from xarray.core.types import T_DuckArray
from xarray.testing import duckarrays
from xarray.testing.utils import suppress_warning
from xarray.tests import _importorskip

if TYPE_CHECKING:
from xarray.core.types import _DTypeLikeNested, _ShapeLike


# ignore the warning that the array_api is experimental raised by numpy
with suppress_warning(
UserWarning, "The numpy.array_api submodule is still experimental. See NEP 47."
):
_importorskip("numpy", "1.26.0")
import numpy.array_api as nxp


nxps = make_strategies_namespace(nxp)


class TestConstructors(duckarrays.ConstructorTests):
dtypes = nxps.scalar_dtypes()

@staticmethod
def array_strategy_fn(
shape: "_ShapeLike",
dtype: "_DTypeLikeNested",
) -> st.SearchStrategy[T_DuckArray]:
return nxps.arrays(shape=shape, dtype=dtype)


class TestReductions(duckarrays.ReduceTests):
dtypes = nxps.scalar_dtypes()

@staticmethod
def array_strategy_fn(
shape: "_ShapeLike",
dtype: "_DTypeLikeNested",
) -> st.SearchStrategy[T_DuckArray]:
return nxps.arrays(shape=shape, dtype=dtype)
33 changes: 33 additions & 0 deletions xarray/tests/duckarrays/test_numpy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import TYPE_CHECKING

import hypothesis.extra.numpy as npst
import hypothesis.strategies as st

from xarray.core.types import T_DuckArray
from xarray.testing import duckarrays
from xarray.testing.strategies import supported_dtypes

if TYPE_CHECKING:
from xarray.core.types import _DTypeLikeNested, _ShapeLike


class TestConstructors(duckarrays.ConstructorTests):
dtypes = supported_dtypes()

@staticmethod
def array_strategy_fn(
shape: "_ShapeLike",
dtype: "_DTypeLikeNested",
) -> st.SearchStrategy[T_DuckArray]:
return npst.arrays(shape=shape, dtype=dtype)


class TestReductions(duckarrays.ReduceTests):
dtypes = supported_dtypes()

@staticmethod
def array_strategy_fn(
shape: "_ShapeLike",
dtype: "_DTypeLikeNested",
) -> st.SearchStrategy[T_DuckArray]:
return npst.arrays(shape=shape, dtype=dtype)
76 changes: 76 additions & 0 deletions xarray/tests/duckarrays/test_sparse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from typing import TYPE_CHECKING

import hypothesis.extra.numpy as npst
import hypothesis.strategies as st
import numpy as np
import numpy.testing as npt
import pytest

import xarray.testing.strategies as xrst
from xarray.testing import duckarrays
from xarray.tests import _importorskip

if TYPE_CHECKING:
from xarray.core.types import _DTypeLikeNested, _ShapeLike


_importorskip("sparse")
import sparse


@pytest.fixture(autouse=True)
def disable_bottleneck():
from xarray import set_options

with set_options(use_bottleneck=False):
yield


# sparse does not support float16
sparse_dtypes = xrst.supported_dtypes().filter(
lambda dtype: (not np.issubdtype(dtype, np.float16))
)


@st.composite
def sparse_arrays_fn(
draw: st.DrawFn,
*,
shape: "_ShapeLike",
dtype: "_DTypeLikeNested",
) -> sparse.COO:
"""When called generates an arbitrary sparse.COO array of the given shape and dtype."""
np_arr = draw(npst.arrays(dtype, shape))

def to_sparse(arr: np.ndarray) -> sparse.COO:
if arr.ndim == 0:
return arr

return sparse.COO.from_numpy(arr)

return to_sparse(np_arr)


class TestConstructors(duckarrays.ConstructorTests):
dtypes = sparse_dtypes()

@staticmethod
def array_strategy_fn(
shape: "_ShapeLike",
dtype: "_DTypeLikeNested",
) -> st.SearchStrategy[sparse.COO]:
return sparse_arrays_fn

def check_values(self, var, arr):
npt.assert_equal(var.to_numpy(), arr.todense())


class TestReductions(duckarrays.ReduceTests):
dtypes = nxps.scalar_dtypes()

@staticmethod
def array_strategy_fn(
shape: "_ShapeLike",
dtype: "_DTypeLikeNested",
) -> st.SearchStrategy[T_DuckArray]:
return nxps.arrays(shape=shape, dtype=dtype)
51 changes: 29 additions & 22 deletions xarray/tests/test_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,14 @@


def array_attach_units(data, unit):
if unit is None or (isinstance(unit, int) and unit == 1):
return data

if isinstance(data, Quantity):
raise ValueError(f"cannot attach unit {unit} to quantity {data}")

try:
quantity = data * unit
quantity = unit._REGISTRY.Quantity(data, unit)
except np.core._exceptions.UFuncTypeError:
if isinstance(unit, unit_registry.Unit):
raise
Expand Down Expand Up @@ -181,36 +184,40 @@
return array_attach_units(obj, units)

if isinstance(obj, xr.Dataset):
data_vars = {
name: attach_units(value, units) for name, value in obj.data_vars.items()
variables = {
name: attach_units(value, {None: units.get(name)})
for name, value in obj.variables.items()
}

coords = {
name: attach_units(value, units) for name, value in obj.coords.items()
name: var for name, var in variables.items() if name in obj._coord_names
}
data_vars = {
name: var for name, var in variables.items() if name not in obj._coord_names
}

new_obj = xr.Dataset(data_vars=data_vars, coords=coords, attrs=obj.attrs)
elif isinstance(obj, xr.DataArray):
# try the array name, "data" and None, then fall back to dimensionless
data_units = units.get(obj.name, None) or units.get(None, None) or 1

data = array_attach_units(obj.data, data_units)
units = units.copy()
THIS_ARRAY = xr.core.dataarray._THIS_ARRAY
unset = object()
if obj.name in units:
name = obj.name
elif None in units:
name = None
else:
name = unset

coords = {
name: (
(value.dims, array_attach_units(value.data, units.get(name) or 1))
if name in units
else (value.dims, value.data)
)
for name, value in obj.coords.items()
}
dims = obj.dims
attrs = obj.attrs
if name is not unset:
units[THIS_ARRAY] = units.pop(name)

new_obj = xr.DataArray(
name=obj.name, data=data, coords=coords, attrs=attrs, dims=dims
)
ds = obj._to_temp_dataset()
attached = attach_units(ds, units)
new_obj = obj._from_temp_dataset(attached, name=obj.name)
else:
if isinstance(obj, xr.IndexVariable):
# no units for index variables
return obj

data_units = units.get("data", None) or units.get(None, None) or 1

data = array_attach_units(obj.data, data_units)
Expand Down Expand Up @@ -4734,7 +4741,7 @@

stacked = ds.stack(v=("x", "y"))

expected = attach_units(func(strip_units(stacked)), units)

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.10 all-but-dask

TestDataset.test_stacking_stacked[float64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.10 all-but-dask

TestDataset.test_stacking_stacked[int64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.11

TestDataset.test_stacking_stacked[int64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.11

TestDataset.test_stacking_stacked[float64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.9 min-all-deps

TestDataset.test_stacking_stacked[float64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.9 min-all-deps

TestDataset.test_stacking_stacked[int64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.9

TestDataset.test_stacking_stacked[float64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.9

TestDataset.test_stacking_stacked[int64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.10 flaky

TestDataset.test_stacking_stacked[int64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / ubuntu-latest py3.10 flaky

TestDataset.test_stacking_stacked[float64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / macos-latest py3.9

TestDataset.test_stacking_stacked[float64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / macos-latest py3.9

TestDataset.test_stacking_stacked[int64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / macos-latest py3.11

TestDataset.test_stacking_stacked[float64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y

Check failure on line 4744 in xarray/tests/test_units.py

View workflow job for this annotation

GitHub Actions / macos-latest py3.11

TestDataset.test_stacking_stacked[int64-data-method_reorder_levels] ValueError: conflicting MultiIndex level / variable name(s): x y
actual = func(stacked)

assert_units_equal(expected, actual)
Expand Down
Loading