None:
with pytest.raises(ValueError):
date_range(start, end, periods, freq, inclusive=inclusive, use_cftime=True) # type: ignore[arg-type]
diff --git a/xarray/tests/test_coding_strings.py b/xarray/tests/test_coding_strings.py
index 17179a44a8a..e7971a311f5 100644
--- a/xarray/tests/test_coding_strings.py
+++ b/xarray/tests/test_coding_strings.py
@@ -139,6 +139,45 @@ def test_CharacterArrayCoder_char_dim_name(original, expected_char_dim_name) ->
assert roundtripped.dims[-1] == original.dims[-1]
+@pytest.mark.parametrize(
+ [
+ "original",
+ "expected_char_dim_name",
+ "expected_char_dim_length",
+ "warning_message",
+ ],
+ [
+ (
+ Variable(("x",), [b"ab", b"cde"], encoding={"char_dim_name": "foo4"}),
+ "foo3",
+ 3,
+ "String dimension naming mismatch",
+ ),
+ (
+ Variable(
+ ("x",),
+ [b"ab", b"cde"],
+ encoding={"original_shape": (2, 4), "char_dim_name": "foo"},
+ ),
+ "foo3",
+ 3,
+ "String dimension length mismatch",
+ ),
+ ],
+)
+def test_CharacterArrayCoder_dim_mismatch_warnings(
+ original, expected_char_dim_name, expected_char_dim_length, warning_message
+) -> None:
+ coder = strings.CharacterArrayCoder()
+ with pytest.warns(UserWarning, match=warning_message):
+ encoded = coder.encode(original)
+ roundtripped = coder.decode(encoded)
+ assert encoded.dims[-1] == expected_char_dim_name
+ assert encoded.sizes[expected_char_dim_name] == expected_char_dim_length
+ assert roundtripped.encoding["char_dim_name"] == expected_char_dim_name
+ assert roundtripped.dims[-1] == original.dims[-1]
+
+
def test_StackedBytesArray() -> None:
array = np.array([[b"a", b"b", b"c"], [b"d", b"e", b"f"]], dtype="S")
actual = strings.StackedBytesArray(array)
diff --git a/xarray/tests/test_coding_times.py b/xarray/tests/test_coding_times.py
index 8a021d4d2d5..af29716fec0 100644
--- a/xarray/tests/test_coding_times.py
+++ b/xarray/tests/test_coding_times.py
@@ -2,7 +2,7 @@
import warnings
from datetime import datetime, timedelta
-from itertools import product
+from itertools import product, starmap
from typing import Literal
import numpy as np
@@ -20,7 +20,6 @@
)
from xarray.coders import CFDatetimeCoder, CFTimedeltaCoder
from xarray.coding.times import (
- _INVALID_LITERAL_TIMEDELTA64_ENCODING_KEYS,
_encode_datetime_with_cftime,
_netcdf_to_numpy_timeunit,
_numpy_to_netcdf_timeunit,
@@ -576,7 +575,7 @@ def test_infer_datetime_units_with_NaT(dates, expected) -> None:
@pytest.mark.parametrize(("date_args", "expected"), _CFTIME_DATETIME_UNITS_TESTS)
def test_infer_cftime_datetime_units(calendar, date_args, expected) -> None:
date_type = _all_cftime_date_types()[calendar]
- dates = [date_type(*args) for args in date_args]
+ dates = list(starmap(date_type, date_args))
assert expected == infer_datetime_units(dates)
@@ -1824,8 +1823,9 @@ def test_encode_cf_timedelta_small_dtype_missing_value(use_dask) -> None:
assert_equal(variable, decoded)
-_DECODE_TIMEDELTA_TESTS = {
+_DECODE_TIMEDELTA_VIA_UNITS_TESTS = {
"default": (True, None, np.dtype("timedelta64[ns]"), True),
+ "decode_timedelta=True": (True, True, np.dtype("timedelta64[ns]"), False),
"decode_timedelta=False": (True, False, np.dtype("int64"), False),
"inherit-time_unit-from-decode_times": (
CFDatetimeCoder(time_unit="s"),
@@ -1856,16 +1856,16 @@ def test_encode_cf_timedelta_small_dtype_missing_value(use_dask) -> None:
@pytest.mark.parametrize(
("decode_times", "decode_timedelta", "expected_dtype", "warns"),
- list(_DECODE_TIMEDELTA_TESTS.values()),
- ids=list(_DECODE_TIMEDELTA_TESTS.keys()),
+ list(_DECODE_TIMEDELTA_VIA_UNITS_TESTS.values()),
+ ids=list(_DECODE_TIMEDELTA_VIA_UNITS_TESTS.keys()),
)
-def test_decode_timedelta(
+def test_decode_timedelta_via_units(
decode_times, decode_timedelta, expected_dtype, warns
) -> None:
timedeltas = pd.timedelta_range(0, freq="D", periods=3)
- encoding = {"units": "days"}
- var = Variable(["time"], timedeltas, encoding=encoding)
- encoded = conventions.encode_cf_variable(var)
+ attrs = {"units": "days"}
+ var = Variable(["time"], timedeltas, encoding=attrs)
+ encoded = Variable(["time"], np.array([0, 1, 2]), attrs=attrs)
if warns:
with pytest.warns(FutureWarning, match="decode_timedelta"):
decoded = conventions.decode_cf_variable(
@@ -1885,6 +1885,57 @@ def test_decode_timedelta(
assert decoded.dtype == expected_dtype
+_DECODE_TIMEDELTA_VIA_DTYPE_TESTS = {
+ "default": (True, None, np.dtype("timedelta64[ns]")),
+ "decode_timedelta=False": (True, False, np.dtype("int64")),
+ "decode_timedelta=True": (True, True, np.dtype("timedelta64[ns]")),
+ "inherit-time_unit-from-decode_times": (
+ CFDatetimeCoder(time_unit="s"),
+ None,
+ np.dtype("timedelta64[s]"),
+ ),
+ "set-time_unit-via-CFTimedeltaCoder-decode_times=True": (
+ True,
+ CFTimedeltaCoder(time_unit="s"),
+ np.dtype("timedelta64[s]"),
+ ),
+ "set-time_unit-via-CFTimedeltaCoder-decode_times=False": (
+ False,
+ CFTimedeltaCoder(time_unit="s"),
+ np.dtype("timedelta64[s]"),
+ ),
+ "override-time_unit-from-decode_times": (
+ CFDatetimeCoder(time_unit="ns"),
+ CFTimedeltaCoder(time_unit="s"),
+ np.dtype("timedelta64[s]"),
+ ),
+}
+
+
+@pytest.mark.parametrize(
+ ("decode_times", "decode_timedelta", "expected_dtype"),
+ list(_DECODE_TIMEDELTA_VIA_DTYPE_TESTS.values()),
+ ids=list(_DECODE_TIMEDELTA_VIA_DTYPE_TESTS.keys()),
+)
+def test_decode_timedelta_via_dtype(
+ decode_times, decode_timedelta, expected_dtype
+) -> None:
+ timedeltas = pd.timedelta_range(0, freq="D", periods=3)
+ encoding = {"units": "days"}
+ var = Variable(["time"], timedeltas, encoding=encoding)
+ encoded = conventions.encode_cf_variable(var)
+ assert encoded.attrs["dtype"] == "timedelta64[ns]"
+ assert encoded.attrs["units"] == encoding["units"]
+ decoded = conventions.decode_cf_variable(
+ "foo", encoded, decode_times=decode_times, decode_timedelta=decode_timedelta
+ )
+ if decode_timedelta is False:
+ assert_equal(encoded, decoded)
+ else:
+ assert_equal(var, decoded)
+ assert decoded.dtype == expected_dtype
+
+
def test_lazy_decode_timedelta_unexpected_dtype() -> None:
attrs = {"units": "seconds"}
encoded = Variable(["time"], [0, 0.5, 1], attrs=attrs)
@@ -1940,7 +1991,12 @@ def test_duck_array_decode_times(calendar) -> None:
def test_decode_timedelta_mask_and_scale(
decode_timedelta: bool, mask_and_scale: bool
) -> None:
- attrs = {"units": "nanoseconds", "_FillValue": np.int16(-1), "add_offset": 100000.0}
+ attrs = {
+ "dtype": "timedelta64[ns]",
+ "units": "nanoseconds",
+ "_FillValue": np.int16(-1),
+ "add_offset": 100000.0,
+ }
encoded = Variable(["time"], np.array([0, -1, 1], "int16"), attrs=attrs)
decoded = conventions.decode_cf_variable(
"foo", encoded, mask_and_scale=mask_and_scale, decode_timedelta=decode_timedelta
@@ -1958,19 +2014,17 @@ def test_decode_floating_point_timedelta_no_serialization_warning() -> None:
decoded.load()
-def test_literal_timedelta64_coding(time_unit: PDDatetimeUnitOptions) -> None:
+def test_timedelta64_coding_via_dtype(time_unit: PDDatetimeUnitOptions) -> None:
timedeltas = np.array([0, 1, "NaT"], dtype=f"timedelta64[{time_unit}]")
variable = Variable(["time"], timedeltas)
- expected_dtype = f"timedelta64[{time_unit}]"
expected_units = _numpy_to_netcdf_timeunit(time_unit)
encoded = conventions.encode_cf_variable(variable)
- assert encoded.attrs["dtype"] == expected_dtype
+ assert encoded.attrs["dtype"] == f"timedelta64[{time_unit}]"
assert encoded.attrs["units"] == expected_units
- assert encoded.attrs["_FillValue"] == np.iinfo(np.int64).min
decoded = conventions.decode_cf_variable("timedeltas", encoded)
- assert decoded.encoding["dtype"] == expected_dtype
+ assert decoded.encoding["dtype"] == np.dtype("int64")
assert decoded.encoding["units"] == expected_units
assert_identical(decoded, variable)
@@ -1981,7 +2035,7 @@ def test_literal_timedelta64_coding(time_unit: PDDatetimeUnitOptions) -> None:
assert reencoded.dtype == encoded.dtype
-def test_literal_timedelta_coding_non_pandas_coarse_resolution_warning() -> None:
+def test_timedelta_coding_via_dtype_non_pandas_coarse_resolution_warning() -> None:
attrs = {"dtype": "timedelta64[D]", "units": "days"}
encoded = Variable(["time"], [0, 1, 2], attrs=attrs)
with pytest.warns(UserWarning, match="xarray only supports"):
@@ -1994,7 +2048,7 @@ def test_literal_timedelta_coding_non_pandas_coarse_resolution_warning() -> None
@pytest.mark.xfail(reason="xarray does not recognize picoseconds as time-like")
-def test_literal_timedelta_coding_non_pandas_fine_resolution_warning() -> None:
+def test_timedelta_coding_via_dtype_non_pandas_fine_resolution_warning() -> None:
attrs = {"dtype": "timedelta64[ps]", "units": "picoseconds"}
encoded = Variable(["time"], [0, 1000, 2000], attrs=attrs)
with pytest.warns(UserWarning, match="xarray only supports"):
@@ -2006,17 +2060,16 @@ def test_literal_timedelta_coding_non_pandas_fine_resolution_warning() -> None:
assert decoded.dtype == np.dtype("timedelta64[ns]")
-@pytest.mark.parametrize("attribute", ["dtype", "units"])
-def test_literal_timedelta_decode_invalid_encoding(attribute) -> None:
+def test_timedelta_decode_via_dtype_invalid_encoding() -> None:
attrs = {"dtype": "timedelta64[s]", "units": "seconds"}
- encoding = {attribute: "foo"}
+ encoding = {"units": "foo"}
encoded = Variable(["time"], [0, 1, 2], attrs=attrs, encoding=encoding)
with pytest.raises(ValueError, match="failed to prevent"):
conventions.decode_cf_variable("timedeltas", encoded)
@pytest.mark.parametrize("attribute", ["dtype", "units"])
-def test_literal_timedelta_encode_invalid_attribute(attribute) -> None:
+def test_timedelta_encode_via_dtype_invalid_attribute(attribute) -> None:
timedeltas = pd.timedelta_range(0, freq="D", periods=3)
attrs = {attribute: "foo"}
variable = Variable(["time"], timedeltas, attrs=attrs)
@@ -2024,23 +2077,6 @@ def test_literal_timedelta_encode_invalid_attribute(attribute) -> None:
conventions.encode_cf_variable(variable)
-@pytest.mark.parametrize("invalid_key", _INVALID_LITERAL_TIMEDELTA64_ENCODING_KEYS)
-def test_literal_timedelta_encoding_invalid_key_error(invalid_key) -> None:
- encoding = {invalid_key: 1.0}
- timedeltas = pd.timedelta_range(0, freq="D", periods=3)
- variable = Variable(["time"], timedeltas, encoding=encoding)
- with pytest.raises(ValueError, match=invalid_key):
- conventions.encode_cf_variable(variable)
-
-
-@pytest.mark.parametrize("invalid_key", _INVALID_LITERAL_TIMEDELTA64_ENCODING_KEYS)
-def test_literal_timedelta_decoding_invalid_key_error(invalid_key) -> None:
- attrs = {invalid_key: 1.0, "dtype": "timedelta64[s]", "units": "seconds"}
- variable = Variable(["time"], [0, 1, 2], attrs=attrs)
- with pytest.raises(ValueError, match=invalid_key):
- conventions.decode_cf_variable("foo", variable)
-
-
@pytest.mark.parametrize(
("decode_via_units", "decode_via_dtype", "attrs", "expect_timedelta64"),
[
@@ -2058,12 +2094,6 @@ def test_literal_timedelta_decoding_invalid_key_error(invalid_key) -> None:
def test_timedelta_decoding_options(
decode_via_units, decode_via_dtype, attrs, expect_timedelta64
) -> None:
- # Note with literal timedelta encoding, we always add a _FillValue, even
- # if one is not present in the original encoding parameters, which is why
- # we ensure one is defined here when "dtype" is present in attrs.
- if "dtype" in attrs:
- attrs["_FillValue"] = np.iinfo(np.int64).min
-
array = np.array([0, 1, 2], dtype=np.dtype("int64"))
encoded = Variable(["time"], array, attrs=attrs)
@@ -2083,7 +2113,11 @@ def test_timedelta_decoding_options(
# Confirm we exactly roundtrip.
reencoded = conventions.encode_cf_variable(decoded)
- assert_identical(reencoded, encoded)
+
+ expected = encoded.copy()
+ if "dtype" not in attrs and decode_via_units:
+ expected.attrs["dtype"] = "timedelta64[s]"
+ assert_identical(reencoded, expected)
def test_timedelta_encoding_explicit_non_timedelta64_dtype() -> None:
@@ -2093,20 +2127,21 @@ def test_timedelta_encoding_explicit_non_timedelta64_dtype() -> None:
encoded = conventions.encode_cf_variable(variable)
assert encoded.attrs["units"] == "days"
+ assert encoded.attrs["dtype"] == "timedelta64[ns]"
assert encoded.dtype == np.dtype("int32")
- with pytest.warns(FutureWarning, match="timedelta"):
- decoded = conventions.decode_cf_variable("foo", encoded)
+ decoded = conventions.decode_cf_variable("foo", encoded)
assert_identical(decoded, variable)
reencoded = conventions.encode_cf_variable(decoded)
assert_identical(reencoded, encoded)
assert encoded.attrs["units"] == "days"
+ assert encoded.attrs["dtype"] == "timedelta64[ns]"
assert encoded.dtype == np.dtype("int32")
@pytest.mark.parametrize("mask_attribute", ["_FillValue", "missing_value"])
-def test_literal_timedelta64_coding_with_mask(
+def test_timedelta64_coding_via_dtype_with_mask(
time_unit: PDDatetimeUnitOptions, mask_attribute: str
) -> None:
timedeltas = np.array([0, 1, "NaT"], dtype=f"timedelta64[{time_unit}]")
@@ -2122,7 +2157,7 @@ def test_literal_timedelta64_coding_with_mask(
assert encoded[-1] == mask
decoded = conventions.decode_cf_variable("timedeltas", encoded)
- assert decoded.encoding["dtype"] == expected_dtype
+ assert decoded.encoding["dtype"] == np.dtype("int64")
assert decoded.encoding["units"] == expected_units
assert decoded.encoding[mask_attribute] == mask
assert np.isnat(decoded[-1])
@@ -2144,7 +2179,7 @@ def test_roundtrip_0size_timedelta(time_unit: PDDatetimeUnitOptions) -> None:
assert encoded.dtype == encoding["dtype"]
assert encoded.attrs["units"] == encoding["units"]
decoded = conventions.decode_cf_variable("foo", encoded, decode_timedelta=True)
- assert decoded.dtype == np.dtype("=m8[ns]")
+ assert decoded.dtype == np.dtype(f"=m8[{time_unit}]")
with assert_no_warnings():
decoded.load()
assert decoded.dtype == np.dtype("=m8[s]")
diff --git a/xarray/tests/test_computation.py b/xarray/tests/test_computation.py
index 91a380e840f..569013b43dc 100644
--- a/xarray/tests/test_computation.py
+++ b/xarray/tests/test_computation.py
@@ -1397,7 +1397,7 @@ def test_apply_dask_new_output_sizes_not_supplied_same_dim_names() -> None:
da,
input_core_dims=[["i", "j"]],
output_core_dims=[["i", "j"]],
- exclude_dims=set(("i", "j")),
+ exclude_dims={"i", "j"},
dask="parallelized",
)
diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py
index 961df78154e..ce792c83740 100644
--- a/xarray/tests/test_conventions.py
+++ b/xarray/tests/test_conventions.py
@@ -555,10 +555,10 @@ def test_decode_cf_time_kwargs(self, time_unit) -> None:
class CFEncodedInMemoryStore(WritableCFDataStore, InMemoryDataStore):
- def encode_variable(self, var):
+ def encode_variable(self, var, name=None):
"""encode one variable"""
coder = coding.strings.EncodedStringCoder(allows_unicode=True)
- var = coder.encode(var)
+ var = coder.encode(var, name=name)
return var
diff --git a/xarray/tests/test_dask.py b/xarray/tests/test_dask.py
index 50870ca6976..eefa3c2b4f8 100644
--- a/xarray/tests/test_dask.py
+++ b/xarray/tests/test_dask.py
@@ -1372,7 +1372,7 @@ def test_map_blocks_da_ds_with_template(obj):
# Check that indexes are written into the graph directly
dsk = dict(actual.__dask_graph__())
- assert len({k for k in dsk if "x-coordinate" in k})
+ assert {k for k in dsk if "x-coordinate" in k}
assert all(
isinstance(v, PandasIndex) for k, v in dsk.items() if "x-coordinate" in k
)
diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py
index b2b9ae314c4..45c169bb931 100644
--- a/xarray/tests/test_dataarray.py
+++ b/xarray/tests/test_dataarray.py
@@ -2920,7 +2920,7 @@ def test_reduce_keepdims(self) -> None:
expected = DataArray(
orig.data.mean(keepdims=True),
dims=orig.dims,
- coords={k: v for k, v in coords.items() if k in ["c"]},
+ coords={k: v for k, v in coords.items() if k == "c"},
)
assert_equal(actual, expected)
diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py
index b17ea252a58..3e0734c8a1a 100644
--- a/xarray/tests/test_dataset.py
+++ b/xarray/tests/test_dataset.py
@@ -1214,7 +1214,7 @@ def test_chunk_by_frequency(self, freq: str, calendar: str, add_gap: bool) -> No
import dask.array
N = 365 * 2
- ΔN = 28
+ ΔN = 28 # noqa: PLC2401
time = xr.date_range(
"2001-01-01", periods=N + ΔN, freq="D", calendar=calendar
).to_numpy(copy=True)
@@ -2369,6 +2369,19 @@ def test_reindex_str_dtype(self, dtype) -> None:
assert_identical(expected, actual)
assert actual.x.dtype == expected.x.dtype
+ def test_reindex_with_multiindex_level(self) -> None:
+ # test for https://github.com/pydata/xarray/issues/10347
+ mindex = pd.MultiIndex.from_product(
+ [[100, 200, 300], [1, 2, 3, 4]], names=["x", "y"]
+ )
+ y_idx = PandasIndex(mindex.levels[1], "y")
+
+ ds1 = xr.Dataset(coords={"y": [1, 2, 3]})
+ ds2 = xr.Dataset(coords=xr.Coordinates.from_xindex(y_idx))
+
+ actual = ds1.reindex(y=ds2.y)
+ assert_identical(actual, ds2)
+
@pytest.mark.parametrize("fill_value", [dtypes.NA, 2, 2.0, {"foo": 2, "bar": 1}])
def test_align_fill_value(self, fill_value) -> None:
x = Dataset({"foo": DataArray([1, 2], dims=["x"], coords={"x": [1, 2]})})
diff --git a/xarray/tests/test_datatree.py b/xarray/tests/test_datatree.py
index 82c624b9bf6..2bf079a7cbd 100644
--- a/xarray/tests/test_datatree.py
+++ b/xarray/tests/test_datatree.py
@@ -837,7 +837,7 @@ def test_nones(self) -> None:
def test_full(self, simple_datatree) -> None:
dt = simple_datatree
- paths = list(node.path for node in dt.subtree)
+ paths = [node.path for node in dt.subtree]
assert paths == [
"/",
"/set1",
@@ -1433,7 +1433,6 @@ def test_doc_example(self) -> None:
def _exact_match(message: str) -> str:
return re.escape(dedent(message).strip())
- return "^" + re.escape(dedent(message.rstrip())) + "$"
class TestInheritance:
@@ -1657,7 +1656,7 @@ def test_drop_nodes(self) -> None:
# test drop multiple nodes
dropped = sue.drop_nodes(names=["Mary", "Kate"])
- assert not set(["Mary", "Kate"]).intersection(set(dropped.children))
+ assert not {"Mary", "Kate"}.intersection(set(dropped.children))
assert "Ashley" in dropped.children
# test raise
@@ -2310,7 +2309,7 @@ class TestUFuncs:
@pytest.mark.xfail(reason="__array_ufunc__ not implemented yet")
def test_tree(self, create_test_datatree):
dt = create_test_datatree()
- expected = create_test_datatree(modify=lambda ds: np.sin(ds))
+ expected = create_test_datatree(modify=np.sin)
result_tree = np.sin(dt)
assert_equal(result_tree, expected)
diff --git a/xarray/tests/test_duck_array_ops.py b/xarray/tests/test_duck_array_ops.py
index eaafe2d4536..5928581de30 100644
--- a/xarray/tests/test_duck_array_ops.py
+++ b/xarray/tests/test_duck_array_ops.py
@@ -587,7 +587,7 @@ def test_reduce(dim_num, dtype, dask, func, skipna, aggdim):
if dask and not has_dask:
pytest.skip("requires dask")
- if dask and skipna is False and dtype in [np.bool_]:
+ if dask and skipna is False and dtype == np.bool_:
pytest.skip("dask does not compute object-typed array")
rtol = 1e-04 if dtype == np.float32 else 1e-05
diff --git a/xarray/tests/test_formatting.py b/xarray/tests/test_formatting.py
index 2e0925c1b9a..88c2c819405 100644
--- a/xarray/tests/test_formatting.py
+++ b/xarray/tests/test_formatting.py
@@ -101,6 +101,9 @@ def test_format_item(self) -> None:
(np.float16(1.1234), "1.123"),
(np.float32(1.0111111), "1.011"),
(np.float64(22.222222), "22.22"),
+ (np.zeros((1, 1)), "[[0.]]"),
+ (np.zeros(2), "[0. 0.]"),
+ (np.zeros((2, 2)), "[[0. 0.]\n [0. 0.]]"),
]
for item, expected in cases:
actual = formatting.format_item(item)
@@ -718,6 +721,27 @@ def test_diff_datatree_repr_node_data(self):
actual = formatting.diff_datatree_repr(dt_1, dt_2, "identical")
assert actual == expected
+ def test_diff_datatree_repr_equals(self) -> None:
+ ds1 = xr.Dataset(data_vars={"data": ("y", [5, 2])})
+ ds2 = xr.Dataset(data_vars={"data": (("x", "y"), [[5, 2]])})
+ dt1 = xr.DataTree.from_dict({"node": ds1})
+ dt2 = xr.DataTree.from_dict({"node": ds2})
+
+ expected = dedent(
+ """\
+ Left and right DataTree objects are not equal
+
+ Data at node 'node' does not match:
+ Differing dimensions:
+ (y: 2) != (x: 1, y: 2)
+ Differing data variables:
+ L data (y) int64 16B 5 2
+ R data (x, y) int64 16B 5 2"""
+ )
+
+ actual = formatting.diff_datatree_repr(dt1, dt2, "equals")
+ assert actual == expected
+
def test_inline_variable_array_repr_custom_repr() -> None:
class CustomArray:
diff --git a/xarray/tests/test_groupby.py b/xarray/tests/test_groupby.py
index a64dfc97bb6..54cc21b5d2c 100644
--- a/xarray/tests/test_groupby.py
+++ b/xarray/tests/test_groupby.py
@@ -1321,8 +1321,7 @@ def test_groupby_properties(self) -> None:
grouped = self.da.groupby("abc")
expected_groups = {"a": range(9), "c": [9], "b": range(10, 20)}
assert expected_groups.keys() == grouped.groups.keys()
- for key in expected_groups:
- expected_group = expected_groups[key]
+ for key, expected_group in expected_groups.items():
actual_group = grouped.groups[key]
# TODO: array_api doesn't allow slice:
@@ -3257,8 +3256,6 @@ def test_shuffle_simple() -> None:
def test_shuffle_by(chunks, expected_chunks):
import dask.array
- from xarray.groupers import UniqueGrouper
-
da = xr.DataArray(
dims="x",
data=dask.array.arange(10, chunks=chunks),
diff --git a/xarray/tests/test_interp.py b/xarray/tests/test_interp.py
index 3d6fbcf025f..7d5a9bf3db4 100644
--- a/xarray/tests/test_interp.py
+++ b/xarray/tests/test_interp.py
@@ -124,7 +124,7 @@ def test_interpolate_1d(method: InterpOptions, dim: str, case: int) -> None:
if not has_scipy:
pytest.skip("scipy is not installed.")
- if not has_dask and case in [1]:
+ if not has_dask and case == 1:
pytest.skip("dask is not installed in the environment.")
da = get_example_data(case)
@@ -433,7 +433,7 @@ def test_interpolate_nd_with_nan() -> None:
"case", [pytest.param(0, id="no_chunk"), pytest.param(1, id="chunk_y")]
)
def test_interpolate_scalar(method: InterpOptions, case: int) -> None:
- if not has_dask and case in [1]:
+ if not has_dask and case == 1:
pytest.skip("dask is not installed in the environment.")
da = get_example_data(case)
@@ -463,7 +463,7 @@ def func(obj, new_x):
"case", [pytest.param(3, id="no_chunk"), pytest.param(4, id="chunked")]
)
def test_interpolate_nd_scalar(method: InterpOptions, case: int) -> None:
- if not has_dask and case in [4]:
+ if not has_dask and case == 4:
pytest.skip("dask is not installed in the environment.")
da = get_example_data(case)
diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py
index 3c7d83d2825..bfe0b81e4b6 100644
--- a/xarray/tests/test_plot.py
+++ b/xarray/tests/test_plot.py
@@ -235,7 +235,7 @@ def test_1d_x_y_kw(self) -> None:
z = np.arange(10)
da = DataArray(np.cos(z), dims=["z"], coords=[z], name="f")
- xy: list[list[None | str]] = [[None, None], [None, "z"], ["z", None]]
+ xy: list[list[str | None]] = [[None, None], [None, "z"], ["z", None]]
f, axs = plt.subplots(3, 1, squeeze=False)
for aa, (x, y) in enumerate(xy):
@@ -828,7 +828,7 @@ def test_slice_in_title_single_item_array(self) -> None:
darray = self.darray.expand_dims({"d": np.array([10.009])})
darray.plot.line(x="period")
title = plt.gca().get_title()
- assert "d = 10.01" == title
+ assert "d = [10.009]" == title
class TestPlotStep(PlotTestCase):
@@ -2698,9 +2698,9 @@ class TestDatasetStreamplotPlots(PlotTestCase):
def setUp(self) -> None:
das = [
DataArray(
- np.random.randn(3, 3, 2, 2),
+ np.random.randn(3, 4, 2, 2),
dims=["x", "y", "row", "col"],
- coords=[range(k) for k in [3, 3, 2, 2]],
+ coords=[range(k) for k in [3, 4, 2, 2]],
)
for _ in [1, 2]
]
@@ -2789,7 +2789,7 @@ def test_accessor(self) -> None:
def test_add_guide(
self,
add_guide: bool | None,
- hue_style: Literal["continuous", "discrete", None],
+ hue_style: Literal["continuous", "discrete"] | None,
legend: bool,
colorbar: bool,
) -> None:
diff --git a/xarray/tests/test_plugins.py b/xarray/tests/test_plugins.py
index b4817d7442f..e2129229c2c 100644
--- a/xarray/tests/test_plugins.py
+++ b/xarray/tests/test_plugins.py
@@ -2,6 +2,7 @@
import sys
from importlib.metadata import EntryPoint, EntryPoints
+from itertools import starmap
from unittest import mock
import pytest
@@ -48,7 +49,7 @@ def dummy_duplicated_entrypoints():
["engine2", "xarray.tests.test_plugins:backend_1", "xarray.backends"],
["engine2", "xarray.tests.test_plugins:backend_2", "xarray.backends"],
]
- eps = [EntryPoint(name, value, group) for name, value, group in specs]
+ eps = list(starmap(EntryPoint, specs))
return eps
@@ -91,7 +92,7 @@ def test_backends_dict_from_pkg() -> None:
["engine1", "xarray.tests.test_plugins:backend_1", "xarray.backends"],
["engine2", "xarray.tests.test_plugins:backend_2", "xarray.backends"],
]
- entrypoints = [EntryPoint(name, value, group) for name, value, group in specs]
+ entrypoints = list(starmap(EntryPoint, specs))
engines = plugins.backends_dict_from_pkg(entrypoints)
assert len(engines) == 2
assert engines.keys() == {"engine1", "engine2"}
diff --git a/xarray/tests/test_range_index.py b/xarray/tests/test_range_index.py
index 3a30650ebda..d0644ba73a2 100644
--- a/xarray/tests/test_range_index.py
+++ b/xarray/tests/test_range_index.py
@@ -121,6 +121,28 @@ def test_range_index_isel() -> None:
expected = create_dataset_arange(0.0, 1.0, 0.2)
assert_identical(actual, expected, check_default_indexes=False)
+ actual = ds.isel(x=slice(None, None, -1))
+ expected = create_dataset_arange(0.9, -0.1, -0.1)
+ assert_identical(actual, expected, check_default_indexes=False)
+
+ actual = ds.isel(x=slice(None, 4, -1))
+ expected = create_dataset_arange(0.9, 0.4, -0.1)
+ assert_identical(actual, expected, check_default_indexes=False)
+
+ actual = ds.isel(x=slice(8, 4, -1))
+ expected = create_dataset_arange(0.8, 0.4, -0.1)
+ assert_identical(actual, expected, check_default_indexes=False)
+
+ actual = ds.isel(x=slice(8, None, -1))
+ expected = create_dataset_arange(0.8, -0.1, -0.1)
+ assert_identical(actual, expected, check_default_indexes=False)
+
+ # https://github.com/pydata/xarray/issues/10441
+ ds2 = create_dataset_arange(0.0, 3.0, 0.1)
+ actual = ds2.isel(x=slice(4, None, 3))
+ expected = create_dataset_arange(0.4, 3.0, 0.3)
+ assert_identical(actual, expected, check_default_indexes=False)
+
# scalar
actual = ds.isel(x=0)
expected = xr.Dataset(coords={"x": 0.0})
@@ -220,6 +242,6 @@ def test_range_index_repr() -> None:
def test_range_index_repr_inline() -> None:
index = RangeIndex.arange(0.0, 1.0, 0.1, dim="x")
- actual = index._repr_inline_(max_width=None)
+ actual = index._repr_inline_(max_width=70)
expected = "RangeIndex (start=0, stop=1, step=0.1)"
assert actual == expected
diff --git a/xarray/tests/test_rolling.py b/xarray/tests/test_rolling.py
index 3d7f5657567..d93216a3ccc 100644
--- a/xarray/tests/test_rolling.py
+++ b/xarray/tests/test_rolling.py
@@ -341,7 +341,7 @@ def test_ndrolling_reduce(
assert_allclose(actual, expected)
assert actual.sizes == expected.sizes
- if name in ["mean"]:
+ if name == "mean":
# test our reimplementation of nanmean using np.nanmean
expected = getattr(rolling_obj.construct({"time": "tw", "x": "xw"}), name)(
["tw", "xw"]
diff --git a/xarray/tests/test_units.py b/xarray/tests/test_units.py
index ab4ec36ea97..d98d72d9876 100644
--- a/xarray/tests/test_units.py
+++ b/xarray/tests/test_units.py
@@ -2650,7 +2650,7 @@ def test_searchsorted(self, func, unit, error, dtype):
data_array = xr.DataArray(data=array)
scalar_types = (int, float)
- args = list(value * unit for value in func.args)
+ args = [value * unit for value in func.args]
kwargs = {
key: (value * unit if isinstance(value, scalar_types) else value)
for key, value in func.kwargs.items()
@@ -2708,7 +2708,7 @@ def test_numpy_methods_with_args(self, func, unit, error, dtype):
data_array = xr.DataArray(data=array)
scalar_types = (int, float)
- args = list(value * unit for value in func.args)
+ args = [value * unit for value in func.args]
kwargs = {
key: (value * unit if isinstance(value, scalar_types) else value)
for key, value in func.kwargs.items()
diff --git a/xarray/tests/test_utils.py b/xarray/tests/test_utils.py
index 9873b271033..0e6bbf29a45 100644
--- a/xarray/tests/test_utils.py
+++ b/xarray/tests/test_utils.py
@@ -300,7 +300,7 @@ def test_parse_dims_set() -> None:
@pytest.mark.parametrize(
"dim", [pytest.param(None, id="None"), pytest.param(..., id="ellipsis")]
)
-def test_parse_dims_replace_none(dim: None | EllipsisType) -> None:
+def test_parse_dims_replace_none(dim: EllipsisType | None) -> None:
all_dims = ("a", "b", 1, ("b", "c")) # selection of different Hashables
actual = utils.parse_dims_as_tuple(dim, all_dims, replace_none=True)
assert actual == all_dims
diff --git a/xarray/tutorial.py b/xarray/tutorial.py
index ec832694a99..70e7fc68f7e 100644
--- a/xarray/tutorial.py
+++ b/xarray/tutorial.py
@@ -85,7 +85,7 @@ def _check_netcdf_engine_installed(name):
def open_dataset(
name: str,
cache: bool = True,
- cache_dir: None | str | os.PathLike = None,
+ cache_dir: str | os.PathLike | None = None,
*,
engine: T_Engine = None,
**kws,
@@ -216,7 +216,7 @@ def load_dataset(*args, **kwargs) -> Dataset:
return ds.load()
-def scatter_example_dataset(*, seed: None | int = None) -> Dataset:
+def scatter_example_dataset(*, seed: int | None = None) -> Dataset:
"""
Create an example dataset.
@@ -255,7 +255,7 @@ def scatter_example_dataset(*, seed: None | int = None) -> Dataset:
def open_datatree(
name: str,
cache: bool = True,
- cache_dir: None | str | os.PathLike = None,
+ cache_dir: str | os.PathLike | None = None,
*,
engine: T_Engine = None,
**kws,
diff --git a/xarray/ufuncs.py b/xarray/ufuncs.py
index e25657216fd..83acbde858b 100644
--- a/xarray/ufuncs.py
+++ b/xarray/ufuncs.py
@@ -39,7 +39,7 @@ def get_array_namespace(*args):
names = [module.__name__ for module in xps]
raise ValueError(f"Mixed array types {names} are not supported.")
- return next(iter(xps)) if len(xps) else np
+ return next(iter(xps)) if xps else np
class _ufunc_wrapper(ABC):
diff --git a/xarray/util/generate_aggregations.py b/xarray/util/generate_aggregations.py
index 8812a1abb22..15319e2f6c8 100644
--- a/xarray/util/generate_aggregations.py
+++ b/xarray/util/generate_aggregations.py
@@ -692,8 +692,7 @@ def write_methods(filepath, generators, preamble):
f.write(preamble)
for gen in generators:
for lines in gen.generate_methods():
- for line in lines:
- f.write(line + "\n")
+ f.writelines(line + "\n" for line in lines)
if __name__ == "__main__":
diff --git a/xarray/util/generate_ops.py b/xarray/util/generate_ops.py
index 3300bbf594a..74fec786afa 100644
--- a/xarray/util/generate_ops.py
+++ b/xarray/util/generate_ops.py
@@ -133,7 +133,7 @@ def {{ method }}(self, *args: Any, **kwargs: Any) -> Self:
# We require a "hack" to tell type checkers that e.g. Variable + DataArray = DataArray
# In reality this returns NotImplemented, but this is not a valid type in python 3.9.
# Therefore, we return DataArray. In reality this would call DataArray.__add__(Variable)
-# TODO: change once python 3.10 is the minimum.
+# TODO: change once python 3.11 is the minimum.
#
# Mypy seems to require that __iadd__ and __add__ have the same signature.
# This requires some extra type: ignores[misc] in the inplace methods :/
@@ -222,32 +222,33 @@ def unops() -> list[OpsType]:
# ruff does not reformat everything. When reformatting, the
# type-ignores end up in the wrong line :/
-ops_info = {}
-# TODO add inplace ops for DataTree?
-ops_info["DataTreeOpsMixin"] = binops(other_type="DtCompatible") + unops()
-ops_info["DatasetOpsMixin"] = (
- binops_overload(other_type="DsCompatible", overload_types=["DataTree"])
- + inplace(other_type="DsCompatible", type_ignore="misc")
- + unops()
-)
-ops_info["DataArrayOpsMixin"] = (
- binops_overload(other_type="DaCompatible", overload_types=["Dataset", "DataTree"])
- + inplace(other_type="DaCompatible", type_ignore="misc")
- + unops()
-)
-ops_info["VariableOpsMixin"] = (
- binops_overload(
- other_type="VarCompatible", overload_types=["T_DA", "Dataset", "DataTree"]
- )
- + inplace(other_type="VarCompatible", type_ignore="misc")
- + unops()
-)
-ops_info["DatasetGroupByOpsMixin"] = binops(
- other_type="Dataset | DataArray", return_type="Dataset"
-)
-ops_info["DataArrayGroupByOpsMixin"] = binops(
- other_type="T_Xarray", return_type="T_Xarray"
-)
+ops_info = {
+ # TODO add inplace ops for DataTree?
+ "DataTreeOpsMixin": binops(other_type="DtCompatible") + unops(),
+ "DatasetOpsMixin": (
+ binops_overload(other_type="DsCompatible", overload_types=["DataTree"])
+ + inplace(other_type="DsCompatible", type_ignore="misc")
+ + unops()
+ ),
+ "DataArrayOpsMixin": (
+ binops_overload(
+ other_type="DaCompatible", overload_types=["Dataset", "DataTree"]
+ )
+ + inplace(other_type="DaCompatible", type_ignore="misc")
+ + unops()
+ ),
+ "VariableOpsMixin": (
+ binops_overload(
+ other_type="VarCompatible", overload_types=["T_DA", "Dataset", "DataTree"]
+ )
+ + inplace(other_type="VarCompatible", type_ignore="misc")
+ + unops()
+ ),
+ "DatasetGroupByOpsMixin": binops(
+ other_type="Dataset | DataArray", return_type="Dataset"
+ ),
+ "DataArrayGroupByOpsMixin": binops(other_type="T_Xarray", return_type="T_Xarray"),
+}
MODULE_PREAMBLE = '''\
"""Mixin classes with arithmetic operators."""
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy