Skip to content

Commit 6abb769

Browse files
erik-manssonErik Månssonpre-commit-ci[bot]dcherian
authored
apply_ufunc: don't modify attrs on input variables (#10330)
Co-authored-by: Erik Månsson <none@example> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Deepak Cherian <dcherian@users.noreply.github.com>
1 parent fad1185 commit 6abb769

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

xarray/structure/merge.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,11 +283,17 @@ def merge_collected(
283283
"conflicting attribute values on combined "
284284
f"variable {name!r}:\nfirst value: {variable.attrs!r}\nsecond value: {other_variable.attrs!r}"
285285
)
286-
merged_vars[name] = variable
287-
merged_vars[name].attrs = merge_attrs(
286+
attrs = merge_attrs(
288287
[var.attrs for var, _ in indexed_elements],
289288
combine_attrs=combine_attrs,
290289
)
290+
if variable.attrs or attrs:
291+
# Make a shallow copy to so that assigning merged_vars[name].attrs
292+
# does not affect the original input variable.
293+
merged_vars[name] = variable.copy(deep=False)
294+
merged_vars[name].attrs = attrs
295+
else:
296+
merged_vars[name] = variable
291297
merged_indexes[name] = index
292298
else:
293299
variables = [variable for variable, _ in elements_list]

xarray/tests/test_computation.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,6 +2206,7 @@ def test_where() -> None:
22062206
def test_where_attrs() -> None:
22072207
cond = xr.DataArray([True, False], coords={"a": [0, 1]}, attrs={"attr": "cond_da"})
22082208
cond["a"].attrs = {"attr": "cond_coord"}
2209+
input_cond = cond.copy()
22092210
x = xr.DataArray([1, 1], coords={"a": [0, 1]}, attrs={"attr": "x_da"})
22102211
x["a"].attrs = {"attr": "x_coord"}
22112212
y = xr.DataArray([0, 0], coords={"a": [0, 1]}, attrs={"attr": "y_da"})
@@ -2216,6 +2217,22 @@ def test_where_attrs() -> None:
22162217
expected = xr.DataArray([1, 0], coords={"a": [0, 1]}, attrs={"attr": "x_da"})
22172218
expected["a"].attrs = {"attr": "x_coord"}
22182219
assert_identical(expected, actual)
2220+
# Check also that input coordinate attributes weren't modified by reference
2221+
assert x["a"].attrs == {"attr": "x_coord"}
2222+
assert y["a"].attrs == {"attr": "y_coord"}
2223+
assert cond["a"].attrs == {"attr": "cond_coord"}
2224+
assert_identical(cond, input_cond)
2225+
2226+
# 3 DataArrays, drop attrs
2227+
actual = xr.where(cond, x, y, keep_attrs=False)
2228+
expected = xr.DataArray([1, 0], coords={"a": [0, 1]})
2229+
assert_identical(expected, actual)
2230+
assert_identical(expected.coords["a"], actual.coords["a"])
2231+
# Check also that input coordinate attributes weren't modified by reference
2232+
assert x["a"].attrs == {"attr": "x_coord"}
2233+
assert y["a"].attrs == {"attr": "y_coord"}
2234+
assert cond["a"].attrs == {"attr": "cond_coord"}
2235+
assert_identical(cond, input_cond)
22192236

22202237
# x as a scalar, takes no attrs
22212238
actual = xr.where(cond, 0, y, keep_attrs=True)

xarray/tests/test_merge.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,11 @@ def test_merge_arrays_attrs_variables(
183183
self, combine_attrs, attrs1, attrs2, expected_attrs, expect_exception
184184
):
185185
"""check that combine_attrs is used on data variables and coords"""
186+
input_attrs1 = attrs1.copy()
186187
data1 = xr.Dataset(
187188
{"var1": ("dim1", [], attrs1)}, coords={"dim1": ("dim1", [], attrs1)}
188189
)
190+
input_attrs2 = attrs2.copy()
189191
data2 = xr.Dataset(
190192
{"var1": ("dim1", [], attrs2)}, coords={"dim1": ("dim1", [], attrs2)}
191193
)
@@ -202,6 +204,12 @@ def test_merge_arrays_attrs_variables(
202204

203205
assert_identical(actual, expected)
204206

207+
# Check also that input attributes weren't modified
208+
assert data1["var1"].attrs == input_attrs1
209+
assert data1.coords["dim1"].attrs == input_attrs1
210+
assert data2["var1"].attrs == input_attrs2
211+
assert data2.coords["dim1"].attrs == input_attrs2
212+
205213
def test_merge_attrs_override_copy(self):
206214
ds1 = xr.Dataset(attrs={"x": 0})
207215
ds2 = xr.Dataset(attrs={"x": 1})
@@ -344,6 +352,18 @@ def test_merge(self):
344352
with pytest.raises(ValueError, match=r"should be coordinates or not"):
345353
data.merge(data.reset_coords())
346354

355+
def test_merge_drop_attrs(self):
356+
data = create_test_data()
357+
ds1 = data[["var1"]]
358+
ds2 = data[["var3"]]
359+
ds1.coords["dim2"].attrs["keep me"] = "example"
360+
ds2.coords["numbers"].attrs["foo"] = "bar"
361+
actual = ds1.merge(ds2, combine_attrs="drop")
362+
assert actual.coords["dim2"].attrs == {}
363+
assert actual.coords["numbers"].attrs == {}
364+
assert ds1.coords["dim2"].attrs["keep me"] == "example"
365+
assert ds2.coords["numbers"].attrs["foo"] == "bar"
366+
347367
def test_merge_broadcast_equals(self):
348368
ds1 = xr.Dataset({"x": 0})
349369
ds2 = xr.Dataset({"x": ("y", [0, 0])})

xarray/tests/test_ufuncs.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ def test_binary_out():
6262
assert_identical(actual_exponent, arg)
6363

6464

65+
def test_binary_coord_attrs():
66+
t = xr.Variable("t", np.arange(2, 4), attrs={"units": "s"})
67+
x = xr.DataArray(t.values**2, coords={"t": t}, attrs={"units": "s^2"})
68+
y = xr.DataArray(t.values**3, coords={"t": t}, attrs={"units": "s^3"})
69+
z1 = xr.apply_ufunc(np.add, x, y, keep_attrs=True)
70+
assert z1.coords["t"].attrs == {"units": "s"}
71+
z2 = xr.apply_ufunc(np.add, x, y, keep_attrs=False)
72+
assert z2.coords["t"].attrs == {}
73+
# Check also that input array's coordinate attributes weren't affected
74+
assert t.attrs == {"units": "s"}
75+
assert x.coords["t"].attrs == {"units": "s"}
76+
77+
6578
def test_groupby():
6679
ds = xr.Dataset({"a": ("x", [0, 0, 0])}, {"c": ("x", [0, 0, 1])})
6780
ds_grouped = ds.groupby("c")

0 commit comments

Comments
 (0)