Skip to content

Commit 99a3576

Browse files
authored
Fix: order for v2 arrays (#2679)
* fixes order for v2 arrays * release notes
1 parent e10b69d commit 99a3576

File tree

3 files changed

+56
-14
lines changed

3 files changed

+56
-14
lines changed

docs/release-notes.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
Release notes
22
=============
33

4+
Unreleased
5+
----------
6+
7+
New features
8+
~~~~~~~~~~~~
9+
10+
Bug fixes
11+
~~~~~~~~~
12+
* Fixes ``order`` argument for Zarr format 2 arrays.
13+
By :user:`Norman Rzepka <normanrz>` (:issue:`2679`).
14+
15+
Behaviour changes
16+
~~~~~~~~~~~~~~~~~
17+
418
.. _release_3.0.0:
519

620
3.0.0

src/zarr/core/array.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import warnings
55
from asyncio import gather
66
from collections.abc import Iterable
7-
from dataclasses import dataclass, field
7+
from dataclasses import dataclass, field, replace
88
from itertools import starmap
99
from logging import getLogger
1010
from typing import (
@@ -1226,14 +1226,17 @@ async def _get_selection(
12261226
fill_value=self.metadata.fill_value,
12271227
)
12281228
if product(indexer.shape) > 0:
1229+
# need to use the order from the metadata for v2
1230+
_config = self._config
1231+
if self.metadata.zarr_format == 2:
1232+
_config = replace(_config, order=self.metadata.order)
1233+
12291234
# reading chunks and decoding them
12301235
await self.codec_pipeline.read(
12311236
[
12321237
(
12331238
self.store_path / self.metadata.encode_chunk_key(chunk_coords),
1234-
self.metadata.get_chunk_spec(
1235-
chunk_coords, self._config, prototype=prototype
1236-
),
1239+
self.metadata.get_chunk_spec(chunk_coords, _config, prototype=prototype),
12371240
chunk_selection,
12381241
out_selection,
12391242
)
@@ -1350,12 +1353,17 @@ async def _set_selection(
13501353
# Buffer and NDBuffer between components.
13511354
value_buffer = prototype.nd_buffer.from_ndarray_like(value)
13521355

1356+
# need to use the order from the metadata for v2
1357+
_config = self._config
1358+
if self.metadata.zarr_format == 2:
1359+
_config = replace(_config, order=self.metadata.order)
1360+
13531361
# merging with existing data and encoding chunks
13541362
await self.codec_pipeline.write(
13551363
[
13561364
(
13571365
self.store_path / self.metadata.encode_chunk_key(chunk_coords),
1358-
self.metadata.get_chunk_spec(chunk_coords, self._config, prototype),
1366+
self.metadata.get_chunk_spec(chunk_coords, _config, prototype),
13591367
chunk_selection,
13601368
out_selection,
13611369
)

tests/test_v2.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import zarr.core.buffer
1313
import zarr.storage
1414
from zarr import config
15+
from zarr.core.buffer.core import default_buffer_prototype
16+
from zarr.core.sync import sync
1517
from zarr.storage import MemoryStore, StorePath
1618

1719

@@ -166,36 +168,54 @@ def test_v2_filters_codecs(filters: Any, order: Literal["C", "F"]) -> None:
166168

167169
@pytest.mark.parametrize("array_order", ["C", "F"])
168170
@pytest.mark.parametrize("data_order", ["C", "F"])
169-
def test_v2_non_contiguous(array_order: Literal["C", "F"], data_order: Literal["C", "F"]) -> None:
171+
@pytest.mark.parametrize("memory_order", ["C", "F"])
172+
def test_v2_non_contiguous(
173+
array_order: Literal["C", "F"], data_order: Literal["C", "F"], memory_order: Literal["C", "F"]
174+
) -> None:
175+
store = MemoryStore()
170176
arr = zarr.create_array(
171-
MemoryStore({}),
177+
store,
172178
shape=(10, 8),
173179
chunks=(3, 3),
174180
fill_value=np.nan,
175181
dtype="float64",
176182
zarr_format=2,
183+
filters=None,
184+
compressors=None,
177185
overwrite=True,
178186
order=array_order,
187+
config={"order": memory_order},
179188
)
180189

181190
# Non-contiguous write
182191
a = np.arange(arr.shape[0] * arr.shape[1]).reshape(arr.shape, order=data_order)
183-
arr[slice(6, 9, None), slice(3, 6, None)] = a[
184-
slice(6, 9, None), slice(3, 6, None)
185-
] # The slice on the RHS is important
192+
arr[6:9, 3:6] = a[6:9, 3:6] # The slice on the RHS is important
193+
np.testing.assert_array_equal(arr[6:9, 3:6], a[6:9, 3:6])
194+
186195
np.testing.assert_array_equal(
187-
arr[slice(6, 9, None), slice(3, 6, None)], a[slice(6, 9, None), slice(3, 6, None)]
196+
a[6:9, 3:6],
197+
np.frombuffer(
198+
sync(store.get("2.1", default_buffer_prototype())).to_bytes(), dtype="float64"
199+
).reshape((3, 3), order=array_order),
188200
)
201+
if memory_order == "F":
202+
assert (arr[6:9, 3:6]).flags.f_contiguous
203+
else:
204+
assert (arr[6:9, 3:6]).flags.c_contiguous
189205

206+
store = MemoryStore()
190207
arr = zarr.create_array(
191-
MemoryStore({}),
208+
store,
192209
shape=(10, 8),
193210
chunks=(3, 3),
194211
fill_value=np.nan,
195212
dtype="float64",
196213
zarr_format=2,
214+
compressors=None,
215+
filters=None,
197216
overwrite=True,
198217
order=array_order,
218+
config={"order": memory_order},
199219
)
200220

201221
# Contiguous write
@@ -204,8 +224,8 @@ def test_v2_non_contiguous(array_order: Literal["C", "F"], data_order: Literal["
204224
assert a.flags.f_contiguous
205225
else:
206226
assert a.flags.c_contiguous
207-
arr[slice(6, 9, None), slice(3, 6, None)] = a
208-
np.testing.assert_array_equal(arr[slice(6, 9, None), slice(3, 6, None)], a)
227+
arr[6:9, 3:6] = a
228+
np.testing.assert_array_equal(arr[6:9, 3:6], a)
209229

210230

211231
def test_default_compressor_deprecation_warning():

0 commit comments

Comments
 (0)