diff --git a/lib/iris/fileformats/_nc_load_rules/helpers.py b/lib/iris/fileformats/_nc_load_rules/helpers.py index 6a135a211c..894bb31af8 100644 --- a/lib/iris/fileformats/_nc_load_rules/helpers.py +++ b/lib/iris/fileformats/_nc_load_rules/helpers.py @@ -327,7 +327,7 @@ class UnknownCellMethodWarning(iris.exceptions.IrisUnknownCellMethodWarning): pass -def parse_cell_methods(nc_cell_methods): +def parse_cell_methods(nc_cell_methods, cf_name=None): """Parse a CF cell_methods attribute string into a tuple of zero or more CellMethod instances. @@ -345,6 +345,7 @@ def parse_cell_methods(nc_cell_methods): results are not affected. """ + msg = None cell_methods = [] if nc_cell_methods is not None: for m in _split_cell_methods(nc_cell_methods): @@ -356,10 +357,16 @@ def parse_cell_methods(nc_cell_methods): method_words = method.split() if method_words[0].lower() not in _CM_KNOWN_METHODS: msg = "NetCDF variable contains unknown cell method {!r}" - warnings.warn( - msg.format("{}".format(method_words[0])), - category=UnknownCellMethodWarning, - ) + msg = msg.format(method_words[0]) + if cf_name: + name = "{}".format(cf_name) + msg = msg.replace("variable", "variable {!r}".format(name)) + else: + warnings.warn( + msg, + category=UnknownCellMethodWarning, + ) + msg = None d[_CM_METHOD] = method name = d[_CM_NAME] name = name.replace(" ", "") @@ -417,6 +424,9 @@ def parse_cell_methods(nc_cell_methods): comments=d[_CM_COMMENT], ) cell_methods.append(cell_method) + # only prints one warning, rather than each loop + if msg: + warnings.warn(msg, category=UnknownCellMethodWarning) return tuple(cell_methods) @@ -447,21 +457,7 @@ def build_cube_metadata(engine): # Incorporate cell methods nc_att_cell_methods = getattr(cf_var, CF_ATTR_CELL_METHODS, None) - with warnings.catch_warnings(record=True) as warning_records: - cube.cell_methods = parse_cell_methods(nc_att_cell_methods) - # Filter to get the warning we are interested in. - warning_records = [ - record - for record in warning_records - if issubclass(record.category, UnknownCellMethodWarning) - ] - if len(warning_records) > 0: - # Output an enhanced warning message. - warn_record = warning_records[0] - name = "{}".format(cf_var.cf_name) - msg = warn_record.message.args[0] - msg = msg.replace("variable", "variable {!r}".format(name)) - warnings.warn(message=msg, category=UnknownCellMethodWarning) + cube.cell_methods = parse_cell_methods(nc_att_cell_methods, cf_var.cf_name) # Set the cube global attributes. for attr_name, attr_value in cf_var.cf_group.global_attributes.items(): diff --git a/lib/iris/tests/integration/netcdf/test_general.py b/lib/iris/tests/integration/netcdf/test_general.py index 8c27742185..751c160805 100644 --- a/lib/iris/tests/integration/netcdf/test_general.py +++ b/lib/iris/tests/integration/netcdf/test_general.py @@ -484,5 +484,40 @@ def test_path_string_save_same(self): self.assertCDL(tempfile_frompath) +@tests.skip_data +class TestWarningRepeats(tests.IrisTest): + def test_datum_once(self): + """Tests for warnings being duplicated. + + 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 + ] + + with warnings.catch_warnings(record=True) as record: + warnings.simplefilter("default") + for fpath in fpaths: + iris.load(fpath) + warnings.warn("Dummy warning", category=iris.exceptions.IrisUserWarning) + assert len(record) == 2 + + if __name__ == "__main__": tests.main()