diff --git a/lib/iris/cube.py b/lib/iris/cube.py index a1a07caab2..2c3f26971f 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -1044,7 +1044,7 @@ def _check_multi_dim_metadata(self, metadata, data_dims): def _add_unique_aux_coord(self, coord, data_dims): data_dims = self._check_multi_dim_metadata(coord, data_dims) - self._aux_coords_and_dims.append([coord, data_dims]) + self._aux_coords_and_dims.append((coord, data_dims)) def add_aux_factory(self, aux_factory): """ @@ -1095,7 +1095,7 @@ def add_cell_measure(self, cell_measure, data_dims=None): if self.cell_measures(cell_measure): raise ValueError("Duplicate cell_measures are not permitted.") data_dims = self._check_multi_dim_metadata(cell_measure, data_dims) - self._cell_measures_and_dims.append([cell_measure, data_dims]) + self._cell_measures_and_dims.append((cell_measure, data_dims)) self._cell_measures_and_dims.sort( key=lambda cm_dims: (cm_dims[0]._as_defn(), cm_dims[1]) ) @@ -1125,7 +1125,7 @@ def add_ancillary_variable(self, ancillary_variable, data_dims=None): ancillary_variable, data_dims ) self._ancillary_variables_and_dims.append( - [ancillary_variable, data_dims] + (ancillary_variable, data_dims) ) self._ancillary_variables_and_dims.sort( key=lambda av_dims: (av_dims[0]._as_defn(), av_dims[1]) @@ -1195,7 +1195,7 @@ def _add_unique_dim_coord(self, dim_coord, data_dim): ) ) - self._dim_coords_and_dims.append([dim_coord, int(data_dim)]) + self._dim_coords_and_dims.append((dim_coord, int(data_dim))) def remove_aux_factory(self, aux_factory): """Removes the given auxiliary coordinate factory from the cube.""" @@ -1263,7 +1263,7 @@ def remove_cell_measure(self, cell_measure): cell_measure = self.cell_measure(cell_measure) self._cell_measures_and_dims = [ - [cell_measure_, dim] + (cell_measure_, dim) for cell_measure_, dim in self._cell_measures_and_dims if cell_measure_ is not cell_measure ] @@ -1280,7 +1280,7 @@ def remove_ancillary_variable(self, ancillary_variable): """ self._ancillary_variables_and_dims = [ - [ancillary_variable_, dim] + (ancillary_variable_, dim) for ancillary_variable_, dim in self._ancillary_variables_and_dims if ancillary_variable_ is not ancillary_variable ] @@ -3583,6 +3583,16 @@ def __eq__(self, other): or coord_comparison["non_equal_data_dimension"] ) + if result: + result = set(self._cell_measures_and_dims) == set( + other._cell_measures_and_dims + ) + + if result: + result = set(self._ancillary_variables_and_dims) == set( + other._ancillary_variables_and_dims + ) + # Having checked everything else, check approximate data equality. if result: result = da.allclose( diff --git a/lib/iris/tests/unit/cube/test_Cube.py b/lib/iris/tests/unit/cube/test_Cube.py index cd2484370b..2407238b40 100644 --- a/lib/iris/tests/unit/cube/test_Cube.py +++ b/lib/iris/tests/unit/cube/test_Cube.py @@ -25,7 +25,13 @@ from iris.analysis import MEAN from iris.aux_factory import HybridHeightFactory from iris.cube import Cube -from iris.coords import AuxCoord, DimCoord, CellMeasure, AncillaryVariable +from iris.coords import ( + AuxCoord, + DimCoord, + CellMeasure, + AncillaryVariable, + CellMethod, +) from iris.exceptions import ( CoordinateNotFoundError, CellMeasureNotFoundError, @@ -1913,13 +1919,13 @@ def test_remove_aux_coord(self): def test_remove_cell_measure(self): self.cube.remove_cell_measure(self.cube.cell_measure("area")) self.assertEqual( - self.cube._cell_measures_and_dims, [[self.b_cell_measure, (0, 1)]] + self.cube._cell_measures_and_dims, [(self.b_cell_measure, (0, 1))] ) def test_remove_cell_measure_by_name(self): self.cube.remove_cell_measure("area") self.assertEqual( - self.cube._cell_measures_and_dims, [[self.b_cell_measure, (0, 1)]] + self.cube._cell_measures_and_dims, [(self.b_cell_measure, (0, 1))] ) def test_fail_remove_cell_measure_by_name(self): @@ -2206,5 +2212,99 @@ def test_data_bool_not_eq(self): self.assertFalse(cube1 == cube2) +class Test__eq__meta(tests.IrisTest): + def test_ancillary_fail(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + avr = AncillaryVariable([2, 3], long_name="foo") + cube2.add_ancillary_variable(avr, 0) + self.assertFalse(cube1 == cube2) + + def test_ancillary_reorder(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + avr1 = AncillaryVariable([2, 3], long_name="foo") + avr2 = AncillaryVariable([4, 5], long_name="bar") + # Add the same ancillary variables to cube1 and cube2 in + # opposite orders. + cube1.add_ancillary_variable(avr1, 0) + cube1.add_ancillary_variable(avr2, 0) + cube2.add_ancillary_variable(avr2, 0) + cube2.add_ancillary_variable(avr1, 0) + self.assertTrue(cube1 == cube2) + + def test_ancillary_diff_data(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + avr1 = AncillaryVariable([2, 3], long_name="foo") + avr2 = AncillaryVariable([4, 5], long_name="foo") + cube1.add_ancillary_variable(avr1, 0) + cube2.add_ancillary_variable(avr2, 0) + self.assertFalse(cube1 == cube2) + + def test_cell_measure_fail(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + cms = CellMeasure([2, 3], measure="area", long_name="foo") + cube2.add_cell_measure(cms, 0) + self.assertFalse(cube1 == cube2) + + def test_cell_measure_reorder(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + cms1 = CellMeasure([2, 3], measure="area", long_name="foo") + cms2 = CellMeasure([4, 5], measure="area", long_name="bar") + # Add the same cell measure to cube1 and cube2 in + # opposite orders. + cube1.add_cell_measure(cms1, 0) + cube1.add_cell_measure(cms2, 0) + cube2.add_cell_measure(cms2, 0) + cube2.add_cell_measure(cms1, 0) + self.assertTrue(cube1 == cube2) + + def test_cell_measure_diff_data(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + cms1 = CellMeasure([2, 3], measure="area", long_name="foo") + cms2 = CellMeasure([4, 5], measure="area", long_name="foo") + cube1.add_cell_measure(cms1, 0) + cube2.add_cell_measure(cms2, 0) + self.assertFalse(cube1 == cube2) + + def test_cell_method_fail(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + cmth = CellMethod("mean", "time", "6hr") + cube2.add_cell_method(cmth) + self.assertFalse(cube1 == cube2) + + # Unlike cell measures, cell methods are order sensitive. + def test_cell_method_reorder_fail(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + cmth1 = CellMethod("mean", "time", "6hr") + cmth2 = CellMethod("mean", "time", "12hr") + # Add the same cell method to cube1 and cube2 in + # opposite orders. + cube1.add_cell_method(cmth1) + cube1.add_cell_method(cmth2) + cube2.add_cell_method(cmth2) + cube2.add_cell_method(cmth1) + self.assertFalse(cube1 == cube2) + + def test_cell_method_correct_order(self): + cube1 = Cube([0, 1]) + cube2 = Cube([0, 1]) + cmth1 = CellMethod("mean", "time", "6hr") + cmth2 = CellMethod("mean", "time", "12hr") + # Add the same cell method to cube1 and cube2 in + # the same order. + cube1.add_cell_method(cmth1) + cube1.add_cell_method(cmth2) + cube2.add_cell_method(cmth1) + cube2.add_cell_method(cmth2) + self.assertTrue(cube1 == cube2) + + if __name__ == "__main__": tests.main()