|
9 | 9 | import pandas as pd |
10 | 10 | import pytest |
11 | 11 |
|
12 | | -from xarray import AlignmentError, DataArray, Dataset, Variable, concat, set_options |
| 12 | +from xarray import ( |
| 13 | + AlignmentError, |
| 14 | + DataArray, |
| 15 | + Dataset, |
| 16 | + Variable, |
| 17 | + concat, |
| 18 | + open_dataset, |
| 19 | + set_options, |
| 20 | +) |
13 | 21 | from xarray.core import dtypes, types |
14 | 22 | from xarray.core.coordinates import Coordinates |
15 | 23 | from xarray.core.indexes import PandasIndex |
|
23 | 31 | assert_identical, |
24 | 32 | requires_dask, |
25 | 33 | requires_pyarrow, |
| 34 | + requires_scipy_or_netCDF4, |
26 | 35 | ) |
27 | 36 | from xarray.tests.indexes import XYIndex |
28 | 37 | from xarray.tests.test_dataset import create_test_data |
@@ -1119,6 +1128,47 @@ def test_concat_promote_shape_without_creating_new_index(self) -> None: |
1119 | 1128 | assert_identical(actual, expected, check_default_indexes=False) |
1120 | 1129 | assert actual.indexes == {} |
1121 | 1130 |
|
| 1131 | + @requires_scipy_or_netCDF4 |
| 1132 | + def test_concat_combine_attrs_nan_after_netcdf_roundtrip(self, tmp_path) -> None: |
| 1133 | + # Test for issue #10833: NaN attributes should be preserved |
| 1134 | + # with combine_attrs="drop_conflicts" after NetCDF roundtrip |
| 1135 | + import numpy as np |
| 1136 | + |
| 1137 | + # Create arrays with matching NaN fill_value attribute |
| 1138 | + ds1 = Dataset( |
| 1139 | + {"a": ("x", [0, 1])}, |
| 1140 | + attrs={"fill_value": np.nan, "sensor": "G18", "field": "CTH"}, |
| 1141 | + ) |
| 1142 | + ds2 = Dataset( |
| 1143 | + {"a": ("x", [2, 3])}, |
| 1144 | + attrs={"fill_value": np.nan, "sensor": "G16", "field": "CTH"}, |
| 1145 | + ) |
| 1146 | + |
| 1147 | + # Save to NetCDF and reload (converts Python float NaN to NumPy scalar NaN) |
| 1148 | + path1 = tmp_path / "ds1.nc" |
| 1149 | + path2 = tmp_path / "ds2.nc" |
| 1150 | + ds1.to_netcdf(path1) |
| 1151 | + ds2.to_netcdf(path2) |
| 1152 | + |
| 1153 | + ds1_loaded = open_dataset(path1) |
| 1154 | + ds2_loaded = open_dataset(path2) |
| 1155 | + |
| 1156 | + # Verify that NaN attributes are preserved after concat |
| 1157 | + actual = concat( |
| 1158 | + [ds1_loaded, ds2_loaded], dim="y", combine_attrs="drop_conflicts" |
| 1159 | + ) |
| 1160 | + |
| 1161 | + # fill_value should be preserved (not dropped) since both have NaN |
| 1162 | + assert "fill_value" in actual.attrs |
| 1163 | + assert np.isnan(actual.attrs["fill_value"]) |
| 1164 | + # field should be preserved (identical in both) |
| 1165 | + assert actual.attrs["field"] == "CTH" |
| 1166 | + # sensor should be dropped (conflicts) |
| 1167 | + assert "sensor" not in actual.attrs |
| 1168 | + |
| 1169 | + ds1_loaded.close() |
| 1170 | + ds2_loaded.close() |
| 1171 | + |
1122 | 1172 |
|
1123 | 1173 | class TestConcatDataArray: |
1124 | 1174 | def test_concat(self) -> None: |
|
0 commit comments