diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 7a23c055bf5..470635d2184 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -69,6 +69,11 @@ Bug Fixes for zarr writes. Existing zarr stores written with the old ``int8`` encoding are still read correctly. (:issue:`2937`, :pull:`11318`) By `Evan Lyall `_. +- No longer emit a ``SerializationWarning`` about a missing ``_FillValue`` when + encoding a CF coordinate variable (a 1D variable named after its dimension) to + an integer dtype. CF forbids missing values in coordinate variables, so a + ``_FillValue`` is not expected there (:issue:`10305`). + By `NoiceHax `_. - Raise an informative ``TypeError`` when a :py:class:`~xarray.Coordinates` object is passed as a coordinate value, e.g. ``ds.assign_coords({"x": coords})``, instead of silently creating a broken coordinate. Pass the object directly with diff --git a/pyproject.toml b/pyproject.toml index 6fad5adacff..e1b812bf087 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -425,6 +425,7 @@ Celles = "Celles" slowy = "slowy" Commun = "Commun" Noice = "Noice" +Hax = "Hax" # Tests Ome = "Ome" diff --git a/xarray/coding/variables.py b/xarray/coding/variables.py index 6a5deb09152..42976533819 100644 --- a/xarray/coding/variables.py +++ b/xarray/coding/variables.py @@ -635,10 +635,14 @@ def encode(self, variable: Variable, name: T_Name = None) -> Variable: dtype = np.dtype(encoding.pop("dtype")) if dtype != variable.dtype: if np.issubdtype(dtype, np.integer): + # CF coordinate variables are not allowed to have missing values, so + # they do not need a _FillValue. For simplicity we don't warn with 1D dimension coordinates. + # http://cfconventions.org/cf-conventions/cf-conventions.html#missing-data if ( np.issubdtype(variable.dtype, np.floating) and "_FillValue" not in variable.attrs and "missing_value" not in variable.attrs + and dims != (name,) ): warnings.warn( f"saving variable {name} with floating " diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py index fd76aed836b..a0aac08c918 100644 --- a/xarray/tests/test_conventions.py +++ b/xarray/tests/test_conventions.py @@ -173,6 +173,27 @@ def test_missing_fillvalue(self) -> None: "invalid value encountered in cast" in msg for msg in warning_messages ) + def test_missing_fillvalue_coordinate_variable(self) -> None: + # regression test for GH10305 + # CF coordinate variables cannot have missing values, so they do not + # need a _FillValue and should not warn about one being absent + v = Variable(["x"], np.array([0.0, 1.0, 2.0]), encoding={"dtype": "int16"}) + with warnings.catch_warnings(): + warnings.simplefilter("error") + encoded = conventions.encode_cf_variable(v, name="x") + assert encoded.dtype == np.dtype("int16") + + def test_missing_fillvalue_non_coordinate_variable(self) -> None: + # data variables and multidimensional (auxiliary) coordinates may hold + # missing values, so they still warn + v = Variable(["x"], np.array([0.0, 1.0, 2.0]), encoding={"dtype": "int16"}) + with pytest.warns(SerializationWarning, match="floating point data"): + conventions.encode_cf_variable(v, name="data") + + v2d = Variable(["y", "x"], np.zeros((2, 3)), encoding={"dtype": "int16"}) + with pytest.warns(SerializationWarning, match="floating point data"): + conventions.encode_cf_variable(v2d, name="lat") + def test_multidimensional_coordinates(self) -> None: # regression test for GH1763 # Set up test case with coordinates that have overlapping (but not