diff --git a/Changelog.rst b/Changelog.rst index fb81561a34..25c42854df 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -1,3 +1,13 @@ +version 3.15.4 +-------------- + +**2023-??-??** + +* Fix bug in `cf.Field.match_by_construct` that always returned True for + 1-d constructs whose axis is not in the data, even when the + criterion was not matched + (https://github.com/NCAS-CMS/cf-python/issues/691) + version 3.15.3 -------------- @@ -54,7 +64,7 @@ version 3.15.1 (https://github.com/NCAS-CMS/cf-python/pull/654) * Fix `set_data` when the units are invalid (https://github.com/NCAS-CMS/cf-python/pull/646) -* Fix `cf.Field.laplacian_xy`, cf.Field.grad_xy`, `cf.curl_xy` and +* Fix `cf.Field.laplacian_xy`, `cf.Field.grad_xy`, `cf.curl_xy` and `cf.div_xy` to work in cases when the dimension coordinates are missing standard names (https://github.com/NCAS-CMS/cf-python/pull/643) diff --git a/cf/field.py b/cf/field.py index 50b1fd891b..8967e5c063 100644 --- a/cf/field.py +++ b/cf/field.py @@ -10324,7 +10324,24 @@ def indices(self, *mode, **kwargs): indices = [] # Add the indices that apply to the field's data dimensions - indices.extend([domain_indices["indices"][axis] for axis in data_axes]) + axis_indices = domain_indices["indices"] + indices.extend([axis_indices[axis] for axis in data_axes]) + + # Check that there are no invalid indices for size 1 axes not + # spanned by the data + if len(axis_indices) > len(data_axes): + for axis, index in axis_indices.items(): + if axis in data_axes or index == slice(None): + continue + + import dask.array as da + + shape = da.from_array([0])[index].compute_chunk_sizes().shape + if 0 in shape: + raise IndexError( + "Can't create size 0 indices for the size 1 " + f"{self.constructs.domain_axis_identity(axis)!r} axis" + ) return tuple(indices) diff --git a/cf/mixin/fielddomain.py b/cf/mixin/fielddomain.py index 5c5354db64..8af4ba4f8c 100644 --- a/cf/mixin/fielddomain.py +++ b/cf/mixin/fielddomain.py @@ -344,7 +344,8 @@ def _indices(self, mode, data_axes, ancillary_mask, kwargs): if debug: logger.debug( - f" item_axes = {item_axes!r}\n keys = {keys!r}" + f" item_axes = {item_axes!r}\n" + f" keys = {keys!r}" ) # pragma: no cover if n_axes == 1: @@ -369,9 +370,9 @@ def _indices(self, mode, data_axes, ancillary_mask, kwargs): if isinstance(value, (list, slice, tuple, np.ndarray)): # 1-d CASE 1: Value is already an index, e.g. [0], # [7,4,2], slice(0,4,2), - # numpy.array([2,4,7]), [True, False, - # True] - + # numpy.array([2,4,7]), + # [True,False,True] + index = value if debug: logger.debug(" 1-d CASE 1:") # pragma: no cover @@ -475,7 +476,7 @@ def _indices(self, mode, data_axes, ancillary_mask, kwargs): if debug: logger.debug( - f" index = {index}\n ind = {ind}" + f" index = {index}\n ind = {ind}" ) # pragma: no cover # Put the index into the correct place in the list of diff --git a/cf/test/test_Field.py b/cf/test/test_Field.py index e890125797..9292d76056 100644 --- a/cf/test/test_Field.py +++ b/cf/test/test_Field.py @@ -1637,7 +1637,9 @@ def test_Field_match(self): self.assertFalse(g.match_by_naxes(3)) self.assertFalse(g.match_by_naxes(99, 88)) - # Match by construct + def test_Field_match_by_construct(self): + f = self.f.copy() + for OR in (True, False): self.assertTrue(f.match_by_construct(OR=OR)) self.assertTrue(f.match_by_construct("X", OR=OR)) @@ -1673,6 +1675,11 @@ def test_Field_match(self): ) ) + # Check match for size 1 axes that are not spanned by the data + f = cf.example_field(0) + self.assertTrue(f.match_by_construct(T=cf.dt("2019-01-01"))) + self.assertFalse(f.match_by_construct(T=cf.dt("9876-12-31"))) + def test_Field_autocyclic(self): f = self.f.copy()