diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 76920c5ad5..0039ccea85 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -59,6 +59,10 @@ This document explains the changes made to Iris for this release #. `@pp-mo`_ corrected the use of mesh dimensions when saving with multiple meshes. (:issue:`5908`, :pull:`6004`) +#. `@trexfeathers`_ fixed the datum :class:`python:FutureWarning` to only be raised if + the ``datum_support`` :class:`~iris.Future` flag is disabled AND a datum is + present on the loaded NetCDF grid mapping. (:issue:`5749`, :pull:`6050`) + 💣 Incompatible Changes ======================= diff --git a/lib/iris/fileformats/_nc_load_rules/helpers.py b/lib/iris/fileformats/_nc_load_rules/helpers.py index 7a7424d4f7..5aed21bebf 100644 --- a/lib/iris/fileformats/_nc_load_rules/helpers.py +++ b/lib/iris/fileformats/_nc_load_rules/helpers.py @@ -522,7 +522,7 @@ def _get_ellipsoid(cf_grid_var): if datum == "unknown": datum = None - if not iris.FUTURE.datum_support: + if datum is not None and not iris.FUTURE.datum_support: wmsg = ( "Ignoring a datum in netCDF load for consistency with existing " "behaviour. In a future version of Iris, this datum will be " diff --git a/lib/iris/tests/integration/netcdf/test_coord_systems.py b/lib/iris/tests/integration/netcdf/test_coord_systems.py index 55ecf2e2ef..6c101d9024 100644 --- a/lib/iris/tests/integration/netcdf/test_coord_systems.py +++ b/lib/iris/tests/integration/netcdf/test_coord_systems.py @@ -11,6 +11,9 @@ from os.path import join as path_join import shutil import tempfile +import warnings + +import pytest import iris from iris.coords import DimCoord @@ -135,15 +138,25 @@ def test_load_datum_wkt(self): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertMultiLineEqual(expected, actual) + assert actual == expected def test_no_load_datum_wkt(self): nc_path = tlc.cdl_to_nc(self.datum_wkt_cdl) - with self.assertWarnsRegex(FutureWarning, "iris.FUTURE.datum_support"): + with pytest.warns(FutureWarning, match="iris.FUTURE.datum_support"): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertMultiLineEqual(actual, "unknown") + assert actual == "unknown" + + def test_no_datum_no_warn(self): + new_cdl = self.datum_wkt_cdl.splitlines() + new_cdl = [line for line in new_cdl if "DATUM" not in line] + new_cdl = "\n".join(new_cdl) + nc_path = tlc.cdl_to_nc(new_cdl) + with warnings.catch_warnings(): + # pytest's recommended way to assert for no warnings. + warnings.simplefilter("error", FutureWarning) + _ = iris.load_cube(nc_path) def test_load_datum_cf_var(self): expected = "OSGB 1936" @@ -152,15 +165,15 @@ def test_load_datum_cf_var(self): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertMultiLineEqual(expected, actual) + assert actual == expected def test_no_load_datum_cf_var(self): nc_path = tlc.cdl_to_nc(self.datum_cf_var_cdl) - with self.assertWarnsRegex(FutureWarning, "iris.FUTURE.datum_support"): + with pytest.warns(FutureWarning, match="iris.FUTURE.datum_support"): cube = iris.load_cube(nc_path) test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertMultiLineEqual(actual, "unknown") + assert actual == "unknown" def test_save_datum(self): expected = "OSGB 1936" @@ -199,7 +212,7 @@ def test_save_datum(self): test_crs = cube.coord("projection_y_coordinate").coord_system actual = str(test_crs.as_cartopy_crs().datum) - self.assertMultiLineEqual(expected, actual) + assert actual == expected class TestLoadMinimalGeostationary(tests.IrisTest): @@ -270,9 +283,9 @@ def test_geostationary_no_false_offsets(self): cube = iris.load_cube(self.path_test_nc) # Check the coordinate system properties has the correct default properties. cs = cube.coord_system() - self.assertIsInstance(cs, iris.coord_systems.Geostationary) - self.assertEqual(cs.false_easting, 0.0) - self.assertEqual(cs.false_northing, 0.0) + assert isinstance(cs, iris.coord_systems.Geostationary) + assert cs.false_easting == 0.0 + assert cs.false_northing == 0.0 if __name__ == "__main__": diff --git a/lib/iris/tests/integration/netcdf/test_general.py b/lib/iris/tests/integration/netcdf/test_general.py index c505a21af5..88d636a315 100644 --- a/lib/iris/tests/integration/netcdf/test_general.py +++ b/lib/iris/tests/integration/netcdf/test_general.py @@ -488,37 +488,38 @@ def test_path_string_save_same(self): @tests.skip_data class TestWarningRepeats(tests.IrisTest): - def test_datum_once(self): - """Tests for warnings being duplicated. + def test_warning_repeats(self): + """Confirm Iris load does not break Python duplicate warning handling.""" + # units.nc is designed for testing Iris' 'ignoring invalid units' + # warning; it contains two variables with invalid units, producing two + # unique warnings (due to two different messages). + file_path = tests.get_data_path(("NetCDF", "testing", "units.nc")) - Notes - ----- - This test relies on `iris.load` throwing a warning. This warning might - be removed in the future, in which case `assert len(record) == 2 should` - be change to `assert len(record) == 1`. - - toa_brightness_temperature.nc has an AuxCoord with lazy data, and triggers a - specific part of dask which contains a `catch_warnings()` call which - causes warnings to be repeated, and so has been removed from the - `fnames` list until a solution is found for such a file. - - """ - # - fnames = [ - "false_east_north_merc.nc", - "non_unit_scale_factor_merc.nc", - # toa_brightness_temperature.nc, - ] - fpaths = [ - tests.get_data_path(("NetCDF", "mercator", fname)) for fname in fnames - ] + def _raise_warning() -> None: + # Contain in function so warning always has identical line number. + warnings.warn("Dummy warning", category=iris.warnings.IrisUserWarning) with warnings.catch_warnings(record=True) as record: warnings.simplefilter("default") - for fpath in fpaths: - iris.load(fpath) - warnings.warn("Dummy warning", category=iris.warnings.IrisUserWarning) - assert len(record) == 2 + + # Warn before Iris has been invoked. + _raise_warning() + assert len(record) == 1 + + # This Iris call should raise 2 warnings and should NOT affect + # Python's duplicate warning handling. + _ = iris.load(file_path) + assert len(record) == 3 + # Raise a duplicate warning. + _raise_warning() + assert len(record) == 3 + + # Repeated identical calls should only raise duplicate warnings + # and therefore not affect the record. + for i in range(2): + _ = iris.load(file_path) + _raise_warning() + assert len(record) == 3 if __name__ == "__main__":