diff --git a/zarr/core.py b/zarr/core.py index e0fe4eb0e9..88424ad9bd 100644 --- a/zarr/core.py +++ b/zarr/core.py @@ -135,6 +135,7 @@ class Array: set_mask_selection get_coordinate_selection set_coordinate_selection + set_options digest hexdigest resize @@ -191,6 +192,9 @@ def __init__( self._oindex = OIndex(self) self._vindex = VIndex(self) + # initialize options + self.set_options() + def _load_metadata(self): """(Re)load metadata from store.""" if self._synchronizer is None: @@ -860,6 +864,8 @@ def _get_basic_selection_zd(self, selection, out=None, fields=None): cdata = self.chunk_store[ckey] except KeyError: + if not self._fill_missing_chunk: + raise # chunk not initialized chunk = np.zeros((), dtype=self._dtype) if self._fill_value is not None: @@ -1547,6 +1553,18 @@ def set_coordinate_selection(self, selection, value, fields=None): self._set_selection(indexer, value, fields=fields) + def set_options(self, fill_missing_chunk=True): + """Set options. + + Parameters + ---------- + fill_missing_chunk : bool + Whether Zarr is supposed to fill missing chunks. Defaults to True. + + """ + + self._fill_missing_chunk = fill_missing_chunk + def set_mask_selection(self, selection, value, fields=None): """Modify a selection of individual items, by providing a Boolean array of the same shape as the array against which the selection is being made, where True @@ -1871,6 +1889,8 @@ def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection, cdata = self.chunk_store[ckey] except KeyError: + if not self._fill_missing_chunk: + raise # chunk not initialized if self._fill_value is not None: if fields: diff --git a/zarr/tests/test_missing.py b/zarr/tests/test_missing.py new file mode 100644 index 0000000000..7c6ed4fd47 --- /dev/null +++ b/zarr/tests/test_missing.py @@ -0,0 +1,44 @@ +import unittest +from zarr.creation import array + + +class TestArrayMissingKeys(unittest.TestCase): + def test_raises_on_missing_key_zd(self): + a = array(1, chunks=1) + + # pop first chunk + a.chunk_store.pop("0") + + # read from missing chunk and make sure fill-value is returned + assert a.fill_value == a[()] + + # configure raise on missing chunk + a.set_options(fill_missing_chunk=False) + + # reading missing chunk should raise + with self.assertRaises(KeyError): + a[()] + + def test_raises_on_missing_key_1d(self): + a = array(range(4), chunks=2) + + # pop first chunk + a.chunk_store.pop("0") + + # read from missing chunk and make sure fill-value is returned + assert a.fill_value == a[0] + assert a.fill_value == a[1] + + # read from avaible chunk w/o error + assert 2 == a[2] + assert 3 == a[3] + + # configure raise on missing chunk + a.set_options(fill_missing_chunk=False) + + # reading missing chunk should raise + with self.assertRaises(KeyError): + a[0] + + with self.assertRaises(KeyError): + a[:2]