From c30cb7148cd1d46ba34cf6ce13fd1b0386d292a6 Mon Sep 17 00:00:00 2001 From: Tammas Loughran Date: Tue, 4 Oct 2022 11:20:31 +1100 Subject: [PATCH 1/6] Added more descriptive error message if indexing with all False bool array. --- src/netCDF4/utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/netCDF4/utils.py b/src/netCDF4/utils.py index c96cc7575..59cc4f640 100644 --- a/src/netCDF4/utils.py +++ b/src/netCDF4/utils.py @@ -208,6 +208,12 @@ def _StartCountStride(elem, shape, dimensions=None, grp=None, datashape=None,\ if sum(1 for e in elem if e is Ellipsis) > 1: raise IndexError("At most one ellipsis allowed in a slicing expression") + # Check if elem is valid for bool array. + if type(elem) is np.ndarray: + if elem.dtype is np.dtype(bool) and np.logical_not(np.any(elem)) + raise IndexError("All elements of bool indexing array are False. " + "At least one element must be True to be valid.") + # replace boolean arrays with sequences of integers. newElem = [] IndexErrorMsg=\ From 5e4e90355cd0f02054f19857713ef7b5121ecacd Mon Sep 17 00:00:00 2001 From: Tammas Loughran Date: Sun, 9 Oct 2022 19:25:24 +1100 Subject: [PATCH 2/6] Moved error message --- src/netCDF4/utils.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/netCDF4/utils.py b/src/netCDF4/utils.py index 59cc4f640..dcfeca857 100644 --- a/src/netCDF4/utils.py +++ b/src/netCDF4/utils.py @@ -208,12 +208,6 @@ def _StartCountStride(elem, shape, dimensions=None, grp=None, datashape=None,\ if sum(1 for e in elem if e is Ellipsis) > 1: raise IndexError("At most one ellipsis allowed in a slicing expression") - # Check if elem is valid for bool array. - if type(elem) is np.ndarray: - if elem.dtype is np.dtype(bool) and np.logical_not(np.any(elem)) - raise IndexError("All elements of bool indexing array are False. " - "At least one element must be True to be valid.") - # replace boolean arrays with sequences of integers. newElem = [] IndexErrorMsg=\ @@ -244,6 +238,10 @@ def _StartCountStride(elem, shape, dimensions=None, grp=None, datashape=None,\ unlim = False # convert boolean index to integer array. if np.iterable(ea) and ea.dtype.kind =='b': + # check that boolean array is not all False. + if not ea.any(): + msg='Boolean index array is all False, at least one element must be True' + raise IndexError(msg) # check that boolean array not too long if not unlim and shape[i] != len(ea): msg=""" From ab787f1bc3f9442a0501b18fba8634eaf372d238 Mon Sep 17 00:00:00 2001 From: jswhit Date: Mon, 10 Oct 2022 20:27:00 -0600 Subject: [PATCH 3/6] return empty array if boolean index array is all False --- src/netCDF4/_netCDF4.pyx | 2 +- src/netCDF4/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/netCDF4/_netCDF4.pyx b/src/netCDF4/_netCDF4.pyx index 5acd32c8d..29852a65d 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -4953,7 +4953,7 @@ rename a `Variable` attribute named `oldname` to `newname`.""" # put_ind for this dimension is set to -1 by _StartCountStride. squeeze = data.ndim * [slice(None),] for i,n in enumerate(put_ind.shape[:-1]): - if n == 1 and put_ind[...,i].ravel()[0] == -1: + if n == 1 and put_ind.size > 0 and put_ind[...,i].ravel()[0] == -1: squeeze[i] = 0 # Reshape the arrays so we can iterate over them. diff --git a/src/netCDF4/utils.py b/src/netCDF4/utils.py index c96cc7575..3ed627021 100644 --- a/src/netCDF4/utils.py +++ b/src/netCDF4/utils.py @@ -457,7 +457,7 @@ def _out_array_shape(count): out = [] for i, n in enumerate(s): - if n == 1: + if n == 1 and count.size > 0: c = count[..., i].ravel()[0] # All elements should be identical. out.append(c) else: From d70c336ac877d4d4c0e397f99debb4888bb87e19 Mon Sep 17 00:00:00 2001 From: jswhit Date: Mon, 10 Oct 2022 20:36:19 -0600 Subject: [PATCH 4/6] update --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index a68911d95..41baa59c7 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,9 @@ ========================== * Added ``netCDF4.__has_set_alignment__`` property to help identify if the underlying netcdf4 supports setting the HDF5 alignment. + * Slicing multi-dimensional variables with an all False boolean index array + now returns an empty numpy array (instead of raising an exception - issue #1197). + Behavior now consistent with numpy slicing. version 1.6.1 (tag v1.6.1rel) ============================== From 60702d1993fe127c78894ff679c10556e74e68f1 Mon Sep 17 00:00:00 2001 From: jswhit Date: Tue, 11 Oct 2022 07:28:59 -0600 Subject: [PATCH 5/6] add test for all False boolean index slicing multi-dim array --- test/tst_fancyslicing.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/tst_fancyslicing.py b/test/tst_fancyslicing.py index dd359a52d..38611b3cb 100644 --- a/test/tst_fancyslicing.py +++ b/test/tst_fancyslicing.py @@ -142,6 +142,11 @@ def test_get(self): assert_array_equal(v[0], self.data[0]) + # slicing with all False booleans (PR #1197) + iby[:] = False + data = v[ibx,iby,ibz] + assert(data.size == 0) + f.close() def test_set(self): From 4f37a43a90c114e6e3e5fb08b68d5fdfe0f0978f Mon Sep 17 00:00:00 2001 From: Tammas Loughran Date: Wed, 12 Oct 2022 21:04:58 +1100 Subject: [PATCH 6/6] Changed to warning --- src/netCDF4/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/netCDF4/utils.py b/src/netCDF4/utils.py index 44c2bbc67..d0fd389b1 100644 --- a/src/netCDF4/utils.py +++ b/src/netCDF4/utils.py @@ -240,8 +240,8 @@ def _StartCountStride(elem, shape, dimensions=None, grp=None, datashape=None,\ if np.iterable(ea) and ea.dtype.kind =='b': # check that boolean array is not all False. if not ea.any(): - msg='Boolean index array is all False, at least one element must be True' - raise IndexError(msg) + msg='Boolean index array is all False. Empty array will be returned.' + warnings.warn(msg) # check that boolean array not too long if not unlim and shape[i] != len(ea): msg="""