From 730e1d586433f99bb7d57b78bf1d16b8de076354 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 15 Apr 2020 23:13:33 +0200 Subject: [PATCH 01/57] remove the xfail marks from all aggregations except prod and np.median --- xarray/tests/test_units.py | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 2826dc2479c..01b2e639e17 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3725,14 +3725,8 @@ def test_repr(self, func, variant, dtype): @pytest.mark.parametrize( "func", ( - pytest.param( - function("all"), - marks=pytest.mark.xfail(reason="not implemented by pint"), - ), - pytest.param( - function("any"), - marks=pytest.mark.xfail(reason="not implemented by pint"), - ), + function("all"), + function("any"), function("argmax"), function("argmin"), function("max"), @@ -3752,16 +3746,9 @@ def test_repr(self, func, variant, dtype): function("std"), function("var"), function("cumsum"), - pytest.param( - function("cumprod"), - marks=pytest.mark.xfail(reason="fails within xarray"), - ), - pytest.param( - method("all"), marks=pytest.mark.xfail(reason="not implemented by pint") - ), - pytest.param( - method("any"), marks=pytest.mark.xfail(reason="not implemented by pint") - ), + function("cumprod"), + method("all"), + method("any"), method("argmax"), method("argmin"), method("max"), @@ -3776,9 +3763,7 @@ def test_repr(self, func, variant, dtype): method("std"), method("var"), method("cumsum"), - pytest.param( - method("cumprod"), marks=pytest.mark.xfail(reason="fails within xarray") - ), + method("cumprod"), ), ids=repr, ) From 8da62494a831dab46344670beca95ccab7a4dc5e Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 15 Apr 2020 23:17:33 +0200 Subject: [PATCH 02/57] rewrite the aggregation tests --- xarray/tests/test_units.py | 39 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 01b2e639e17..8fc7e487c56 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3734,9 +3734,7 @@ def test_repr(self, func, variant, dtype): function("mean"), pytest.param( function("median"), - marks=pytest.mark.xfail( - reason="np.median does not work with dataset yet" - ), + marks=pytest.mark.xfail(reason="median does not work with dataset yet"), ), function("sum"), pytest.param( @@ -3768,33 +3766,26 @@ def test_repr(self, func, variant, dtype): ids=repr, ) def test_aggregation(self, func, dtype): - unit_a = ( - unit_registry.Pa if func.name != "cumprod" else unit_registry.dimensionless - ) - unit_b = ( - unit_registry.kg / unit_registry.m ** 3 + unit_a, unit_b = ( + (unit_registry.Pa, unit_registry.kg / unit_registry.m ** 3) if func.name != "cumprod" - else unit_registry.dimensionless - ) - a = xr.DataArray(data=np.linspace(0, 1, 10).astype(dtype) * unit_a, dims="x") - b = xr.DataArray(data=np.linspace(-1, 0, 10).astype(dtype) * unit_b, dims="x") - x = xr.DataArray(data=np.arange(10).astype(dtype) * unit_registry.m, dims="x") - y = xr.DataArray( - data=np.arange(10, 20).astype(dtype) * unit_registry.s, dims="x" + else (unit_registry.dimensionless, unit_registry.dimensionless) ) - ds = xr.Dataset(data_vars={"a": a, "b": b}, coords={"x": x, "y": y}) + a = np.linspace(0, 1, 10).astype(dtype) * unit_a + b = np.linspace(-1, 0, 10).astype(dtype) * unit_b + + ds = xr.Dataset({"a": ("x", a), "b": ("x", b)}) + + units_a = extract_units(func(a)).get(None) + units_b = extract_units(func(b)).get(None) + units = {"a": units_a, "b": units_b} actual = func(ds) - expected = attach_units( - func(strip_units(ds)), - { - "a": extract_units(func(a)).get(None), - "b": extract_units(func(b)).get(None), - }, - ) + expected = attach_units(func(strip_units(ds)), units) - assert_equal_with_units(actual, expected) + assert_units_equal(expected, actual) + xr.testing.assert_equal(expected, actual) @pytest.mark.parametrize("property", ("imag", "real")) def test_numpy_properties(self, property, dtype): From 78cbffae611c02b19183c9911ea6eac9c752458f Mon Sep 17 00:00:00 2001 From: Keewis Date: Thu, 16 Apr 2020 00:50:15 +0200 Subject: [PATCH 03/57] rewrite the repr tests it still does not check the content of the repr, though --- xarray/tests/test_units.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 8fc7e487c56..8ed614c8692 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3691,18 +3691,22 @@ def test_init(self, shared, unit, error, dtype): @pytest.mark.parametrize( "variant", ( + "data", pytest.param( - "with_dims", + "dims", marks=pytest.mark.xfail(reason="units in indexes are not supported"), ), - pytest.param("with_coords"), - pytest.param("without_coords"), + "coords", ), ) @pytest.mark.filterwarnings("error:::pint[.*]") def test_repr(self, func, variant, dtype): - array1 = np.linspace(1, 2, 10, dtype=dtype) * unit_registry.Pa - array2 = np.linspace(0, 1, 10, dtype=dtype) * unit_registry.degK + unit1, unit2 = ( + (unit_registry.Pa, unit_registry.degK) if variant == "data" else (1, 1) + ) + + array1 = np.linspace(1, 2, 10, dtype=dtype) * unit1 + array2 = np.linspace(0, 1, 10, dtype=dtype) * unit2 x = np.arange(len(array1)) * unit_registry.s y = x.to(unit_registry.ms) @@ -3710,17 +3714,17 @@ def test_repr(self, func, variant, dtype): variants = { "with_dims": {"x": x}, "with_coords": {"y": ("x", y)}, - "without_coords": {}, + "data": {}, } - data_array = xr.Dataset( + ds = xr.Dataset( data_vars={"a": ("x", array1), "b": ("x", array2)}, coords=variants.get(variant), ) # FIXME: this just checks that the repr does not raise # warnings or errors, but does not check the result - func(data_array) + func(ds) @pytest.mark.parametrize( "func", From 3f362da39f16a7453d0f988597832588bd820217 Mon Sep 17 00:00:00 2001 From: Keewis Date: Thu, 16 Apr 2020 00:52:14 +0200 Subject: [PATCH 04/57] rewrite some more tests --- xarray/tests/test_units.py | 58 ++++++++++++-------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 8ed614c8692..9833b791b10 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -9,7 +9,7 @@ import xarray as xr from xarray.core import formatting from xarray.core.npcompat import IS_NEP18_ACTIVE -from xarray.testing import assert_allclose, assert_identical +from xarray.testing import assert_allclose, assert_equal, assert_identical from .test_variable import _PAD_XR_NP_ARGS, VariableSubclassobjects @@ -3781,38 +3781,28 @@ def test_aggregation(self, func, dtype): ds = xr.Dataset({"a": ("x", a), "b": ("x", b)}) - units_a = extract_units(func(a)).get(None) - units_b = extract_units(func(b)).get(None) + units_a = array_extract_units(func(a)) + units_b = array_extract_units(func(b)) units = {"a": units_a, "b": units_b} actual = func(ds) expected = attach_units(func(strip_units(ds)), units) assert_units_equal(expected, actual) - xr.testing.assert_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize("property", ("imag", "real")) def test_numpy_properties(self, property, dtype): - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray( - data=np.linspace(0, 1, 10) * unit_registry.Pa, dims="x" - ), - "b": xr.DataArray( - data=np.linspace(-1, 0, 15) * unit_registry.Pa, dims="y" - ), - }, - coords={ - "x": np.arange(10) * unit_registry.m, - "y": np.arange(15) * unit_registry.s, - }, - ) + a = np.linspace(0, 1, 10) * unit_registry.Pa + b = np.linspace(-1, 0, 15) * unit_registry.degK + ds = xr.Dataset({"a": ("x", a), "b": ("y", b)}) units = extract_units(ds) actual = getattr(ds, property) expected = attach_units(getattr(strip_units(ds), property), units) - assert_equal_with_units(actual, expected) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", @@ -3826,31 +3816,19 @@ def test_numpy_properties(self, property, dtype): ids=repr, ) def test_numpy_methods(self, func, dtype): - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray( - data=np.linspace(1, -1, 10) * unit_registry.Pa, dims="x" - ), - "b": xr.DataArray( - data=np.linspace(-1, 1, 15) * unit_registry.Pa, dims="y" - ), - }, - coords={ - "x": np.arange(10) * unit_registry.m, - "y": np.arange(15) * unit_registry.s, - }, - ) - units = { - "a": array_extract_units(func(ds.a)), - "b": array_extract_units(func(ds.b)), - "x": unit_registry.m, - "y": unit_registry.s, - } + a = np.linspace(1, -1, 10) * unit_registry.Pa + b = np.linspace(-1, 1, 15) * unit_registry.degK + ds = xr.Dataset({"a": ("x", a), "b": ("y", b)}) + + units_a = array_extract_units(func(a)) + units_b = array_extract_units(func(b)) + units = {"a": units_a, "b": units_b} actual = func(ds) expected = attach_units(func(strip_units(ds)), units) - assert_equal_with_units(actual, expected) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize("func", (method("clip", min=3, max=8),), ids=repr) @pytest.mark.parametrize( From c0ea8dba509190a8f168c5edbb97e02114e6aba1 Mon Sep 17 00:00:00 2001 From: Keewis Date: Thu, 16 Apr 2020 12:14:58 +0200 Subject: [PATCH 05/57] simplify the numpy-method-with-args tests --- xarray/tests/test_units.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 9833b791b10..9432cd836ee 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -48,6 +48,13 @@ def dimensionality(obj): return dimensionality(unit1) == dimensionality(unit2) +def map_values(func, mapping): + if isinstance(mapping, dict): + mapping = mapping.items() + + return {key: func(value) for key, value in mapping} + + def compatible_mappings(first, second): return { key: is_compatible(unit1, unit2) @@ -3845,22 +3852,12 @@ def test_numpy_methods(self, func, dtype): ) def test_numpy_methods_with_args(self, func, unit, error, dtype): data_unit = unit_registry.m - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=np.arange(10) * data_unit, dims="x"), - "b": xr.DataArray(data=np.arange(15) * data_unit, dims="y"), - }, - coords={ - "x": np.arange(10) * unit_registry.m, - "y": np.arange(15) * unit_registry.s, - }, - ) + a = np.linspace(0, 10, 15) * unit_registry.m + b = np.linspace(-2, 12, 20) * unit_registry.m + ds = xr.Dataset({"a": ("x", a), "b": ("y", b)}) units = extract_units(ds) - kwargs = { - key: (value * unit if isinstance(value, (int, float)) else value) - for key, value in func.kwargs.items() - } + kwargs = map_values(lambda v: array_attach_units(v, unit), func.kwargs) if error is not None: with pytest.raises(error): @@ -3868,15 +3865,15 @@ def test_numpy_methods_with_args(self, func, unit, error, dtype): return - stripped_kwargs = { - key: strip_units(convert_units(value, {None: data_unit})) - for key, value in kwargs.items() - } + stripped_kwargs = map_values( + lambda v: strip_units(convert_units(v, {None: data_unit})), kwargs, + ) actual = func(ds, **kwargs) expected = attach_units(func(strip_units(ds), **stripped_kwargs), units) - assert_equal_with_units(actual, expected) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", (method("isnull"), method("notnull"), method("count")), ids=repr From 34ee647680bc769705e7122b6dc421963289bc88 Mon Sep 17 00:00:00 2001 From: Keewis Date: Thu, 16 Apr 2020 18:33:30 +0200 Subject: [PATCH 06/57] always use the same data units unless the compatibility is tested --- xarray/tests/test_units.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 9432cd836ee..78c220264cc 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3963,7 +3963,7 @@ def test_missing_value_filling(self, func, dtype): None, id="compatible_unit", marks=pytest.mark.xfail( - reason="where converts the array, not the fill value" + False, reason="where converts the array, not the fill value" ), ), pytest.param(unit_registry.m, None, id="identical_unit"), From d16fda6a34cb1fe49303e7d67d46172d0755ad60 Mon Sep 17 00:00:00 2001 From: Keewis Date: Fri, 17 Apr 2020 00:22:52 +0200 Subject: [PATCH 07/57] partially rewrite more tests --- xarray/tests/test_units.py | 144 ++++++++++++------------------------- 1 file changed, 46 insertions(+), 98 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 78c220264cc..811854b5cd8 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3778,7 +3778,7 @@ def test_repr(self, func, variant, dtype): ) def test_aggregation(self, func, dtype): unit_a, unit_b = ( - (unit_registry.Pa, unit_registry.kg / unit_registry.m ** 3) + (unit_registry.Pa, unit_registry.degK) if func.name != "cumprod" else (unit_registry.dimensionless, unit_registry.dimensionless) ) @@ -3903,22 +3903,13 @@ def test_missing_value_detection(self, func, dtype): * unit_registry.Pa ) - x = np.arange(array1.shape[0]) * unit_registry.m - y = np.arange(array1.shape[1]) * unit_registry.m - z = np.arange(array2.shape[0]) * unit_registry.m - - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("z", "x")), - }, - coords={"x": x, "y": y, "z": z}, - ) + ds = xr.Dataset({"a": (("x", "y"), array1), "b": (("z", "x"), array2)}) expected = func(strip_units(ds)) actual = func(ds) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="ffill and bfill lose the unit") @pytest.mark.parametrize("func", (method("ffill"), method("bfill")), ids=repr) @@ -3932,23 +3923,14 @@ def test_missing_value_filling(self, func, dtype): * unit_registry.Pa ) - x = np.arange(len(array1)) - - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - }, - coords={"x": x}, - ) + ds = xr.Dataset({"a": ("x", array1), "b": ("y", array2)}) + units = extract_units(ds) - expected = attach_units( - func(strip_units(ds), dim="x"), - {"a": unit_registry.degK, "b": unit_registry.Pa}, - ) + expected = attach_units(func(strip_units(ds), dim="x"), units,) actual = func(ds, dim="x") - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "unit,error", @@ -3986,30 +3968,26 @@ def test_fillna(self, fill_value, unit, error, dtype): np.array([4.3, 9.8, 7.5, np.nan, 8.2, np.nan]).astype(dtype) * unit_registry.m ) - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - } - ) + ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}) + value = fill_value * unit + units = extract_units(ds) if error is not None: with pytest.raises(error): - ds.fillna(value=fill_value * unit) + ds.fillna(value=value) return - actual = ds.fillna(value=fill_value * unit) + actual = ds.fillna(value=value) expected = attach_units( strip_units(ds).fillna( - value=strip_units( - convert_units(fill_value * unit, {None: unit_registry.m}) - ) + value=strip_units(convert_units(value, {None: unit_registry.m})) ), - {"a": unit_registry.m, "b": unit_registry.m}, + units, ) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) def test_dropna(self, dtype): array1 = ( @@ -4020,22 +3998,14 @@ def test_dropna(self, dtype): np.array([4.3, 9.8, 7.5, np.nan, 8.2, np.nan]).astype(dtype) * unit_registry.Pa ) - x = np.arange(len(array1)) - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - }, - coords={"x": x}, - ) + ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}) + units = extract_units(ds) - expected = attach_units( - strip_units(ds).dropna(dim="x"), - {"a": unit_registry.degK, "b": unit_registry.Pa}, - ) + expected = attach_units(strip_units(ds).dropna(dim="x"), units) actual = ds.dropna(dim="x") - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "unit", @@ -4056,34 +4026,27 @@ def test_isin(self, unit, dtype): np.array([4.3, 9.8, 7.5, np.nan, 8.2, np.nan]).astype(dtype) * unit_registry.m ) - x = np.arange(len(array1)) - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - }, - coords={"x": x}, - ) + ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}) raw_values = np.array([1.4, np.nan, 2.3]).astype(dtype) values = raw_values * unit - if ( - isinstance(values, unit_registry.Quantity) - and values.check(unit_registry.m) - and unit != unit_registry.m - ): - raw_values = values.to(unit_registry.m).magnitude + converted_values = convert_units( + values, + {None: unit_registry.m if is_compatible(unit, unit_registry.m) else None}, + ) - expected = strip_units(ds).isin(raw_values) - if not isinstance(values, unit_registry.Quantity) or not values.check( - unit_registry.m - ): + expected = strip_units(ds).isin(strip_units(converted_values)) + # TODO: use `unit_registry.is_compatible_with(unit, unit_registry.m)` instead. + # Needs `pint>=0.12`, though, so we probably should wait until that is released. + if not is_compatible(unit, unit_registry.m): expected.a[:] = False expected.b[:] = False + actual = ds.isin(values) - assert_equal_with_units(actual, expected) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "variant", ("masking", "replacing_scalar", "replacing_array", "dropping") @@ -4105,13 +4068,8 @@ def test_where(self, variant, unit, error, dtype): array1 = np.linspace(0, 1, 10).astype(dtype) * original_unit array2 = np.linspace(-1, 0, 10).astype(dtype) * original_unit - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - }, - coords={"x": np.arange(len(array1))}, - ) + ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}) + units = extract_units(ds) condition = ds < 0.5 * original_unit other = np.linspace(-2, -1, 10).astype(dtype) * unit @@ -4133,15 +4091,13 @@ def test_where(self, variant, unit, error, dtype): for key, value in kwargs.items() } - expected = attach_units( - strip_units(ds).where(**kwargs_without_units), - {"a": original_unit, "b": original_unit}, - ) + expected = attach_units(strip_units(ds).where(**kwargs_without_units), units,) actual = ds.where(**kwargs) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) - @pytest.mark.xfail(reason="interpolate strips units") + @pytest.mark.xfail(reason="interpolate_na uses numpy.vectorize") def test_interpolate_na(self, dtype): array1 = ( np.array([1.4, np.nan, 2.3, np.nan, np.nan, 9.1]).astype(dtype) @@ -4151,22 +4107,14 @@ def test_interpolate_na(self, dtype): np.array([4.3, 9.8, 7.5, np.nan, 8.2, np.nan]).astype(dtype) * unit_registry.Pa ) - x = np.arange(len(array1)) - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - }, - coords={"x": x}, - ) + ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}) + units = extract_units(ds) - expected = attach_units( - strip_units(ds).interpolate_na(dim="x"), - {"a": unit_registry.degK, "b": unit_registry.Pa}, - ) + expected = attach_units(strip_units(ds).interpolate_na(dim="x"), units,) actual = ds.interpolate_na(dim="x") - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="wrong argument order for `where`") @pytest.mark.parametrize( From 13a312ec8688bb7f5ed2f68b91f3a68a4f776525 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sat, 18 Apr 2020 00:21:57 +0200 Subject: [PATCH 08/57] rewrite combine_first This also adds tests for units in indexes, which are by default stripped. --- xarray/tests/test_units.py | 58 +++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 811854b5cd8..606c6800d6b 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4116,7 +4116,6 @@ def test_interpolate_na(self, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - @pytest.mark.xfail(reason="wrong argument order for `where`") @pytest.mark.parametrize( "unit,error", ( @@ -4129,31 +4128,41 @@ def test_interpolate_na(self, dtype): pytest.param(unit_registry.m, None, id="same_unit"), ), ) - def test_combine_first(self, unit, error, dtype): + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", + marks=pytest.mark.skip(reason="units not supported by IndexVariable"), + ), + ), + ) + def test_combine_first(self, variant, unit, error, dtype): + variants = { + "data": (unit_registry.m, unit, 1, 1), + "dims": (1, 1, unit_registry.m, unit), + } + data_unit, other_data_unit, dims_unit, other_dims_unit = variants.get(variant) + array1 = ( - np.array([1.4, np.nan, 2.3, np.nan, np.nan, 9.1]).astype(dtype) - * unit_registry.m + np.array([1.4, np.nan, 2.3, np.nan, np.nan, 9.1]).astype(dtype) * data_unit ) array2 = ( - np.array([4.3, 9.8, 7.5, np.nan, 8.2, np.nan]).astype(dtype) - * unit_registry.m + np.array([4.3, 9.8, 7.5, np.nan, 8.2, np.nan]).astype(dtype) * data_unit ) - x = np.arange(len(array1)) + x = np.arange(len(array1)) * dims_unit ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - }, - coords={"x": x}, + data_vars={"a": ("x", array1), "b": ("x", array2)}, coords={"x": x}, ) - other_array1 = np.ones_like(array1) * unit - other_array2 = -1 * np.ones_like(array2) * unit + units = extract_units(ds) + + other_array1 = np.ones_like(array1) * other_data_unit + other_array2 = np.full_like(array2, fill_value=-1) * other_data_unit + other_x = (np.arange(array1.shape[0]) + 5) * other_dims_unit other = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=other_array1, dims="x"), - "b": xr.DataArray(data=other_array2, dims="x"), - }, - coords={"x": np.arange(array1.shape[0])}, + data_vars={"a": ("x", other_array1), "b": ("x", other_array2)}, + coords={"x": other_x}, ) if error is not None: @@ -4163,16 +4172,13 @@ def test_combine_first(self, unit, error, dtype): return expected = attach_units( - strip_units(ds).combine_first( - strip_units( - convert_units(other, {"a": unit_registry.m, "b": unit_registry.m}) - ) - ), - {"a": unit_registry.m, "b": unit_registry.m}, + strip_units(ds).combine_first(strip_units(convert_units(other, units))), + units, ) actual = ds.combine_first(other) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "unit", From 36643a43f865cd8288c9a3bbf75f08fcb992484e Mon Sep 17 00:00:00 2001 From: Keewis Date: Sat, 18 Apr 2020 01:24:57 +0200 Subject: [PATCH 09/57] simplify the comparisons test a bit --- xarray/tests/test_units.py | 65 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 606c6800d6b..0f6381fe691 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4191,59 +4191,66 @@ def test_combine_first(self, variant, unit, error, dtype): ), ) @pytest.mark.parametrize( - "variation", + "variant", ( "data", pytest.param( - "dims", marks=pytest.mark.xfail(reason="units in indexes not supported") + "dims", marks=pytest.mark.skip(reason="units in indexes not supported") ), "coords", ), ) @pytest.mark.parametrize("func", (method("equals"), method("identical")), ids=repr) - def test_comparisons(self, func, variation, unit, dtype): - def is_compatible(a, b): - a = a if a is not None else 1 - b = b if b is not None else 1 - quantity = np.arange(5) * a - - return a == b or quantity.check(b) - + def test_comparisons(self, func, variant, unit, dtype): array1 = np.linspace(0, 5, 10).astype(dtype) array2 = np.linspace(-5, 0, 10).astype(dtype) coord = np.arange(len(array1)).astype(dtype) - original_unit = unit_registry.m - quantity1 = array1 * original_unit - quantity2 = array2 * original_unit - x = coord * original_unit - y = coord * original_unit + variants = { + "data": (unit_registry.m, 1, 1), + "dims": (1, unit_registry.m, 1), + "coords": (1, 1, unit_registry.m), + } + data_unit, dim_unit, coord_unit = variants.get(variant) - units = {"data": (unit, 1, 1), "dims": (1, unit, 1), "coords": (1, 1, unit)} - data_unit, dim_unit, coord_unit = units.get(variation) + a = array1 * data_unit + b = array2 * data_unit + x = coord * dim_unit + y = coord * coord_unit ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=quantity1, dims="x"), - "b": xr.DataArray(data=quantity2, dims="x"), - }, - coords={"x": x, "y": ("x", y)}, + data_vars={"a": ("x", a), "b": ("x", b)}, coords={"x": x, "y": ("x", y)}, ) + units = extract_units(ds) + + other_variants = { + "data": (unit, 1, 1), + "dims": (1, unit, 1), + "coords": (1, 1, unit), + } + other_data_unit, other_dim_unit, other_coord_unit = other_variants.get(variant) other_units = { - "a": data_unit if quantity1.check(data_unit) else None, - "b": data_unit if quantity2.check(data_unit) else None, - "x": dim_unit if x.check(dim_unit) else None, - "y": coord_unit if y.check(coord_unit) else None, + "a": other_data_unit, + "b": other_data_unit, + "x": other_dim_unit, + "y": other_coord_unit, } - other = attach_units(strip_units(convert_units(ds, other_units)), other_units) - units = extract_units(ds) + to_convert = { + key: unit if is_compatible(unit, reference) else None + for key, (unit, reference) in merge_mappings(units, other_units) + } + # convert units where possible, then attach all units to the converted dataset + other = attach_units(strip_units(convert_units(ds, to_convert)), other_units) other_units = extract_units(other) + # make sure all units are compatible and only then try to + # convert and compare values equal_ds = all( - is_compatible(units[name], other_units[name]) for name in units.keys() + is_compatible(unit, other_unit) + for _, (unit, other_unit) in merge_mappings(units, other_units) ) and (strip_units(ds).equals(strip_units(convert_units(other, units)))) equal_units = units == other_units expected = equal_ds and (func.name != "identical" or equal_units) From 2fcc3aa1b93ef66c0079669369bda60bd0cf8f76 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sat, 18 Apr 2020 01:38:02 +0200 Subject: [PATCH 10/57] skip the tests for identical --- xarray/tests/test_units.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 0f6381fe691..a31a00fe1c0 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4200,7 +4200,17 @@ def test_combine_first(self, variant, unit, error, dtype): "coords", ), ) - @pytest.mark.parametrize("func", (method("equals"), method("identical")), ids=repr) + @pytest.mark.parametrize( + "func", + ( + method("equals"), + pytest.param( + method("identical"), + marks=pytest.mark.skip("behaviour of identical is unclear"), + ), + ), + ids=repr, + ) def test_comparisons(self, func, variant, unit, dtype): array1 = np.linspace(0, 5, 10).astype(dtype) array2 = np.linspace(-5, 0, 10).astype(dtype) From 154121e92801328b3eac3de37785a8eb04d81a0d Mon Sep 17 00:00:00 2001 From: Keewis Date: Sat, 18 Apr 2020 12:27:21 +0200 Subject: [PATCH 11/57] remove the map_values function --- xarray/tests/test_units.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index a31a00fe1c0..c5dec714bad 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -48,13 +48,6 @@ def dimensionality(obj): return dimensionality(unit1) == dimensionality(unit2) -def map_values(func, mapping): - if isinstance(mapping, dict): - mapping = mapping.items() - - return {key: func(value) for key, value in mapping} - - def compatible_mappings(first, second): return { key: is_compatible(unit1, unit2) @@ -3857,7 +3850,9 @@ def test_numpy_methods_with_args(self, func, unit, error, dtype): ds = xr.Dataset({"a": ("x", a), "b": ("y", b)}) units = extract_units(ds) - kwargs = map_values(lambda v: array_attach_units(v, unit), func.kwargs) + kwargs = { + key: array_attach_units(value, unit) for key, value in func.kwargs.items() + } if error is not None: with pytest.raises(error): @@ -3865,9 +3860,10 @@ def test_numpy_methods_with_args(self, func, unit, error, dtype): return - stripped_kwargs = map_values( - lambda v: strip_units(convert_units(v, {None: data_unit})), kwargs, - ) + stripped_kwargs = { + key: strip_units(convert_units(value, {None: data_unit})) + for key, value in kwargs.items() + } actual = func(ds, **kwargs) expected = attach_units(func(strip_units(ds), **stripped_kwargs), units) From 47df83fd3401912b2b6a19a44e13cc96c62153b5 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sat, 18 Apr 2020 14:38:46 +0200 Subject: [PATCH 12/57] only call convert_units if necessary --- xarray/tests/test_units.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index c5dec714bad..ca37191758d 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4027,9 +4027,10 @@ def test_isin(self, unit, dtype): raw_values = np.array([1.4, np.nan, 2.3]).astype(dtype) values = raw_values * unit - converted_values = convert_units( - values, - {None: unit_registry.m if is_compatible(unit, unit_registry.m) else None}, + converted_values = ( + convert_units(values, {None: unit_registry.m}) + if is_compatible(unit, unit_registry.m) + else values ) expected = strip_units(ds).isin(strip_units(converted_values)) From daf52780a125ad90d0d1fd9c7d41dc19cf6b5e96 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sat, 18 Apr 2020 14:40:11 +0200 Subject: [PATCH 13/57] use assert_units_equal and assert_equal in broadcast_like and skip it --- xarray/tests/test_units.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index ca37191758d..f218e47584c 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4266,6 +4266,7 @@ def test_comparisons(self, func, variant, unit, dtype): assert expected == actual + @pytest.mark.skip(reason="IndexVariable does not support units") @pytest.mark.parametrize( "unit", ( @@ -4278,7 +4279,7 @@ def test_comparisons(self, func, variant, unit, dtype): ) def test_broadcast_like(self, unit, dtype): array1 = np.linspace(1, 2, 2 * 1).reshape(2, 1).astype(dtype) * unit_registry.Pa - array2 = np.linspace(0, 1, 2 * 3).reshape(2, 3).astype(dtype) * unit_registry.Pa + array2 = np.linspace(0, 1, 2 * 3).reshape(2, 3).astype(dtype) x1 = np.arange(2) * unit_registry.m x2 = np.arange(2) * unit @@ -4297,7 +4298,8 @@ def test_broadcast_like(self, unit, dtype): ) actual = ds1.broadcast_like(ds2) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "unit", From b1b04aa2964c85a05ad7bb0afd7d3b88d6c6bf04 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 18:35:39 +0200 Subject: [PATCH 14/57] remove the conditional skip since pint now supports __array_function__ --- xarray/tests/test_units.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index f218e47584c..f68aa48927e 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -27,11 +27,6 @@ pytest.mark.skipif( not IS_NEP18_ACTIVE, reason="NUMPY_EXPERIMENTAL_ARRAY_FUNCTION is not enabled" ), - # TODO: remove this once pint has a released version with __array_function__ - pytest.mark.skipif( - not hasattr(unit_registry.Quantity, "__array_function__"), - reason="pint does not implement __array_function__ yet", - ), # pytest.mark.filterwarnings("ignore:::pint[.*]"), ] From 3e125ccef8eb018d4fe17ce4361b95a56080f482 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 18:40:14 +0200 Subject: [PATCH 15/57] only skip the broadcast_like tests if we attempt to put units in indexes --- xarray/tests/test_units.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index f68aa48927e..e4245e2b7e8 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4261,15 +4261,30 @@ def test_comparisons(self, func, variant, unit, dtype): assert expected == actual - @pytest.mark.skip(reason="IndexVariable does not support units") @pytest.mark.parametrize( "unit", ( pytest.param(1, id="no_unit"), - pytest.param(unit_registry.dimensionless, id="dimensionless"), - pytest.param(unit_registry.s, id="incompatible_unit"), - pytest.param(unit_registry.cm, id="compatible_unit"), - pytest.param(unit_registry.m, id="identical_unit"), + pytest.param( + unit_registry.dimensionless, + id="dimensionless", + marks=pytest.mark.skip(reason="IndexVariable does not support units"), + ), + pytest.param( + unit_registry.s, + id="incompatible_unit", + marks=pytest.mark.skip(reason="IndexVariable does not support units"), + ), + pytest.param( + unit_registry.cm, + id="compatible_unit", + marks=pytest.mark.skip(reason="IndexVariable does not support units"), + ), + pytest.param( + unit_registry.m, + id="identical_unit", + marks=pytest.mark.skip(reason="IndexVariable does not support units"), + ), ), ) def test_broadcast_like(self, unit, dtype): From 94d5016c30e1f2529a63fc94965c8d7c2b3d3581 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 18:42:35 +0200 Subject: [PATCH 16/57] remove the xfail mark from the where tests --- xarray/tests/test_units.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index e4245e2b7e8..7ce195c63d2 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3931,14 +3931,7 @@ def test_missing_value_filling(self, func, dtype): unit_registry.dimensionless, DimensionalityError, id="dimensionless" ), pytest.param(unit_registry.s, DimensionalityError, id="incompatible_unit"), - pytest.param( - unit_registry.cm, - None, - id="compatible_unit", - marks=pytest.mark.xfail( - False, reason="where converts the array, not the fill value" - ), - ), + pytest.param(unit_registry.cm, None, id="compatible_unit",), pytest.param(unit_registry.m, None, id="identical_unit"), ), ) From a22bae00609f7e1aeb16cc528698b6da891bbc78 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 18:45:13 +0200 Subject: [PATCH 17/57] reimplement the broadcast_equals tests --- xarray/tests/test_units.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 7ce195c63d2..d339acd4358 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -50,6 +50,14 @@ def compatible_mappings(first, second): } +def merge_dicts(base, *mappings): + result = base.copy() + for m in mappings: + result.update(m) + + return result + + def array_extract_units(obj): if isinstance(obj, (xr.Variable, xr.DataArray, xr.Dataset)): obj = obj.data @@ -4319,28 +4327,20 @@ def test_broadcast_equals(self, unit, dtype): left_array2 = np.zeros(shape=(3, 6), dtype=dtype) * unit_registry.m right_array1 = np.ones(shape=(2,)) * unit - right_array2 = np.ones(shape=(3,)) * unit + right_array2 = np.zeros(shape=(3,)) * unit left = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=left_array1, dims=("x", "y")), - "b": xr.DataArray(data=left_array2, dims=("y", "z")), - } - ) - right = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=right_array1, dims="x"), - "b": xr.DataArray(data=right_array2, dims="y"), - } + {"a": (("x", "y"), left_array1), "b": (("y", "z"), left_array2)}, ) + right = xr.Dataset({"a": ("x", right_array1), "b": ("y", right_array2)}) - units = { - **extract_units(left), - **({} if left_array1.check(unit) else {"a": None, "b": None}), - } - expected = strip_units(left).broadcast_equals( - strip_units(convert_units(right, units)) - ) & left_array1.check(unit) + units = merge_dicts( + extract_units(left), + {} if is_compatible(left_array1, unit) else {"a": None, "b": None}, + ) + expected = is_compatible(left_array1, unit) and strip_units( + left + ).broadcast_equals(strip_units(convert_units(right, units))) actual = left.broadcast_equals(right) assert expected == actual From 42df3b0f36510b70e3be2652ef60f1744bb624e9 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 22:44:41 +0200 Subject: [PATCH 18/57] reimplement the tests on stacked arrays --- xarray/tests/test_units.py | 43 ++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index d339acd4358..3eff440d567 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4350,35 +4350,46 @@ def test_broadcast_equals(self, unit, dtype): (method("unstack"), method("reset_index", "v"), method("reorder_levels")), ids=repr, ) - def test_stacking_stacked(self, func, dtype): - array1 = ( - np.linspace(0, 10, 5 * 10).reshape(5, 10).astype(dtype) * unit_registry.m - ) + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", + marks=pytest.mark.skip(reason="units not supported in IndexVariable"), + ), + ), + ) + def test_stacking_stacked(self, variant, func, dtype): + variants = { + "data": (unit_registry.m, 1), + "dims": (1, unit_registry.m), + } + data_unit, dim_unit = variants.get(variant) + + array1 = np.linspace(0, 10, 5 * 10).reshape(5, 10).astype(dtype) * data_unit array2 = ( np.linspace(-10, 0, 5 * 10 * 15).reshape(5, 10, 15).astype(dtype) - * unit_registry.m + * data_unit ) - x = np.arange(array1.shape[0]) - y = np.arange(array1.shape[1]) - z = np.arange(array2.shape[2]) + x = np.arange(array1.shape[0]) * dim_unit + y = np.arange(array1.shape[1]) * dim_unit + z = np.arange(array2.shape[2]) * dim_unit ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "y", "z")), - }, + data_vars={"a": (("x", "y"), array1), "b": (("x", "y", "z"), array2)}, coords={"x": x, "y": y, "z": z}, ) + units = extract_units(ds) stacked = ds.stack(v=("x", "y")) - expected = attach_units( - func(strip_units(stacked)), {"a": unit_registry.m, "b": unit_registry.m} - ) + expected = attach_units(func(strip_units(stacked)), units) actual = func(stacked) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="does not work with quantities yet") def test_to_stacked_array(self, dtype): From d7c8b107ccbe6e6531278843d9544f3056be0709 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 22:48:23 +0200 Subject: [PATCH 19/57] refactor the to_stacked_array tests this test is marked as skipped because the unit registry always returns numpy.array objects which are not hashable, so the initial dataset with units cannot be constructed (the result of to_stacked_array wouldn't be correct either because IndexVariable doesn't support units) --- xarray/tests/test_units.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 3eff440d567..e1d7895334f 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4391,27 +4391,26 @@ def test_stacking_stacked(self, variant, func, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - @pytest.mark.xfail(reason="does not work with quantities yet") + @pytest.mark.skip( + reason="stacked dimension's labels have to be hashable, but is a numpy.array" + ) def test_to_stacked_array(self, dtype): - labels = np.arange(5).astype(dtype) * unit_registry.s - arrays = {name: np.linspace(0, 1, 10) * unit_registry.m for name in labels} + labels = range(5) * unit_registry.s + arrays = { + name: np.linspace(0, 1, 10).astype(dtype) * unit_registry.m + for name in labels + } - ds = xr.Dataset( - data_vars={ - name: xr.DataArray(data=array, dims="x") - for name, array in arrays.items() - } - ) + ds = xr.Dataset({name: ("x", array) for name, array in arrays.items()}) + units = {None: unit_registry.m, "y": unit_registry.s} func = method("to_stacked_array", "z", variable_dim="y", sample_dims=["x"]) actual = func(ds).rename(None) - expected = attach_units( - func(strip_units(ds)).rename(None), - {None: unit_registry.m, "y": unit_registry.s}, - ) + expected = attach_units(func(strip_units(ds)).rename(None), units,) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", From ab3e14c6ef4bed6334f33c74f66de24a7b9313d9 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 22:57:22 +0200 Subject: [PATCH 20/57] fix the stacking and reordering tests --- xarray/tests/test_units.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index e1d7895334f..413047a67cf 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4416,12 +4416,9 @@ def test_to_stacked_array(self, dtype): "func", ( method("transpose", "y", "x", "z1", "z2"), - method("stack", a=("x", "y")), + method("stack", u=("x", "y")), method("set_index", x="x2"), - pytest.param( - method("shift", x=2), - marks=pytest.mark.xfail(reason="tries to concatenate nan arrays"), - ), + method("shift", x=2), method("roll", x=2, roll_coords=False), method("sortby", "x2"), ), @@ -4446,18 +4443,18 @@ def test_stacking_reordering(self, func, dtype): ds = xr.Dataset( data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y", "z1")), - "b": xr.DataArray(data=array2, dims=("x", "y", "z2")), + "a": (("x", "y", "z1"), array1), + "b": (("x", "y", "z2"), array2), }, coords={"x": x, "y": y, "z1": z1, "z2": z2, "x2": ("x", x2)}, ) + units = extract_units(ds) - expected = attach_units( - func(strip_units(ds)), {"a": unit_registry.Pa, "b": unit_registry.degK} - ) + expected = attach_units(func(strip_units(ds)), units) actual = func(ds) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="indexes strip units") @pytest.mark.parametrize( From fb906871a8365061f118bea9de478f58da79967e Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 28 Apr 2020 23:00:01 +0200 Subject: [PATCH 21/57] don't create a coordinate for the isel tests --- xarray/tests/test_units.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 413047a67cf..d6dde908615 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4456,7 +4456,6 @@ def test_stacking_reordering(self, func, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - @pytest.mark.xfail(reason="indexes strip units") @pytest.mark.parametrize( "indices", ( @@ -4468,21 +4467,14 @@ def test_isel(self, indices, dtype): array1 = np.arange(10).astype(dtype) * unit_registry.s array2 = np.linspace(0, 1, 10).astype(dtype) * unit_registry.Pa - x = np.arange(len(array1)) * unit_registry.m - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims="x"), - "b": xr.DataArray(data=array2, dims="x"), - }, - coords={"x": x}, - ) + ds = xr.Dataset(data_vars={"a": ("x", array1), "b": ("x", array2)}) + units = extract_units(ds) - expected = attach_units( - strip_units(ds).isel(x=indices), - {"a": unit_registry.s, "b": unit_registry.Pa, "x": unit_registry.m}, - ) + expected = attach_units(strip_units(ds).isel(x=indices), units) actual = ds.isel(x=indices) + assert_units_equal(expected, actual) + assert_equal(expected, actual) assert_equal_with_units(expected, actual) @pytest.mark.xfail(reason="indexes don't support units") From e98c09bb746ea6e94e4bc298aac9dec83c3e5724 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 29 Apr 2020 16:02:53 +0200 Subject: [PATCH 22/57] separate the tests for units in dims from the tests for units in data --- xarray/tests/test_units.py | 51 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index d6dde908615..1c7a9962a67 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4262,40 +4262,43 @@ def test_comparisons(self, func, variant, unit, dtype): assert expected == actual + # TODO: eventually use another decorator / wrapper function that + # applies a filter to the parametrize combinations: + # we only need a single test for data @pytest.mark.parametrize( "unit", ( pytest.param(1, id="no_unit"), + pytest.param(unit_registry.dimensionless, id="dimensionless"), + pytest.param(unit_registry.s, id="incompatible_unit"), + pytest.param(unit_registry.cm, id="compatible_unit"), + pytest.param(unit_registry.m, id="identical_unit"), + ), + ) + @pytest.mark.parametrize( + "variant", + ( + "data", pytest.param( - unit_registry.dimensionless, - id="dimensionless", - marks=pytest.mark.skip(reason="IndexVariable does not support units"), - ), - pytest.param( - unit_registry.s, - id="incompatible_unit", - marks=pytest.mark.skip(reason="IndexVariable does not support units"), - ), - pytest.param( - unit_registry.cm, - id="compatible_unit", - marks=pytest.mark.skip(reason="IndexVariable does not support units"), - ), - pytest.param( - unit_registry.m, - id="identical_unit", + "dims", marks=pytest.mark.skip(reason="IndexVariable does not support units"), ), ), ) - def test_broadcast_like(self, unit, dtype): - array1 = np.linspace(1, 2, 2 * 1).reshape(2, 1).astype(dtype) * unit_registry.Pa - array2 = np.linspace(0, 1, 2 * 3).reshape(2, 3).astype(dtype) + def test_broadcast_like(self, variant, unit, dtype): + variants = { + "data": ((unit_registry.m, unit), (1, 1)), + "dims": ((1, 1), (unit_registry.m, unit)), + } + (data_unit1, data_unit2), (dim_unit1, dim_unit2) = variants.get(variant) - x1 = np.arange(2) * unit_registry.m - x2 = np.arange(2) * unit - y1 = np.array([0]) * unit_registry.m - y2 = np.arange(3) * unit + array1 = np.linspace(1, 2, 2 * 1).reshape(2, 1).astype(dtype) * data_unit1 + array2 = np.linspace(0, 1, 2 * 3).reshape(2, 3).astype(dtype) * data_unit2 + + x1 = np.arange(2) * dim_unit1 + x2 = np.arange(2) * dim_unit2 + y1 = np.array([0]) * dim_unit1 + y2 = np.arange(3) * dim_unit2 ds1 = xr.Dataset( data_vars={"a": (("x", "y"), array1)}, coords={"x": x1, "y": y1} From 3cb2c76243e933eeb22d85061791fcd7c205dc06 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 12:43:54 +0200 Subject: [PATCH 23/57] refactor the dataset constructor tests --- xarray/tests/test_units.py | 82 +++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 1e48112d162..67a97cc6427 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3660,11 +3660,11 @@ class TestDataset: @pytest.mark.parametrize( "unit,error", ( - pytest.param(1, DimensionalityError, id="no_unit"), + pytest.param(1, xr.MergeError, id="no_unit"), pytest.param( - unit_registry.dimensionless, DimensionalityError, id="dimensionless" + unit_registry.dimensionless, xr.MergeError, id="dimensionless" ), - pytest.param(unit_registry.s, DimensionalityError, id="incompatible_unit"), + pytest.param(unit_registry.s, xr.MergeError, id="incompatible_unit"), pytest.param(unit_registry.mm, None, id="compatible_unit"), pytest.param(unit_registry.m, None, id="same_unit"), ), @@ -3673,11 +3673,8 @@ class TestDataset: "shared", ( "nothing", - pytest.param("dims", marks=pytest.mark.xfail(reason="indexes strip units")), - pytest.param( - "coords", - marks=pytest.mark.xfail(reason="reindex does not work with pint yet"), - ), + pytest.param("dims", marks=pytest.mark.skip(reason="indexes strip units")), + "coords", ), ) def test_init(self, shared, unit, error, dtype): @@ -3685,60 +3682,53 @@ def test_init(self, shared, unit, error, dtype): scaled_unit = unit_registry.mm a = np.linspace(0, 1, 10).astype(dtype) * unit_registry.Pa - b = np.linspace(-1, 0, 12).astype(dtype) * unit_registry.Pa - - raw_x = np.arange(a.shape[0]) - x = raw_x * original_unit - x2 = x.to(scaled_unit) - - raw_y = np.arange(b.shape[0]) - y = raw_y * unit - y_units = unit if isinstance(y, unit_registry.Quantity) else None - if isinstance(y, unit_registry.Quantity): - if y.check(scaled_unit): - y2 = y.to(scaled_unit) - else: - y2 = y * 1000 - y2_units = y2.units - else: - y2 = y * 1000 - y2_units = None + b = np.linspace(-1, 0, 10).astype(dtype) * unit_registry.degK + + values_a = np.arange(a.shape[0]) + dim_a = values_a * original_unit + coord_a = dim_a.to(scaled_unit) + + values_b = np.arange(b.shape[0]) + dim_b = values_b * unit + coord_b = ( + dim_b.to(scaled_unit) + if unit_registry.is_compatible_with(dim_b, scaled_unit) + and unit != scaled_unit + else dim_b * 1000 + ) variants = { - "nothing": ({"x": x, "x2": ("x", x2)}, {"y": y, "y2": ("y", y2)}), - "dims": ( - {"x": x, "x2": ("x", strip_units(x2))}, - {"x": y, "y2": ("x", strip_units(y2))}, + "nothing": ({}, {}), + "dims": ({"x": dim_a}, {"x": dim_b}), + "coords": ( + {"x": values_a, "y": ("x", coord_a)}, + {"x": values_b, "y": ("x", coord_b)}, ), - "coords": ({"x": raw_x, "y": ("x", x2)}, {"x": raw_y, "y": ("x", y2)}), } coords_a, coords_b = variants.get(shared) dims_a, dims_b = ("x", "y") if shared == "nothing" else ("x", "x") - arr1 = xr.DataArray(data=a, coords=coords_a, dims=dims_a) - arr2 = xr.DataArray(data=b, coords=coords_b, dims=dims_b) + a = xr.DataArray(data=a, coords=coords_a, dims=dims_a) + b = xr.DataArray(data=b, coords=coords_b, dims=dims_b) + if error is not None and shared != "nothing": with pytest.raises(error): - xr.Dataset(data_vars={"a": arr1, "b": arr2}) + xr.Dataset(data_vars={"a": a, "b": b}) return - actual = xr.Dataset(data_vars={"a": arr1, "b": arr2}) + actual = xr.Dataset(data_vars={"a": a, "b": b}) - expected_units = { - "a": a.units, - "b": b.units, - "x": x.units, - "x2": x2.units, - "y": y_units, - "y2": y2_units, - } + units = dict( + merge_dicts(extract_units(a.rename("a")), extract_units(b.rename("b"))) + ) expected = attach_units( - xr.Dataset(data_vars={"a": strip_units(arr1), "b": strip_units(arr2)}), - expected_units, + xr.Dataset(data_vars={"a": strip_units(a), "b": strip_units(b)}), units ) - assert_equal_with_units(actual, expected) + + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", (pytest.param(str, id="str"), pytest.param(repr, id="repr")) From d6626eb941b04ca87187ea9bfd5832d80f1bd5e2 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 12:47:35 +0200 Subject: [PATCH 24/57] fix the repr tests --- xarray/tests/test_units.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 67a97cc6427..a5a3a72e8de 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3739,7 +3739,7 @@ def test_init(self, shared, unit, error, dtype): "data", pytest.param( "dims", - marks=pytest.mark.xfail(reason="units in indexes are not supported"), + marks=pytest.mark.skip(reason="units in indexes are not supported"), ), "coords", ), @@ -3757,8 +3757,8 @@ def test_repr(self, func, variant, dtype): y = x.to(unit_registry.ms) variants = { - "with_dims": {"x": x}, - "with_coords": {"y": ("x", y)}, + "dims": {"x": x}, + "coords": {"y": ("x", y)}, "data": {}, } From afdb6324bbf56bba09d6c356abb8a42de00ddb47 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 13:23:39 +0200 Subject: [PATCH 25/57] raise on all warnings --- xarray/tests/test_units.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index a5a3a72e8de..1e3456df603 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3677,6 +3677,7 @@ class TestDataset: "coords", ), ) + @pytest.mark.filterwarnings("error") def test_init(self, shared, unit, error, dtype): original_unit = unit_registry.m scaled_unit = unit_registry.mm @@ -3744,7 +3745,7 @@ def test_init(self, shared, unit, error, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error:::pint[.*]") + @pytest.mark.filterwarnings("error") def test_repr(self, func, variant, dtype): unit1, unit2 = ( (unit_registry.Pa, unit_registry.degK) if variant == "data" else (1, 1) From 3ac99e3ee4030f88f7a7d5b139bce0102d05e8bb Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 13:44:47 +0200 Subject: [PATCH 26/57] rename merge_mappings to zip_mappings --- xarray/tests/test_units.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 1e3456df603..12d16197aab 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -46,7 +46,7 @@ def dimensionality(obj): def compatible_mappings(first, second): return { key: is_compatible(unit1, unit2) - for key, (unit1, unit2) in merge_mappings(first, second) + for key, (unit1, unit2) in zip_mappings(first, second) } @@ -58,6 +58,11 @@ def merge_dicts(base, *mappings): return result +def zip_mappings(*mappings): + for key in set(mappings[0]).intersection(*mappings[1:]): + yield key, tuple(m[key] for m in mappings) + + def array_extract_units(obj): if isinstance(obj, (xr.Variable, xr.DataArray, xr.Dataset)): obj = obj.data @@ -299,11 +304,6 @@ def dtype(request): return request.param -def merge_mappings(*mappings): - for key in set(mappings[0]).intersection(*mappings[1:]): - yield key, tuple(m[key] for m in mappings) - - def merge_args(default_args, new_args): from itertools import zip_longest @@ -4286,7 +4286,7 @@ def test_comparisons(self, func, variant, unit, dtype): to_convert = { key: unit if is_compatible(unit, reference) else None - for key, (unit, reference) in merge_mappings(units, other_units) + for key, (unit, reference) in zip_mappings(units, other_units) } # convert units where possible, then attach all units to the converted dataset other = attach_units(strip_units(convert_units(ds, to_convert)), other_units) @@ -4296,7 +4296,7 @@ def test_comparisons(self, func, variant, unit, dtype): # convert and compare values equal_ds = all( is_compatible(unit, other_unit) - for _, (unit, other_unit) in merge_mappings(units, other_units) + for _, (unit, other_unit) in zip_mappings(units, other_units) ) and (strip_units(ds).equals(strip_units(convert_units(other, units)))) equal_units = units == other_units expected = equal_ds and (func.name != "identical" or equal_units) From cc0d03fb8135136eae8f80caa26f9cf8c26ee013 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 13:46:06 +0200 Subject: [PATCH 27/57] rename merge_dicts to merge_mappings --- xarray/tests/test_units.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 12d16197aab..ef79868a23d 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -50,7 +50,7 @@ def compatible_mappings(first, second): } -def merge_dicts(base, *mappings): +def merge_mappings(base, *mappings): result = base.copy() for m in mappings: result.update(m) @@ -3721,8 +3721,8 @@ def test_init(self, shared, unit, error, dtype): actual = xr.Dataset(data_vars={"a": a, "b": b}) - units = dict( - merge_dicts(extract_units(a.rename("a")), extract_units(b.rename("b"))) + units = merge_mappings( + extract_units(a.rename("a")), extract_units(b.rename("b")) ) expected = attach_units( xr.Dataset(data_vars={"a": strip_units(a), "b": strip_units(b)}), units @@ -4380,7 +4380,7 @@ def test_broadcast_equals(self, unit, dtype): ) right = xr.Dataset({"a": ("x", right_array1), "b": ("y", right_array2)}) - units = merge_dicts( + units = merge_mappings( extract_units(left), {} if is_compatible(left_array1, unit) else {"a": None, "b": None}, ) From 0a7e172bbc379919f7fe92b572a56567b0dcaba6 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 13:48:59 +0200 Subject: [PATCH 28/57] make the missing value filling tests raise on warnings --- xarray/tests/test_units.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index ef79868a23d..682f398e7a9 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3955,6 +3955,7 @@ def test_missing_value_detection(self, func, dtype): @pytest.mark.xfail(reason="ffill and bfill lose the unit") @pytest.mark.parametrize("func", (method("ffill"), method("bfill")), ids=repr) + @pytest.mark.filterwarnings("error") def test_missing_value_filling(self, func, dtype): array1 = ( np.array([1.4, np.nan, 2.3, np.nan, np.nan, 9.1]).astype(dtype) @@ -3968,7 +3969,7 @@ def test_missing_value_filling(self, func, dtype): ds = xr.Dataset({"a": ("x", array1), "b": ("y", array2)}) units = extract_units(ds) - expected = attach_units(func(strip_units(ds), dim="x"), units,) + expected = attach_units(func(strip_units(ds), dim="x"), units) actual = func(ds, dim="x") assert_units_equal(expected, actual) From 0469bc6dd415c6d09dc2a585b7bba4d7afb1c6b4 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 13:54:52 +0200 Subject: [PATCH 29/57] remove a leftover assert_equal_with_units --- xarray/tests/test_units.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 682f398e7a9..82838b4c25b 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4522,7 +4522,6 @@ def test_isel(self, indices, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - assert_equal_with_units(expected, actual) @pytest.mark.xfail(reason="indexes don't support units") @pytest.mark.parametrize( From 6ee9d847d4b020fb360125fa35481c2ef1e585fd Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 14:15:49 +0200 Subject: [PATCH 30/57] refactor the sel tests --- xarray/tests/test_units.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 82838b4c25b..51b1c046492 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4538,10 +4538,11 @@ def test_isel(self, indices, dtype): pytest.param(1, KeyError, id="no_units"), pytest.param(unit_registry.dimensionless, KeyError, id="dimensionless"), pytest.param(unit_registry.degree, KeyError, id="incompatible_unit"), - pytest.param(unit_registry.dm, KeyError, id="compatible_unit"), + pytest.param(unit_registry.mm, KeyError, id="compatible_unit"), pytest.param(unit_registry.m, None, id="identical_unit"), ), ) + @pytest.mark.filterwarnings("error") def test_sel(self, raw_values, unit, error, dtype): array1 = np.linspace(5, 10, 20).astype(dtype) * unit_registry.degK array2 = np.linspace(0, 5, 20).astype(dtype) * unit_registry.Pa @@ -4557,20 +4558,24 @@ def test_sel(self, raw_values, unit, error, dtype): values = raw_values * unit - if error is not None and not ( - isinstance(raw_values, (int, float)) and x.check(unit) - ): + # TODO: if we choose dm as compatible unit, single value keys + # can be found. Should we check that? + if error is not None: with pytest.raises(error): ds.sel(x=values) return expected = attach_units( - strip_units(ds).sel(x=strip_units(convert_units(values, {None: x.units}))), - {"a": array1.units, "b": array2.units, "x": x.units}, + strip_units(ds).sel( + x=strip_units(convert_units(values, {None: unit_registry.m})) + ), + extract_units(ds), ) actual = ds.sel(x=values) - assert_equal_with_units(expected, actual) + + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="indexes don't support units") @pytest.mark.parametrize( From cd6628d943e07a1261c96f710eeb9961df7ce33e Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 15:10:26 +0200 Subject: [PATCH 31/57] make the loc tests a slightly modified copy of the sel tests --- xarray/tests/test_units.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 51b1c046492..70f820091f1 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4643,10 +4643,11 @@ def test_drop_sel(self, raw_values, unit, error, dtype): pytest.param(1, KeyError, id="no_units"), pytest.param(unit_registry.dimensionless, KeyError, id="dimensionless"), pytest.param(unit_registry.degree, KeyError, id="incompatible_unit"), - pytest.param(unit_registry.dm, KeyError, id="compatible_unit"), + pytest.param(unit_registry.mm, KeyError, id="compatible_unit"), pytest.param(unit_registry.m, None, id="identical_unit"), ), ) + @pytest.mark.filterwarnings("error") def test_loc(self, raw_values, unit, error, dtype): array1 = np.linspace(5, 10, 20).astype(dtype) * unit_registry.degK array2 = np.linspace(0, 5, 20).astype(dtype) * unit_registry.Pa @@ -4662,9 +4663,9 @@ def test_loc(self, raw_values, unit, error, dtype): values = raw_values * unit - if error is not None and not ( - isinstance(raw_values, (int, float)) and x.check(unit) - ): + # TODO: if we choose dm as compatible unit, single value keys + # can be found. Should we check that? + if error is not None: with pytest.raises(error): ds.loc[{"x": values}] @@ -4672,12 +4673,14 @@ def test_loc(self, raw_values, unit, error, dtype): expected = attach_units( strip_units(ds).loc[ - {"x": strip_units(convert_units(values, {None: x.units}))} + {"x": strip_units(convert_units(values, {None: unit_registry.m}))} ], - {"a": array1.units, "b": array2.units, "x": x.units}, + extract_units(ds), ) actual = ds.loc[{"x": values}] - assert_equal_with_units(expected, actual) + + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", From 122355ca6dbf458e08490ac816f46f2e79eb7886 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 15:29:36 +0200 Subject: [PATCH 32/57] make the drop_sel tests a slightly modified version of the sel tests --- xarray/tests/test_units.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 70f820091f1..6337be3bead 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4592,10 +4592,11 @@ def test_sel(self, raw_values, unit, error, dtype): pytest.param(1, KeyError, id="no_units"), pytest.param(unit_registry.dimensionless, KeyError, id="dimensionless"), pytest.param(unit_registry.degree, KeyError, id="incompatible_unit"), - pytest.param(unit_registry.dm, KeyError, id="compatible_unit"), + pytest.param(unit_registry.mm, KeyError, id="compatible_unit"), pytest.param(unit_registry.m, None, id="identical_unit"), ), ) + @pytest.mark.filterwarnings("error") def test_drop_sel(self, raw_values, unit, error, dtype): array1 = np.linspace(5, 10, 20).astype(dtype) * unit_registry.degK array2 = np.linspace(0, 5, 20).astype(dtype) * unit_registry.Pa @@ -4611,9 +4612,9 @@ def test_drop_sel(self, raw_values, unit, error, dtype): values = raw_values * unit - if error is not None and not ( - isinstance(raw_values, (int, float)) and x.check(unit) - ): + # TODO: if we choose dm as compatible unit, single value keys + # can be found. Should we check that? + if error is not None: with pytest.raises(error): ds.drop_sel(x=values) @@ -4621,12 +4622,14 @@ def test_drop_sel(self, raw_values, unit, error, dtype): expected = attach_units( strip_units(ds).drop_sel( - x=strip_units(convert_units(values, {None: x.units})) + x=strip_units(convert_units(values, {None: unit_registry.m})) ), extract_units(ds), ) actual = ds.drop_sel(x=values) - assert_equal_with_units(expected, actual) + + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="indexes don't support units") @pytest.mark.parametrize( From a38e70c83ddfde48bb7482968686a13dab0a48bc Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 15:39:04 +0200 Subject: [PATCH 33/57] refactor the head / tail / thin tests --- xarray/tests/test_units.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 6337be3bead..1f1ee1716eb 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4694,14 +4694,26 @@ def test_loc(self, raw_values, unit, error, dtype): ), ids=repr, ) - def test_head_tail_thin(self, func, dtype): - array1 = np.linspace(1, 2, 10 * 5).reshape(10, 5) * unit_registry.degK - array2 = np.linspace(1, 2, 10 * 8).reshape(10, 8) * unit_registry.Pa + @pytest.mark.parametrize("variant", ("data", "dims", "coords")) + @pytest.mark.filterwarnings("error") + def test_head_tail_thin(self, func, variant, dtype): + variants = { + "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), + "dims": ((1, 1), unit_registry.m, 1), + "coords": ((1, 1), 1, unit_registry.m), + } + (unit_a, unit_b), dim_unit, coord_unit = variants.get(variant) + + array1 = np.linspace(1, 2, 10 * 5).reshape(10, 5) * unit_a + array2 = np.linspace(1, 2, 10 * 8).reshape(10, 8) * unit_b coords = { - "x": np.arange(10) * unit_registry.m, - "y": np.arange(5) * unit_registry.m, - "z": np.arange(8) * unit_registry.m, + "x": np.arange(10) * dim_unit, + "y": np.arange(5) * dim_unit, + "z": np.arange(8) * dim_unit, + "u": ("x", np.linspace(0, 1, 10) * coord_unit), + "v": ("y", np.linspace(1, 2, 5) * coord_unit), + "w": ("z", np.linspace(-1, 0, 8) * coord_unit), } ds = xr.Dataset( @@ -4715,7 +4727,8 @@ def test_head_tail_thin(self, func, dtype): expected = attach_units(func(strip_units(ds)), extract_units(ds)) actual = func(ds) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "shape", From e01cbb961fd7de14ad484a1164e5fb6a2976045a Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 15:46:03 +0200 Subject: [PATCH 34/57] refactor the squeeze tests to not have multiple tests per case --- xarray/tests/test_units.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 1f1ee1716eb..400f853d652 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4730,6 +4730,7 @@ def test_head_tail_thin(self, func, variant, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) + @pytest.mark.parametrize("dim", ("x", "y", "z", "t", "all")) @pytest.mark.parametrize( "shape", ( @@ -4740,7 +4741,7 @@ def test_head_tail_thin(self, func, variant, dtype): pytest.param((1, 10, 1, 20), id="first and last dimension squeezable"), ), ) - def test_squeeze(self, shape, dtype): + def test_squeeze(self, shape, dim, dtype): names = "xyzt" coords = { name: np.arange(length).astype(dtype) @@ -4763,17 +4764,14 @@ def test_squeeze(self, shape, dtype): ) units = extract_units(ds) - expected = attach_units(strip_units(ds).squeeze(), units) + kwargs = {"dim": dim} if dim != "all" and len(coords.get(dim, [])) == 1 else {} - actual = ds.squeeze() - assert_equal_with_units(actual, expected) + expected = attach_units(strip_units(ds).squeeze(**kwargs), units) - # try squeezing the dimensions separately - names = tuple(dim for dim, coord in coords.items() if len(coord) == 1) - for name in names: - expected = attach_units(strip_units(ds).squeeze(dim=name), units) - actual = ds.squeeze(dim=name) - assert_equal_with_units(actual, expected) + actual = ds.squeeze(**kwargs) + + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="ignores units") @pytest.mark.parametrize( From 37dcd50309e7b097757372ec76935ab1400cb4f7 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 16:13:20 +0200 Subject: [PATCH 35/57] skip the head / tail / thin tests with units in dimensions --- xarray/tests/test_units.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 400f853d652..17548308982 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4694,7 +4694,16 @@ def test_loc(self, raw_values, unit, error, dtype): ), ids=repr, ) - @pytest.mark.parametrize("variant", ("data", "dims", "coords")) + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", marks=pytest.mark.skip(reason="indexes don't support units") + ), + "coords", + ), + ) @pytest.mark.filterwarnings("error") def test_head_tail_thin(self, func, variant, dtype): variants = { From 2ab44b3b589263b757fc75d0d393cca2657d0e34 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 23:12:32 +0200 Subject: [PATCH 36/57] combine the interp and reindex tests --- xarray/tests/test_units.py | 130 +++++++++++++++---------------------- 1 file changed, 51 insertions(+), 79 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 17548308982..8070a5da807 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4782,7 +4782,43 @@ def test_squeeze(self, shape, dim, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - @pytest.mark.xfail(reason="ignores units") + @pytest.mark.parametrize("variant", ("data", "coords")) + @pytest.mark.parametrize( + "func", + ( + pytest.param(method("interp"), marks=pytest.mark.skip(reason="uses scipy")), + method("reindex"), + ), + ids=repr, + ) + @pytest.mark.filterwarnings("error") + def test_interp_reindex(self, func, variant, dtype): + variants = { + "data": (unit_registry.m, 1), + "coords": (1, unit_registry.m), + } + data_unit, coord_unit = variants.get(variant) + + array1 = np.linspace(-1, 0, 10).astype(dtype) * data_unit + array2 = np.linspace(0, 1, 10).astype(dtype) * data_unit + + y = np.arange(10) * coord_unit + + x = np.arange(10) + new_x = np.arange(10) + 0.5 + + ds = xr.Dataset( + {"a": ("x", array1), "b": ("x", array2)}, coords={"x": x, "y": ("x", y)} + ) + units = extract_units(ds) + + expected = attach_units(func(strip_units(ds), x=new_x), units) + actual = func(ds, x=new_x) + + assert_units_equal(expected, actual) + assert_equal(expected, actual) + + @pytest.mark.xfail(reason="indexes don't support units") @pytest.mark.parametrize( "unit,error", ( @@ -4795,40 +4831,29 @@ def test_squeeze(self, shape, dim, dtype): pytest.param(unit_registry.m, None, id="identical_unit"), ), ) - def test_interp(self, unit, error): - array1 = np.linspace(1, 2, 10 * 5).reshape(10, 5) * unit_registry.degK - array2 = np.linspace(1, 2, 10 * 8).reshape(10, 8) * unit_registry.Pa - - coords = { - "x": np.arange(10) * unit_registry.m, - "y": np.arange(5) * unit_registry.m, - "z": np.arange(8) * unit_registry.s, - } + @pytest.mark.parametrize("func", (method("interp"), method("reindex")), ids=repr) + @pytest.mark.filterwarnings("error") + def test_interp_reindex_indexing(self, func, unit, error, dtype): + array1 = np.linspace(-1, 0, 10).astype(dtype) + array2 = np.linspace(0, 1, 10).astype(dtype) - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "z")), - }, - coords=coords, - ) + x = np.arange(10) * unit_registry.m + new_x = (np.arange(10) + 0.5) * unit - new_coords = (np.arange(10) + 0.5) * unit + ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}, coords={"x": x}) + units = extract_units(ds) if error is not None: with pytest.raises(error): - ds.interp(x=new_coords) + func(ds, x=new_x) return - units = extract_units(ds) - expected = attach_units( - strip_units(ds).interp(x=strip_units(convert_units(new_coords, units))), - units, - ) - actual = ds.interp(x=new_coords) + expected = attach_units(func(strip_units(ds), x=new_x), units) + actual = func(ds, x=new_x) - assert_equal_with_units(actual, expected) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="ignores units") @pytest.mark.parametrize( @@ -4891,59 +4916,6 @@ def test_interp_like(self, unit, error, dtype): assert_equal_with_units(actual, expected) - @pytest.mark.xfail(reason="indexes don't support units") - @pytest.mark.parametrize( - "unit,error", - ( - pytest.param(1, DimensionalityError, id="no_unit"), - pytest.param( - unit_registry.dimensionless, DimensionalityError, id="dimensionless" - ), - pytest.param(unit_registry.s, DimensionalityError, id="incompatible_unit"), - pytest.param(unit_registry.cm, None, id="compatible_unit"), - pytest.param(unit_registry.m, None, id="identical_unit"), - ), - ) - def test_reindex(self, unit, error, dtype): - array1 = ( - np.linspace(1, 2, 10 * 5).reshape(10, 5).astype(dtype) * unit_registry.degK - ) - array2 = ( - np.linspace(1, 2, 10 * 8).reshape(10, 8).astype(dtype) * unit_registry.Pa - ) - - coords = { - "x": np.arange(10) * unit_registry.m, - "y": np.arange(5) * unit_registry.m, - "z": np.arange(8) * unit_registry.s, - } - - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "z")), - }, - coords=coords, - ) - - new_coords = (np.arange(10) + 0.5) * unit - - if error is not None: - with pytest.raises(error): - ds.reindex(x=new_coords) - - return - - expected = attach_units( - strip_units(ds).reindex( - x=strip_units(convert_units(new_coords, {None: coords["x"].units})) - ), - extract_units(ds), - ) - actual = ds.reindex(x=new_coords) - - assert_equal_with_units(actual, expected) - @pytest.mark.xfail(reason="indexes don't support units") @pytest.mark.parametrize( "unit,error", From a0936c85c974e70aa31939f501eac1eb72c14cb8 Mon Sep 17 00:00:00 2001 From: Keewis Date: Tue, 26 May 2020 23:35:17 +0200 Subject: [PATCH 37/57] combine the interp_like and reindex_like tests --- xarray/tests/test_units.py | 132 +++++++++++++------------------------ 1 file changed, 45 insertions(+), 87 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 8070a5da807..369132cc48c 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4805,7 +4805,7 @@ def test_interp_reindex(self, func, variant, dtype): y = np.arange(10) * coord_unit x = np.arange(10) - new_x = np.arange(10) + 0.5 + new_x = np.arange(8) + 0.5 ds = xr.Dataset( {"a": ("x", array1), "b": ("x", array2)}, coords={"x": x, "y": ("x", y)} @@ -4838,7 +4838,7 @@ def test_interp_reindex_indexing(self, func, unit, error, dtype): array2 = np.linspace(0, 1, 10).astype(dtype) x = np.arange(10) * unit_registry.m - new_x = (np.arange(10) + 0.5) * unit + new_x = (np.arange(8) + 0.5) * unit ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}, coords={"x": x}) units = extract_units(ds) @@ -4855,66 +4855,45 @@ def test_interp_reindex_indexing(self, func, unit, error, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - @pytest.mark.xfail(reason="ignores units") + @pytest.mark.parametrize("variant", ("data", "coords")) @pytest.mark.parametrize( - "unit,error", + "func", ( - pytest.param(1, DimensionalityError, id="no_unit"), pytest.param( - unit_registry.dimensionless, DimensionalityError, id="dimensionless" + method("interp_like"), marks=pytest.mark.skip(reason="uses scipy") ), - pytest.param(unit_registry.s, DimensionalityError, id="incompatible_unit"), - pytest.param(unit_registry.cm, None, id="compatible_unit"), - pytest.param(unit_registry.m, None, id="identical_unit"), + method("reindex_like"), ), + ids=repr, ) - def test_interp_like(self, unit, error, dtype): - array1 = ( - np.linspace(0, 10, 10 * 5).reshape(10, 5).astype(dtype) * unit_registry.degK - ) - array2 = ( - np.linspace(10, 20, 10 * 8).reshape(10, 8).astype(dtype) * unit_registry.Pa - ) - - coords = { - "x": np.arange(10) * unit_registry.m, - "y": np.arange(5) * unit_registry.m, - "z": np.arange(8) * unit_registry.m, + @pytest.mark.filterwarnings("error") + def test_interp_reindex_like(self, func, variant, dtype): + variants = { + "data": (unit_registry.m, 1), + "coords": (1, unit_registry.m), } + data_unit, coord_unit = variants.get(variant) - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "z")), - }, - coords=coords, - ) - - other = xr.Dataset( - data_vars={ - "c": xr.DataArray(data=np.empty((20, 10)), dims=("x", "y")), - "d": xr.DataArray(data=np.empty((20, 15)), dims=("x", "z")), - }, - coords={ - "x": (np.arange(20) + 0.3) * unit, - "y": (np.arange(10) - 0.2) * unit, - "z": (np.arange(15) + 0.4) * unit, - }, - ) + array1 = np.linspace(-1, 0, 10).astype(dtype) * data_unit + array2 = np.linspace(0, 1, 10).astype(dtype) * data_unit - if error is not None: - with pytest.raises(error): - ds.interp_like(other) + y = np.arange(10) * coord_unit - return + x = np.arange(10) + new_x = np.arange(8) + 0.5 - units = extract_units(ds) - expected = attach_units( - strip_units(ds).interp_like(strip_units(convert_units(other, units))), units + ds = xr.Dataset( + {"a": ("x", array1), "b": ("x", array2)}, coords={"x": x, "y": ("x", y)} ) - actual = ds.interp_like(other) + units = extract_units(ds) + + other = xr.Dataset({"a": ("x", np.empty_like(new_x))}, coords={"x": new_x}) + + expected = attach_units(func(strip_units(ds), other), units) + actual = func(ds, other) - assert_equal_with_units(actual, expected) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.xfail(reason="indexes don't support units") @pytest.mark.parametrize( @@ -4929,54 +4908,33 @@ def test_interp_like(self, unit, error, dtype): pytest.param(unit_registry.m, None, id="identical_unit"), ), ) - def test_reindex_like(self, unit, error, dtype): - array1 = ( - np.linspace(0, 10, 10 * 5).reshape(10, 5).astype(dtype) * unit_registry.degK - ) - array2 = ( - np.linspace(10, 20, 10 * 8).reshape(10, 8).astype(dtype) * unit_registry.Pa - ) + @pytest.mark.parametrize( + "func", (method("interp_like"), method("reindex_like")), ids=repr + ) + @pytest.mark.filterwarnings("error") + def test_interp_reindex_like_indexing(self, func, unit, error, dtype): + array1 = np.linspace(-1, 0, 10).astype(dtype) + array2 = np.linspace(0, 1, 10).astype(dtype) - coords = { - "x": np.arange(10) * unit_registry.m, - "y": np.arange(5) * unit_registry.m, - "z": np.arange(8) * unit_registry.m, - } + x = np.arange(10) * unit_registry.m + new_x = (np.arange(8) + 0.5) * unit - ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "z")), - }, - coords=coords, - ) + ds = xr.Dataset({"a": ("x", array1), "b": ("x", array2)}, coords={"x": x}) + units = extract_units(ds) - other = xr.Dataset( - data_vars={ - "c": xr.DataArray(data=np.empty((20, 10)), dims=("x", "y")), - "d": xr.DataArray(data=np.empty((20, 15)), dims=("x", "z")), - }, - coords={ - "x": (np.arange(20) + 0.3) * unit, - "y": (np.arange(10) - 0.2) * unit, - "z": (np.arange(15) + 0.4) * unit, - }, - ) + other = xr.Dataset({"a": ("x", np.empty_like(new_x))}, coords={"x": new_x}) if error is not None: with pytest.raises(error): - ds.reindex_like(other) + func(ds, other) return - units = extract_units(ds) - expected = attach_units( - strip_units(ds).reindex_like(strip_units(convert_units(other, units))), - units, - ) - actual = ds.reindex_like(other) + expected = attach_units(func(strip_units(ds), other), units) + actual = func(ds, other) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", From b7992c64ea20269a6b615c4a4c8c53b8080400d7 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 00:00:55 +0200 Subject: [PATCH 38/57] refactor the computation tests --- xarray/tests/test_units.py | 44 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 369132cc48c..94435ce8922 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4944,30 +4944,47 @@ def test_interp_reindex_like_indexing(self, func, unit, error, dtype): method("integrate", coord="x"), pytest.param( method("quantile", q=[0.25, 0.75]), - marks=pytest.mark.xfail(reason="nanquantile not implemented"), + marks=pytest.mark.xfail( + LooseVersion(pint.__version__) < "0.12", + reason="nanquantile not implemented yet", + ), ), method("reduce", func=np.sum, dim="x"), method("map", np.fabs), ), ids=repr, ) - def test_computation(self, func, dtype): - array1 = ( - np.linspace(-5, 5, 10 * 5).reshape(10, 5).astype(dtype) * unit_registry.degK - ) - array2 = ( - np.linspace(10, 20, 10 * 8).reshape(10, 8).astype(dtype) * unit_registry.Pa - ) - x = np.arange(10) * unit_registry.m - y = np.arange(5) * unit_registry.m - z = np.arange(8) * unit_registry.m + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", marks=pytest.mark.skip(reason="indexes don't support units") + ), + "coords", + ), + ) + @pytest.mark.filterwarnings("error") + def test_computation(self, func, variant, dtype): + variants = { + "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), + "dims": ((1, 1), unit_registry.m, 1), + "coords": ((1, 1), 1, unit_registry.m), + } + (unit1, unit2), dim_unit, coord_unit = variants.get(variant) + + array1 = np.linspace(-5, 5, 4 * 5).reshape(4, 5).astype(dtype) * unit1 + array2 = np.linspace(10, 20, 4 * 3).reshape(4, 3).astype(dtype) * unit2 + x = np.arange(4) * dim_unit + y = np.arange(5) * dim_unit + z = np.arange(3) * dim_unit ds = xr.Dataset( data_vars={ "a": xr.DataArray(data=array1, dims=("x", "y")), "b": xr.DataArray(data=array2, dims=("x", "z")), }, - coords={"x": x, "y": y, "z": z}, + coords={"x": x, "y": y, "z": z, "y2": ("y", np.arange(5) * coord_unit)}, ) units = extract_units(ds) @@ -4975,7 +4992,8 @@ def test_computation(self, func, dtype): expected = attach_units(func(strip_units(ds)), units) actual = func(ds) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", From 9f82fbca44be3a2b23f0a60807f41688187ba017 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 00:44:39 +0200 Subject: [PATCH 39/57] rewrite the computation objects tests --- xarray/tests/test_units.py | 50 +++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 94435ce8922..6c03f05a562 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -5011,33 +5011,43 @@ def test_computation(self, func, variant, dtype): ), ids=repr, ) - def test_computation_objects(self, func, dtype): - array1 = ( - np.linspace(-5, 5, 10 * 5).reshape(10, 5).astype(dtype) * unit_registry.degK - ) - array2 = ( - np.linspace(10, 20, 10 * 5 * 8).reshape(10, 5, 8).astype(dtype) - * unit_registry.Pa - ) - x = np.arange(10) * unit_registry.m - y = np.arange(5) * unit_registry.m - z = np.arange(8) * unit_registry.m + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", marks=pytest.mark.skip(reason="indexes don't support units") + ), + "coords", + ), + ) + @pytest.mark.filterwarnings("error") + def test_computation_objects(self, func, variant, dtype): + variants = { + "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), + "dims": ((1, 1), unit_registry.m, 1), + "coords": ((1, 1), 1, unit_registry.m), + } + (unit1, unit2), dim_unit, coord_unit = variants.get(variant) + + array1 = np.linspace(-5, 5, 4 * 5).reshape(4, 5).astype(dtype) * unit1 + array2 = np.linspace(10, 20, 4 * 3).reshape(4, 3).astype(dtype) * unit2 + x = np.arange(4) * dim_unit + y = np.arange(5) * dim_unit + z = np.arange(3) * dim_unit ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "y", "z")), - }, - coords={"x": x, "y": y, "z": z}, + data_vars={"a": (("x", "y"), array1), "b": (("x", "z"), array2)}, + coords={"x": x, "y": y, "z": z, "y2": ("y", np.arange(5) * coord_unit)}, ) units = extract_units(ds) args = [] if func.name != "groupby" else ["y"] - reduce_func = method("mean", *args) - expected = attach_units(reduce_func(func(strip_units(ds))), units) - actual = reduce_func(func(ds)) + expected = attach_units(func(strip_units(ds)).mean(*args), units) + actual = func(ds).mean(*args) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) def test_resample(self, dtype): array1 = ( From 4cf2ec9b469917132ec4b16542086fc773af249c Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 01:07:37 +0200 Subject: [PATCH 40/57] rewrite the resample tests --- xarray/tests/test_units.py | 46 +++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 6c03f05a562..50d29d43ce3 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -5049,23 +5049,38 @@ def test_computation_objects(self, func, variant, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - def test_resample(self, dtype): - array1 = ( - np.linspace(-5, 5, 10 * 5).reshape(10, 5).astype(dtype) * unit_registry.degK - ) - array2 = ( - np.linspace(10, 20, 10 * 8).reshape(10, 8).astype(dtype) * unit_registry.Pa - ) + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", marks=pytest.mark.skip(reason="indexes don't support units") + ), + "coords", + ), + ) + @pytest.mark.filterwarnings("error") + def test_resample(self, variant, dtype): + # TODO: move this to test_computation_objects + variants = { + "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), + "dims": ((1, 1), unit_registry.m, 1), + "coords": ((1, 1), 1, unit_registry.m), + } + (unit1, unit2), dim_unit, coord_unit = variants.get(variant) + + array1 = np.linspace(-5, 5, 10 * 5).reshape(10, 5).astype(dtype) * unit1 + array2 = np.linspace(10, 20, 10 * 8).reshape(10, 8).astype(dtype) * unit2 + t = pd.date_range("10-09-2010", periods=array1.shape[0], freq="1y") - y = np.arange(5) * unit_registry.m - z = np.arange(8) * unit_registry.m + y = np.arange(5) * dim_unit + z = np.arange(8) * dim_unit + + u = np.linspace(-1, 0, 5) * coord_unit ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("time", "y")), - "b": xr.DataArray(data=array2, dims=("time", "z")), - }, - coords={"time": t, "y": y, "z": z}, + data_vars={"a": (("time", "y"), array1), "b": (("time", "z"), array2)}, + coords={"time": t, "y": y, "z": z, "u": ("y", u)}, ) units = extract_units(ds) @@ -5074,7 +5089,8 @@ def test_resample(self, dtype): expected = attach_units(func(strip_units(ds)).mean(), units) actual = func(ds).mean() - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", From 2e168091c1442c8f25a5e4e318ce7519742fe2fe Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 01:16:59 +0200 Subject: [PATCH 41/57] rewrite the grouped operations tests --- xarray/tests/test_units.py | 54 ++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 50d29d43ce3..c2a874e74a0 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -5096,7 +5096,7 @@ def test_resample(self, variant, dtype): "func", ( method("assign", c=lambda ds: 10 * ds.b), - method("assign_coords", v=("x", np.arange(10) * unit_registry.s)), + method("assign_coords", v=("x", np.arange(5) * unit_registry.s)), method("first"), method("last"), pytest.param( @@ -5106,27 +5106,40 @@ def test_resample(self, variant, dtype): ), ids=repr, ) - def test_grouped_operations(self, func, dtype): - array1 = ( - np.linspace(-5, 5, 10 * 5).reshape(10, 5).astype(dtype) * unit_registry.degK - ) - array2 = ( - np.linspace(10, 20, 10 * 5 * 8).reshape(10, 5, 8).astype(dtype) - * unit_registry.Pa - ) - x = np.arange(10) * unit_registry.m - y = np.arange(5) * unit_registry.m - z = np.arange(8) * unit_registry.m + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", marks=pytest.mark.skip(reason="indexes don't support units") + ), + "coords", + ), + ) + @pytest.mark.filterwarnings("error") + def test_grouped_operations(self, func, variant, dtype): + variants = { + "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), + "dims": ((1, 1), unit_registry.m, 1), + "coords": ((1, 1), 1, unit_registry.m), + } + (unit1, unit2), dim_unit, coord_unit = variants.get(variant) + + array1 = np.linspace(-5, 5, 5 * 4).reshape(5, 4).astype(dtype) * unit1 + array2 = np.linspace(10, 20, 5 * 4 * 3).reshape(5, 4, 3).astype(dtype) * unit2 + x = np.arange(5) * dim_unit + y = np.arange(4) * dim_unit + z = np.arange(3) * dim_unit + + u = np.linspace(-1, 0, 4) * coord_unit ds = xr.Dataset( - data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "y", "z")), - }, - coords={"x": x, "y": y, "z": z}, + data_vars={"a": (("x", "y"), array1), "b": (("x", "y", "z"), array2)}, + coords={"x": x, "y": y, "z": z, "u": ("y", u)}, ) - units = extract_units(ds) - units.update({"c": unit_registry.Pa, "v": unit_registry.s}) + + assigned_units = {"c": unit2, "v": unit_registry.s} + units = merge_mappings(extract_units(ds), assigned_units) stripped_kwargs = { name: strip_units(value) for name, value in func.kwargs.items() @@ -5136,7 +5149,8 @@ def test_grouped_operations(self, func, dtype): ) actual = func(ds.groupby("y")) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "func", From 0242a13b42c9ab9127c0718ba2b2636b2eae24cb Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 01:46:05 +0200 Subject: [PATCH 42/57] rewrite the content manipulation tests --- xarray/tests/test_units.py | 82 ++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index c2a874e74a0..e5e8f30d98e 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -5157,13 +5157,18 @@ def test_grouped_operations(self, func, variant, dtype): ( method("pipe", lambda ds: ds * 10), method("assign", d=lambda ds: ds.b * 10), - method("assign_coords", y2=("y", np.arange(5) * unit_registry.mm)), + method("assign_coords", y2=("y", np.arange(4) * unit_registry.mm)), method("assign_attrs", attr1="value"), method("rename", x2="x_mm"), method("rename_vars", c="temperature"), method("rename_dims", x="offset_x"), - method("swap_dims", {"x": "x2"}), - method("expand_dims", v=np.linspace(10, 20, 12) * unit_registry.s, axis=1), + method("swap_dims", {"x": "u"}), + pytest.param( + method( + "expand_dims", v=np.linspace(10, 20, 12) * unit_registry.s, axis=1 + ), + marks=pytest.mark.skip(reason="indexes don't support units"), + ), method("drop_vars", "x"), method("drop_dims", "z"), method("set_coords", names="c"), @@ -5172,40 +5177,56 @@ def test_grouped_operations(self, func, variant, dtype): ), ids=repr, ) - def test_content_manipulation(self, func, dtype): - array1 = ( - np.linspace(-5, 5, 10 * 5).reshape(10, 5).astype(dtype) - * unit_registry.m ** 3 - ) - array2 = ( - np.linspace(10, 20, 10 * 5 * 8).reshape(10, 5, 8).astype(dtype) - * unit_registry.Pa - ) - array3 = np.linspace(0, 10, 10).astype(dtype) * unit_registry.degK + @pytest.mark.parametrize( + "variant", + ( + "data", + pytest.param( + "dims", marks=pytest.mark.skip(reason="indexes don't support units") + ), + "coords", + ), + ) + @pytest.mark.filterwarnings("error") + def test_content_manipulation(self, func, variant, dtype): + variants = { + "data": ( + (unit_registry.m ** 3, unit_registry.Pa, unit_registry.degK), + 1, + 1, + ), + "dims": ((1, 1, 1), unit_registry.m, 1), + "coords": ((1, 1, 1), 1, unit_registry.m), + } + (unit1, unit2, unit3), dim_unit, coord_unit = variants.get(variant) - x = np.arange(10) * unit_registry.m - x2 = x.to(unit_registry.mm) - y = np.arange(5) * unit_registry.m - z = np.arange(8) * unit_registry.m + array1 = np.linspace(-5, 5, 5 * 4).reshape(5, 4).astype(dtype) * unit1 + array2 = np.linspace(10, 20, 5 * 4 * 3).reshape(5, 4, 3).astype(dtype) * unit2 + array3 = np.linspace(0, 10, 5).astype(dtype) * unit3 + + x = np.arange(5) * dim_unit + y = np.arange(4) * dim_unit + z = np.arange(3) * dim_unit + + x2 = np.linspace(-1, 0, 5) * coord_unit ds = xr.Dataset( data_vars={ - "a": xr.DataArray(data=array1, dims=("x", "y")), - "b": xr.DataArray(data=array2, dims=("x", "y", "z")), - "c": xr.DataArray(data=array3, dims="x"), + "a": (("x", "y"), array1), + "b": (("x", "y", "z"), array2), + "c": ("x", array3), }, coords={"x": x, "y": y, "z": z, "x2": ("x", x2)}, ) - units = { - **extract_units(ds), - **{ - "y2": unit_registry.mm, - "x_mm": unit_registry.mm, - "offset_x": unit_registry.m, - "d": unit_registry.Pa, - "temperature": unit_registry.degK, - }, + + new_units = { + "y2": unit_registry.mm, + "x_mm": coord_unit, + "offset_x": unit_registry.m, + "d": unit2, + "temperature": unit3, } + units = merge_mappings(extract_units(ds), new_units) stripped_kwargs = { key: strip_units(value) for key, value in func.kwargs.items() @@ -5213,7 +5234,8 @@ def test_content_manipulation(self, func, dtype): expected = attach_units(func(strip_units(ds), **stripped_kwargs), units) actual = func(ds) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) @pytest.mark.parametrize( "unit,error", From e52707c0f8839de973acb064c65e2fbe4ddd6297 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 01:53:50 +0200 Subject: [PATCH 43/57] refactor the merge tests --- xarray/tests/test_units.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index e5e8f30d98e..4159326953e 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -5259,26 +5259,31 @@ def test_content_manipulation(self, func, variant, dtype): "coords", ), ) + @pytest.mark.filterwarnings("error") def test_merge(self, variant, unit, error, dtype): - original_data_unit = unit_registry.m - original_dim_unit = unit_registry.m - original_coord_unit = unit_registry.m + left_variants = { + "data": (unit_registry.m, 1, 1), + "dims": (1, unit_registry.m, 1), + "coords": (1, 1, unit_registry.m), + } - variants = { - "data": (unit, original_dim_unit, original_coord_unit), - "dims": (original_data_unit, unit, original_coord_unit), - "coords": (original_data_unit, original_dim_unit, unit), + left_data_unit, left_dim_unit, left_coord_unit = left_variants.get(variant) + + right_variants = { + "data": (unit, 1, 1), + "dims": (1, unit, 1), + "coords": (1, 1, unit), } - data_unit, dim_unit, coord_unit = variants.get(variant) + right_data_unit, right_dim_unit, right_coord_unit = right_variants.get(variant) - left_array = np.arange(10).astype(dtype) * original_data_unit - right_array = np.arange(-5, 5).astype(dtype) * data_unit + left_array = np.arange(10).astype(dtype) * left_data_unit + right_array = np.arange(-5, 5).astype(dtype) * right_data_unit - left_dim = np.arange(10, 20) * original_dim_unit - right_dim = np.arange(5, 15) * dim_unit + left_dim = np.arange(10, 20) * left_dim_unit + right_dim = np.arange(5, 15) * right_dim_unit - left_coord = np.arange(-10, 0) * original_coord_unit - right_coord = np.arange(-15, -5) * coord_unit + left_coord = np.arange(-10, 0) * left_coord_unit + right_coord = np.arange(-15, -5) * right_coord_unit left = xr.Dataset( data_vars={"a": ("x", left_array)}, @@ -5301,4 +5306,5 @@ def test_merge(self, variant, unit, error, dtype): expected = attach_units(strip_units(left).merge(strip_units(converted)), units) actual = left.merge(right) - assert_equal_with_units(expected, actual) + assert_units_equal(expected, actual) + assert_equal(expected, actual) From 58d5bb132d2798f39e9d4fdd2c3fc2dfc771848a Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 01:54:55 +0200 Subject: [PATCH 44/57] remove the old assert_equal_with_units function --- xarray/tests/test_units.py | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 4159326953e..7ba008a62be 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -7,7 +7,6 @@ import pytest import xarray as xr -from xarray.core import formatting from xarray.core.npcompat import IS_NEP18_ACTIVE from xarray.testing import assert_allclose, assert_equal, assert_identical @@ -265,40 +264,6 @@ def assert_units_equal(a, b): assert extract_units(a) == extract_units(b) -def assert_equal_with_units(a, b): - # works like xr.testing.assert_equal, but also explicitly checks units - # so, it is more like assert_identical - __tracebackhide__ = True - - if isinstance(a, xr.Dataset) or isinstance(b, xr.Dataset): - a_units = extract_units(a) - b_units = extract_units(b) - - a_without_units = strip_units(a) - b_without_units = strip_units(b) - - assert a_without_units.equals(b_without_units), formatting.diff_dataset_repr( - a, b, "equals" - ) - assert a_units == b_units - else: - a = a if not isinstance(a, (xr.DataArray, xr.Variable)) else a.data - b = b if not isinstance(b, (xr.DataArray, xr.Variable)) else b.data - - assert type(a) == type(b) or ( - isinstance(a, Quantity) and isinstance(b, Quantity) - ) - - # workaround until pint implements allclose in __array_function__ - if isinstance(a, Quantity) or isinstance(b, Quantity): - assert ( - hasattr(a, "magnitude") and hasattr(b, "magnitude") - ) and np.allclose(a.magnitude, b.magnitude, equal_nan=True) - assert (hasattr(a, "units") and hasattr(b, "units")) and a.units == b.units - else: - assert np.allclose(a, b, equal_nan=True) - - @pytest.fixture(params=[float, int]) def dtype(request): return request.param From fec4b9fa78211a9d65931b887472cb2413603461 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 02:25:58 +0200 Subject: [PATCH 45/57] xfail the groupby_bins tests for now --- xarray/tests/test_units.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 7ba008a62be..d16238dab19 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4964,7 +4964,13 @@ def test_computation(self, func, variant, dtype): "func", ( method("groupby", "x"), - method("groupby_bins", "x", bins=4), + pytest.param( + method("groupby_bins", "x", bins=2), + marks=pytest.mark.xfail( + LooseVersion(pint.__version__) < "0.12", + reason="needs assert_allclose but that does not work with pint", + ), + ), method("coarsen", x=2), pytest.param( method("rolling", x=3), marks=pytest.mark.xfail(reason="strips units") From 1a50af8d7d05de27390c8c534414f687af2969bb Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 13:11:57 +0200 Subject: [PATCH 46/57] fix and use allclose --- xarray/testing.py | 6 +++--- xarray/tests/test_units.py | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/xarray/testing.py b/xarray/testing.py index e7bf5f9221a..ab971ac55ec 100644 --- a/xarray/testing.py +++ b/xarray/testing.py @@ -121,7 +121,7 @@ def assert_allclose(a, b, rtol=1e-05, atol=1e-08, decode_bytes=True): kwargs = dict(rtol=rtol, atol=atol, decode_bytes=decode_bytes) if isinstance(a, Variable): assert a.dims == b.dims - allclose = _data_allclose_or_equiv(a.values, b.values, **kwargs) + allclose = _data_allclose_or_equiv(a.data, b.data, **kwargs) assert allclose, f"{a.values}\n{b.values}" elif isinstance(a, DataArray): assert_allclose(a.variable, b.variable, **kwargs) @@ -130,9 +130,9 @@ def assert_allclose(a, b, rtol=1e-05, atol=1e-08, decode_bytes=True): # can't recurse with this function as coord is sometimes a # DataArray, so call into _data_allclose_or_equiv directly allclose = _data_allclose_or_equiv( - a.coords[v].values, b.coords[v].values, **kwargs + a.coords[v].data, b.coords[v].data, **kwargs ) - assert allclose, "{}\n{}".format(a.coords[v].values, b.coords[v].values) + assert allclose, "{}\n{}".format(a.coords[v].data, b.coords[v].data) elif isinstance(a, Dataset): assert set(a.data_vars) == set(b.data_vars) assert set(a.coords) == set(b.coords) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index d16238dab19..cf74093973a 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4100,6 +4100,7 @@ def test_where(self, variant, unit, error, dtype): assert_equal(expected, actual) @pytest.mark.xfail(reason="interpolate_na uses numpy.vectorize") + @pytest.mark.filterwarnings("error") def test_interpolate_na(self, dtype): array1 = ( np.array([1.4, np.nan, 2.3, np.nan, np.nan, 9.1]).astype(dtype) @@ -5018,7 +5019,11 @@ def test_computation_objects(self, func, variant, dtype): actual = func(ds).mean(*args) assert_units_equal(expected, actual) - assert_equal(expected, actual) + # TODO: remove once pint 0.12 has been released + if LooseVersion(pint.__version__) < "0.12": + assert_equal(expected, actual) + else: + assert_allclose(expected, actual) @pytest.mark.parametrize( "variant", From cbeb8c63f674e2cce43c6855d40bd9479f3c78e6 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 13:14:13 +0200 Subject: [PATCH 47/57] filterwarnings for the whole TestDataset class --- xarray/tests/test_units.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index cf74093973a..9167549a0fc 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3621,6 +3621,7 @@ def test_grouped_operations(self, func, dtype): xr.testing.assert_identical(expected, actual) +@pytest.mark.filterwarnings("error") class TestDataset: @pytest.mark.parametrize( "unit,error", @@ -3642,7 +3643,6 @@ class TestDataset: "coords", ), ) - @pytest.mark.filterwarnings("error") def test_init(self, shared, unit, error, dtype): original_unit = unit_registry.m scaled_unit = unit_registry.mm @@ -3710,7 +3710,6 @@ def test_init(self, shared, unit, error, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_repr(self, func, variant, dtype): unit1, unit2 = ( (unit_registry.Pa, unit_registry.degK) if variant == "data" else (1, 1) @@ -3920,7 +3919,6 @@ def test_missing_value_detection(self, func, dtype): @pytest.mark.xfail(reason="ffill and bfill lose the unit") @pytest.mark.parametrize("func", (method("ffill"), method("bfill")), ids=repr) - @pytest.mark.filterwarnings("error") def test_missing_value_filling(self, func, dtype): array1 = ( np.array([1.4, np.nan, 2.3, np.nan, np.nan, 9.1]).astype(dtype) @@ -4100,7 +4098,6 @@ def test_where(self, variant, unit, error, dtype): assert_equal(expected, actual) @pytest.mark.xfail(reason="interpolate_na uses numpy.vectorize") - @pytest.mark.filterwarnings("error") def test_interpolate_na(self, dtype): array1 = ( np.array([1.4, np.nan, 2.3, np.nan, np.nan, 9.1]).astype(dtype) @@ -4508,7 +4505,6 @@ def test_isel(self, indices, dtype): pytest.param(unit_registry.m, None, id="identical_unit"), ), ) - @pytest.mark.filterwarnings("error") def test_sel(self, raw_values, unit, error, dtype): array1 = np.linspace(5, 10, 20).astype(dtype) * unit_registry.degK array2 = np.linspace(0, 5, 20).astype(dtype) * unit_registry.Pa @@ -4562,7 +4558,6 @@ def test_sel(self, raw_values, unit, error, dtype): pytest.param(unit_registry.m, None, id="identical_unit"), ), ) - @pytest.mark.filterwarnings("error") def test_drop_sel(self, raw_values, unit, error, dtype): array1 = np.linspace(5, 10, 20).astype(dtype) * unit_registry.degK array2 = np.linspace(0, 5, 20).astype(dtype) * unit_registry.Pa @@ -4616,7 +4611,6 @@ def test_drop_sel(self, raw_values, unit, error, dtype): pytest.param(unit_registry.m, None, id="identical_unit"), ), ) - @pytest.mark.filterwarnings("error") def test_loc(self, raw_values, unit, error, dtype): array1 = np.linspace(5, 10, 20).astype(dtype) * unit_registry.degK array2 = np.linspace(0, 5, 20).astype(dtype) * unit_registry.Pa @@ -4670,7 +4664,6 @@ def test_loc(self, raw_values, unit, error, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_head_tail_thin(self, func, variant, dtype): variants = { "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), @@ -4757,7 +4750,6 @@ def test_squeeze(self, shape, dim, dtype): ), ids=repr, ) - @pytest.mark.filterwarnings("error") def test_interp_reindex(self, func, variant, dtype): variants = { "data": (unit_registry.m, 1), @@ -4798,7 +4790,6 @@ def test_interp_reindex(self, func, variant, dtype): ), ) @pytest.mark.parametrize("func", (method("interp"), method("reindex")), ids=repr) - @pytest.mark.filterwarnings("error") def test_interp_reindex_indexing(self, func, unit, error, dtype): array1 = np.linspace(-1, 0, 10).astype(dtype) array2 = np.linspace(0, 1, 10).astype(dtype) @@ -4832,7 +4823,6 @@ def test_interp_reindex_indexing(self, func, unit, error, dtype): ), ids=repr, ) - @pytest.mark.filterwarnings("error") def test_interp_reindex_like(self, func, variant, dtype): variants = { "data": (unit_registry.m, 1), @@ -4877,7 +4867,6 @@ def test_interp_reindex_like(self, func, variant, dtype): @pytest.mark.parametrize( "func", (method("interp_like"), method("reindex_like")), ids=repr ) - @pytest.mark.filterwarnings("error") def test_interp_reindex_like_indexing(self, func, unit, error, dtype): array1 = np.linspace(-1, 0, 10).astype(dtype) array2 = np.linspace(0, 1, 10).astype(dtype) @@ -4930,7 +4919,6 @@ def test_interp_reindex_like_indexing(self, func, unit, error, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_computation(self, func, variant, dtype): variants = { "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), @@ -4993,7 +4981,6 @@ def test_computation(self, func, variant, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_computation_objects(self, func, variant, dtype): variants = { "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), @@ -5035,7 +5022,6 @@ def test_computation_objects(self, func, variant, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_resample(self, variant, dtype): # TODO: move this to test_computation_objects variants = { @@ -5092,7 +5078,6 @@ def test_resample(self, variant, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_grouped_operations(self, func, variant, dtype): variants = { "data": ((unit_registry.degK, unit_registry.Pa), 1, 1), @@ -5163,7 +5148,6 @@ def test_grouped_operations(self, func, variant, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_content_manipulation(self, func, variant, dtype): variants = { "data": ( @@ -5235,7 +5219,6 @@ def test_content_manipulation(self, func, variant, dtype): "coords", ), ) - @pytest.mark.filterwarnings("error") def test_merge(self, variant, unit, error, dtype): left_variants = { "data": (unit_registry.m, 1, 1), From 980839f6d9c228a811f16b34bed077c86cb3713e Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 13:14:48 +0200 Subject: [PATCH 48/57] modify the squeeze tests to not use units in indexes --- xarray/tests/test_units.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 9167549a0fc..5ab5dad483d 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -4711,11 +4711,7 @@ def test_head_tail_thin(self, func, variant, dtype): ) def test_squeeze(self, shape, dim, dtype): names = "xyzt" - coords = { - name: np.arange(length).astype(dtype) - * (unit_registry.m if name != "t" else unit_registry.s) - for name, length in zip(names, shape) - } + dim_lengths = dict(zip(names, shape)) array1 = ( np.linspace(0, 1, 10 * 20).astype(dtype).reshape(shape) * unit_registry.degK ) @@ -4725,14 +4721,13 @@ def test_squeeze(self, shape, dim, dtype): ds = xr.Dataset( data_vars={ - "a": xr.DataArray(data=array1, dims=tuple(names[: len(shape)])), - "b": xr.DataArray(data=array2, dims=tuple(names[: len(shape)])), + "a": (tuple(names[: len(shape)]), array1), + "b": (tuple(names[: len(shape)]), array2), }, - coords=coords, ) units = extract_units(ds) - kwargs = {"dim": dim} if dim != "all" and len(coords.get(dim, [])) == 1 else {} + kwargs = {"dim": dim} if dim != "all" and dim_lengths.get(dim, 0) == 1 else {} expected = attach_units(strip_units(ds).squeeze(**kwargs), units) From 29b9250d5a09166bc6ff5811b53d9be958e92b72 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 13:21:32 +0200 Subject: [PATCH 49/57] replace skip with xfail --- xarray/tests/test_units.py | 40 ++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 5ab5dad483d..a4f30490a6b 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3639,7 +3639,9 @@ class TestDataset: "shared", ( "nothing", - pytest.param("dims", marks=pytest.mark.skip(reason="indexes strip units")), + pytest.param( + "dims", marks=pytest.mark.xfail(reason="indexes don't support units") + ), "coords", ), ) @@ -3705,7 +3707,7 @@ def test_init(self, shared, unit, error, dtype): "data", pytest.param( "dims", - marks=pytest.mark.skip(reason="units in indexes are not supported"), + marks=pytest.mark.xfail(reason="units in indexes are not supported"), ), "coords", ), @@ -4133,8 +4135,7 @@ def test_interpolate_na(self, dtype): ( "data", pytest.param( - "dims", - marks=pytest.mark.skip(reason="units not supported by IndexVariable"), + "dims", marks=pytest.mark.xfail(reason="indexes don't support units"), ), ), ) @@ -4195,7 +4196,7 @@ def test_combine_first(self, variant, unit, error, dtype): ( "data", pytest.param( - "dims", marks=pytest.mark.skip(reason="units in indexes not supported") + "dims", marks=pytest.mark.xfail(reason="units in indexes not supported") ), "coords", ), @@ -4287,8 +4288,7 @@ def test_comparisons(self, func, variant, unit, dtype): ( "data", pytest.param( - "dims", - marks=pytest.mark.skip(reason="IndexVariable does not support units"), + "dims", marks=pytest.mark.xfail(reason="indexes don't support units"), ), ), ) @@ -4333,6 +4333,7 @@ def test_broadcast_like(self, variant, unit, dtype): ), ) def test_broadcast_equals(self, unit, dtype): + # TODO: does this use indexes? left_array1 = np.ones(shape=(2, 3), dtype=dtype) * unit_registry.m left_array2 = np.zeros(shape=(3, 6), dtype=dtype) * unit_registry.m @@ -4365,8 +4366,7 @@ def test_broadcast_equals(self, unit, dtype): ( "data", pytest.param( - "dims", - marks=pytest.mark.skip(reason="units not supported in IndexVariable"), + "dims", marks=pytest.mark.xfail(reason="indexes don't support units"), ), ), ) @@ -4401,7 +4401,7 @@ def test_stacking_stacked(self, variant, func, dtype): assert_units_equal(expected, actual) assert_equal(expected, actual) - @pytest.mark.skip( + @pytest.mark.xfail( reason="stacked dimension's labels have to be hashable, but is a numpy.array" ) def test_to_stacked_array(self, dtype): @@ -4659,7 +4659,7 @@ def test_loc(self, raw_values, unit, error, dtype): ( "data", pytest.param( - "dims", marks=pytest.mark.skip(reason="indexes don't support units") + "dims", marks=pytest.mark.xfail(reason="indexes don't support units") ), "coords", ), @@ -4740,7 +4740,9 @@ def test_squeeze(self, shape, dim, dtype): @pytest.mark.parametrize( "func", ( - pytest.param(method("interp"), marks=pytest.mark.skip(reason="uses scipy")), + pytest.param( + method("interp"), marks=pytest.mark.xfail(reason="uses scipy") + ), method("reindex"), ), ids=repr, @@ -4812,7 +4814,7 @@ def test_interp_reindex_indexing(self, func, unit, error, dtype): "func", ( pytest.param( - method("interp_like"), marks=pytest.mark.skip(reason="uses scipy") + method("interp_like"), marks=pytest.mark.xfail(reason="uses scipy") ), method("reindex_like"), ), @@ -4909,7 +4911,7 @@ def test_interp_reindex_like_indexing(self, func, unit, error, dtype): ( "data", pytest.param( - "dims", marks=pytest.mark.skip(reason="indexes don't support units") + "dims", marks=pytest.mark.xfail(reason="indexes don't support units") ), "coords", ), @@ -4971,7 +4973,7 @@ def test_computation(self, func, variant, dtype): ( "data", pytest.param( - "dims", marks=pytest.mark.skip(reason="indexes don't support units") + "dims", marks=pytest.mark.xfail(reason="indexes don't support units") ), "coords", ), @@ -5012,7 +5014,7 @@ def test_computation_objects(self, func, variant, dtype): ( "data", pytest.param( - "dims", marks=pytest.mark.skip(reason="indexes don't support units") + "dims", marks=pytest.mark.xfail(reason="indexes don't support units") ), "coords", ), @@ -5068,7 +5070,7 @@ def test_resample(self, variant, dtype): ( "data", pytest.param( - "dims", marks=pytest.mark.skip(reason="indexes don't support units") + "dims", marks=pytest.mark.xfail(reason="indexes don't support units") ), "coords", ), @@ -5123,7 +5125,7 @@ def test_grouped_operations(self, func, variant, dtype): method( "expand_dims", v=np.linspace(10, 20, 12) * unit_registry.s, axis=1 ), - marks=pytest.mark.skip(reason="indexes don't support units"), + marks=pytest.mark.xfail(reason="indexes don't support units"), ), method("drop_vars", "x"), method("drop_dims", "z"), @@ -5138,7 +5140,7 @@ def test_grouped_operations(self, func, variant, dtype): ( "data", pytest.param( - "dims", marks=pytest.mark.skip(reason="indexes don't support units") + "dims", marks=pytest.mark.xfail(reason="indexes don't support units") ), "coords", ), From bee75046b44ff1d47257427bb6931b52bd243a4f Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 13:23:25 +0200 Subject: [PATCH 50/57] update whats-new.rst --- doc/whats-new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 59c7faa8973..50cf04d9115 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -69,7 +69,7 @@ New Features - Support dask handling for :py:meth:`DataArray.idxmax`, :py:meth:`DataArray.idxmin`, :py:meth:`Dataset.idxmax`, :py:meth:`Dataset.idxmin`. (:pull:`3922`) By `Kai Mühlbauer `_. -- More support for unit aware arrays with pint (:pull:`3643`) +- More support for unit aware arrays with pint (:pull:`3643`, :pull:`3975`) By `Justus Magin `_. - Support overriding existing variables in ``to_zarr()`` with ``mode='a'`` even without ``append_dim``, as long as dimension sizes do not change. From 918fdd8854ea34a8965b0a86b2c73682ada1f9ea Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 27 May 2020 13:32:43 +0200 Subject: [PATCH 51/57] update the xfail reason for the rolling_exp tests --- xarray/tests/test_units.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index a4f30490a6b..997bd24d864 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3540,7 +3540,9 @@ def test_computation(self, func, dtype): ), pytest.param( method("rolling_exp", y=3), - marks=pytest.mark.xfail(reason="units not supported by numbagg"), + marks=pytest.mark.xfail( + reason="numbagg functions are not supported by pint" + ), ), ), ids=repr, @@ -4963,7 +4965,9 @@ def test_computation(self, func, variant, dtype): ), pytest.param( method("rolling_exp", x=3), - marks=pytest.mark.xfail(reason="uses numbagg which strips units"), + marks=pytest.mark.xfail( + reason="numbagg functions are not supported by pint" + ), ), ), ids=repr, From c27a393a5b68656af3e9b27e687db839638820b6 Mon Sep 17 00:00:00 2001 From: Keewis Date: Mon, 1 Jun 2020 17:21:49 +0200 Subject: [PATCH 52/57] temporarily use pip to install pint since the feedstock seems to take a while --- ci/requirements/py36-min-nep18.yml | 3 ++- ci/requirements/py36.yml | 2 +- ci/requirements/py37-windows.yml | 2 +- ci/requirements/py37.yml | 2 +- ci/requirements/py38-all-but-dask.yml | 2 +- ci/requirements/py38.yml | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ci/requirements/py36-min-nep18.yml b/ci/requirements/py36-min-nep18.yml index a5eded49cd4..029fb44d26b 100644 --- a/ci/requirements/py36-min-nep18.yml +++ b/ci/requirements/py36-min-nep18.yml @@ -11,7 +11,6 @@ dependencies: - msgpack-python=0.6 # remove once distributed is bumped. distributed GH3491 - numpy=1.17 - pandas=0.25 - - pint=0.11 - pip - pytest - pytest-cov @@ -19,3 +18,5 @@ dependencies: - scipy=1.2 - setuptools=41.2 - sparse=0.8 + - pip: + - pint=0.12 diff --git a/ci/requirements/py36.yml b/ci/requirements/py36.yml index a500173f277..aa2baf9dcce 100644 --- a/ci/requirements/py36.yml +++ b/ci/requirements/py36.yml @@ -28,7 +28,6 @@ dependencies: - numba - numpy - pandas - - pint - pip - pseudonetcdf - pydap @@ -45,3 +44,4 @@ dependencies: - zarr - pip: - numbagg + - pint diff --git a/ci/requirements/py37-windows.yml b/ci/requirements/py37-windows.yml index e9e5c7a900a..8b12704d644 100644 --- a/ci/requirements/py37-windows.yml +++ b/ci/requirements/py37-windows.yml @@ -28,7 +28,6 @@ dependencies: - numba - numpy - pandas - - pint - pip - pseudonetcdf - pydap @@ -45,3 +44,4 @@ dependencies: - zarr - pip: - numbagg + - pint diff --git a/ci/requirements/py37.yml b/ci/requirements/py37.yml index dba3926596e..70c453e8776 100644 --- a/ci/requirements/py37.yml +++ b/ci/requirements/py37.yml @@ -28,7 +28,6 @@ dependencies: - numba - numpy - pandas - - pint - pip - pseudonetcdf - pydap @@ -45,3 +44,4 @@ dependencies: - zarr - pip: - numbagg + - pint diff --git a/ci/requirements/py38-all-but-dask.yml b/ci/requirements/py38-all-but-dask.yml index a375d9e1e5a..6d76eecbd6a 100644 --- a/ci/requirements/py38-all-but-dask.yml +++ b/ci/requirements/py38-all-but-dask.yml @@ -25,7 +25,6 @@ dependencies: - numba - numpy - pandas - - pint - pip - pseudonetcdf - pydap @@ -42,3 +41,4 @@ dependencies: - zarr - pip: - numbagg + - pint diff --git a/ci/requirements/py38.yml b/ci/requirements/py38.yml index 24602f884e9..4dcd4db51dc 100644 --- a/ci/requirements/py38.yml +++ b/ci/requirements/py38.yml @@ -28,7 +28,6 @@ dependencies: - numba - numpy - pandas - - pint - pip - pseudonetcdf - pydap @@ -45,3 +44,4 @@ dependencies: - zarr - pip: - numbagg + - pint From a89183454ef207be5a2b657866b980ae902b1ed1 Mon Sep 17 00:00:00 2001 From: Keewis Date: Mon, 15 Jun 2020 01:57:28 +0200 Subject: [PATCH 53/57] don't use pip to install pint --- ci/requirements/py36-min-nep18.yml | 3 +-- ci/requirements/py36.yml | 2 +- ci/requirements/py37-windows.yml | 2 +- ci/requirements/py37.yml | 2 +- ci/requirements/py38-all-but-dask.yml | 2 +- ci/requirements/py38.yml | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ci/requirements/py36-min-nep18.yml b/ci/requirements/py36-min-nep18.yml index 3c3b3c4b660..48b9c057260 100644 --- a/ci/requirements/py36-min-nep18.yml +++ b/ci/requirements/py36-min-nep18.yml @@ -11,6 +11,7 @@ dependencies: - msgpack-python=0.6 # remove once distributed is bumped. distributed GH3491 - numpy=1.17 - pandas=0.25 + - pint - pip - pytest - pytest-cov @@ -18,5 +19,3 @@ dependencies: - scipy=1.2 - setuptools=41.2 - sparse=0.8 - - pip: - - pint=0.12 diff --git a/ci/requirements/py36.yml b/ci/requirements/py36.yml index aa2baf9dcce..a500173f277 100644 --- a/ci/requirements/py36.yml +++ b/ci/requirements/py36.yml @@ -28,6 +28,7 @@ dependencies: - numba - numpy - pandas + - pint - pip - pseudonetcdf - pydap @@ -44,4 +45,3 @@ dependencies: - zarr - pip: - numbagg - - pint diff --git a/ci/requirements/py37-windows.yml b/ci/requirements/py37-windows.yml index 8b12704d644..e9e5c7a900a 100644 --- a/ci/requirements/py37-windows.yml +++ b/ci/requirements/py37-windows.yml @@ -28,6 +28,7 @@ dependencies: - numba - numpy - pandas + - pint - pip - pseudonetcdf - pydap @@ -44,4 +45,3 @@ dependencies: - zarr - pip: - numbagg - - pint diff --git a/ci/requirements/py37.yml b/ci/requirements/py37.yml index 70c453e8776..dba3926596e 100644 --- a/ci/requirements/py37.yml +++ b/ci/requirements/py37.yml @@ -28,6 +28,7 @@ dependencies: - numba - numpy - pandas + - pint - pip - pseudonetcdf - pydap @@ -44,4 +45,3 @@ dependencies: - zarr - pip: - numbagg - - pint diff --git a/ci/requirements/py38-all-but-dask.yml b/ci/requirements/py38-all-but-dask.yml index 6d76eecbd6a..a375d9e1e5a 100644 --- a/ci/requirements/py38-all-but-dask.yml +++ b/ci/requirements/py38-all-but-dask.yml @@ -25,6 +25,7 @@ dependencies: - numba - numpy - pandas + - pint - pip - pseudonetcdf - pydap @@ -41,4 +42,3 @@ dependencies: - zarr - pip: - numbagg - - pint diff --git a/ci/requirements/py38.yml b/ci/requirements/py38.yml index 4dcd4db51dc..24602f884e9 100644 --- a/ci/requirements/py38.yml +++ b/ci/requirements/py38.yml @@ -28,6 +28,7 @@ dependencies: - numba - numpy - pandas + - pint - pip - pseudonetcdf - pydap @@ -44,4 +45,3 @@ dependencies: - zarr - pip: - numbagg - - pint From 9a5d5fe6ee2124e6a1923a5fcd87641772acb0dd Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 17 Jun 2020 19:42:08 +0200 Subject: [PATCH 54/57] update the xfail to require at least 0.12.1 --- xarray/tests/test_units.py | 53 ++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 59380ef3ba4..ab38065f31b 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -395,7 +395,7 @@ def test_apply_ufunc_dataset(dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize( "unit,error", @@ -486,7 +486,7 @@ def test_align_dataarray(fill_value, variant, unit, error, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize( "unit,error", @@ -907,7 +907,7 @@ def test_concat_dataset(variant, unit, error, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize( "unit,error", @@ -1018,7 +1018,7 @@ def test_merge_dataarray(variant, unit, error, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize( "unit,error", @@ -1398,7 +1398,7 @@ def example_1d_objects(self): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) def test_real_and_imag(self): super().test_real_and_imag() @@ -1442,7 +1442,7 @@ def test_aggregation(self, func, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) def test_aggregate_complex(self): variable = xr.Variable("x", [1, 2j, np.nan] * unit_registry.m) @@ -1454,7 +1454,7 @@ def test_aggregate_complex(self): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize( "func", @@ -1756,7 +1756,7 @@ def test_isel(self, indices, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize( "unit,error", @@ -1896,7 +1896,7 @@ def test_squeeze(self, dtype): pytest.param( method("quantile", q=[0.25, 0.75]), marks=pytest.mark.xfail( - LooseVersion(pint.__version__) < "0.12", + LooseVersion(pint.__version__) <= "0.12", reason="quantile / nanquantile not implemented yet", ), ), @@ -2236,7 +2236,7 @@ def test_repr(self, func, variant, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose", + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose", ) @pytest.mark.parametrize( "func", @@ -3299,7 +3299,7 @@ def test_head_tail_thin(self, func, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize("variant", ("data", "coords")) @pytest.mark.parametrize( @@ -3376,7 +3376,7 @@ def test_interp_reindex_indexing(self, func, unit, error, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize("variant", ("data", "coords")) @pytest.mark.parametrize( @@ -3545,7 +3545,7 @@ def test_stacking_reordering(self, func, dtype): pytest.param( method("quantile", q=[0.25, 0.75]), marks=pytest.mark.xfail( - LooseVersion(pint.__version__) < "0.12", + LooseVersion(pint.__version__) <= "0.12", reason="quantile / nanquantile not implemented yet", ), ), @@ -3582,7 +3582,7 @@ def test_computation(self, func, dtype): # TODO: remove once pint==0.12 has been released @pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.11", reason="pint bug in isclose" + LooseVersion(pint.__version__) <= "0.12", reason="pint bug in isclose" ) @pytest.mark.parametrize( "func", @@ -3646,7 +3646,7 @@ def test_resample(self, dtype): pytest.param( method("quantile", q=[0.25, 0.5, 0.75], dim="x"), marks=pytest.mark.xfail( - LooseVersion(pint.__version__) < "0.12", + LooseVersion(pint.__version__) <= "0.12", reason="quantile / nanquantile not implemented yet", ), ), @@ -3815,7 +3815,10 @@ def test_repr(self, func, variant, dtype): function("sum"), pytest.param( function("prod"), - marks=pytest.mark.xfail(reason="not implemented by pint"), + marks=pytest.mark.xfail( + LooseVersion(pint.__version__) <= "0.12", + reason="not implemented by pint", + ), ), function("std"), function("var"), @@ -3832,7 +3835,10 @@ def test_repr(self, func, variant, dtype): method("sum"), pytest.param( method("prod"), - marks=pytest.mark.xfail(reason="not implemented by pint"), + marks=pytest.mark.xfail( + LooseVersion(pint.__version__) <= "0.12", + reason="not implemented by pint", + ), ), method("std"), method("var"), @@ -4100,7 +4106,7 @@ def test_isin(self, unit, dtype): expected = strip_units(ds).isin(strip_units(converted_values)) # TODO: use `unit_registry.is_compatible_with(unit, unit_registry.m)` instead. - # Needs `pint>=0.12`, though, so we probably should wait until that is released. + # Needs `pint>=0.12.1`, though, so we probably should wait until that is released. if not is_compatible(unit, unit_registry.m): expected.a[:] = False expected.b[:] = False @@ -4957,7 +4963,7 @@ def test_interp_reindex_like_indexing(self, func, unit, error, dtype): pytest.param( method("quantile", q=[0.25, 0.75]), marks=pytest.mark.xfail( - LooseVersion(pint.__version__) < "0.12", + LooseVersion(pint.__version__) <= "0.12", reason="nanquantile not implemented yet", ), ), @@ -5013,7 +5019,7 @@ def test_computation(self, func, variant, dtype): pytest.param( method("groupby_bins", "x", bins=2), marks=pytest.mark.xfail( - LooseVersion(pint.__version__) < "0.12", + LooseVersion(pint.__version__) <= "0.12", reason="needs assert_allclose but that does not work with pint", ), ), @@ -5066,7 +5072,7 @@ def test_computation_objects(self, func, variant, dtype): assert_units_equal(expected, actual) # TODO: remove once pint 0.12 has been released - if LooseVersion(pint.__version__) < "0.12": + if LooseVersion(pint.__version__) <= "0.12": assert_equal(expected, actual) else: assert_allclose(expected, actual) @@ -5122,7 +5128,10 @@ def test_resample(self, variant, dtype): method("last"), pytest.param( method("quantile", q=[0.25, 0.5, 0.75], dim="x"), - marks=pytest.mark.xfail(reason="nanquantile not implemented"), + marks=pytest.mark.xfail( + LooseVersion(pint.__version__) <= "0.12", + reason="nanquantile not implemented", + ), ), ), ids=repr, From 4463bf49fa29e3d0037e08f4883b793df45cd22c Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 17 Jun 2020 19:58:23 +0200 Subject: [PATCH 55/57] xfail the prod tests --- xarray/tests/test_units.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index ab38065f31b..190720cc71f 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3815,10 +3815,7 @@ def test_repr(self, func, variant, dtype): function("sum"), pytest.param( function("prod"), - marks=pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.12", - reason="not implemented by pint", - ), + marks=pytest.mark.xfail(reason="prod does not work with dataset yet",), ), function("std"), function("var"), @@ -3835,10 +3832,7 @@ def test_repr(self, func, variant, dtype): method("sum"), pytest.param( method("prod"), - marks=pytest.mark.xfail( - LooseVersion(pint.__version__) <= "0.12", - reason="not implemented by pint", - ), + marks=pytest.mark.xfail(reason="prod does not work with dataset yet",), ), method("std"), method("var"), From 94138a0ca2325e9339dceb5909caabd1a0cc7962 Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 17 Jun 2020 21:22:30 +0200 Subject: [PATCH 56/57] filter only UnitStrippedWarning --- xarray/tests/test_units.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index 190720cc71f..dc2240a07ac 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3681,7 +3681,7 @@ def test_grouped_operations(self, func, dtype): xr.testing.assert_identical(expected, actual) -@pytest.mark.filterwarnings("error") +@pytest.mark.filterwarnings("error::pint.UnitStrippedWarning") class TestDataset: @pytest.mark.parametrize( "unit,error", From 91b95a4960f727d3d0715361b1c20cde2409126d Mon Sep 17 00:00:00 2001 From: Keewis Date: Wed, 17 Jun 2020 21:55:52 +0200 Subject: [PATCH 57/57] remove unncessary commas --- xarray/tests/test_units.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py index dc2240a07ac..b477e8cccb2 100644 --- a/xarray/tests/test_units.py +++ b/xarray/tests/test_units.py @@ -3815,7 +3815,7 @@ def test_repr(self, func, variant, dtype): function("sum"), pytest.param( function("prod"), - marks=pytest.mark.xfail(reason="prod does not work with dataset yet",), + marks=pytest.mark.xfail(reason="prod does not work with dataset yet"), ), function("std"), function("var"), @@ -3832,7 +3832,7 @@ def test_repr(self, func, variant, dtype): method("sum"), pytest.param( method("prod"), - marks=pytest.mark.xfail(reason="prod does not work with dataset yet",), + marks=pytest.mark.xfail(reason="prod does not work with dataset yet"), ), method("std"), method("var"),