Skip to content

Commit 501ae9e

Browse files
normanrzdcherian
andauthored
[v3] Makes data contiguous in v2 codec (#2515)
* fixes #2501 * typing * only use c-contiguous * more tests * typing * tests * astype with copy=False --------- Co-authored-by: Deepak Cherian <[email protected]>
1 parent 90b3aea commit 501ae9e

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

src/zarr/codecs/_v2.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from typing import TYPE_CHECKING
66

77
import numcodecs
8-
from numcodecs.compat import ensure_ndarray_like
8+
from numcodecs.compat import ensure_bytes, ensure_ndarray_like
99

1010
from zarr.abc.codec import ArrayBytesCodec
1111
from zarr.registry import get_ndbuffer_class
@@ -68,6 +68,9 @@ async def _encode_single(
6868
) -> Buffer | None:
6969
chunk = chunk_array.as_ndarray_like()
7070

71+
# ensure contiguous and correct order
72+
chunk = chunk.astype(chunk_spec.dtype, order=chunk_spec.order, copy=False)
73+
7174
# apply filters
7275
if self.filters:
7376
for f in self.filters:
@@ -83,6 +86,7 @@ async def _encode_single(
8386
else:
8487
cdata = chunk
8588

89+
cdata = ensure_bytes(cdata)
8690
return chunk_spec.prototype.buffer.from_bytes(cdata)
8791

8892
def compute_encoded_size(self, _input_byte_length: int, _chunk_spec: ArraySpec) -> int:

src/zarr/core/buffer/core.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ def reshape(
8080

8181
def view(self, dtype: npt.DTypeLike) -> Self: ...
8282

83-
def astype(self, dtype: npt.DTypeLike, order: Literal["K", "A", "C", "F"] = ...) -> Self: ...
83+
def astype(
84+
self,
85+
dtype: npt.DTypeLike,
86+
order: Literal["K", "A", "C", "F"] = ...,
87+
*,
88+
copy: bool = ...,
89+
) -> Self: ...
8490

8591
def fill(self, value: Any) -> None: ...
8692

tests/test_v2.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
from collections.abc import Iterator
3-
from typing import Any
3+
from typing import Any, Literal
44

55
import numcodecs.vlen
66
import numpy as np
@@ -126,9 +126,54 @@ async def test_create_dtype_str(dtype: Any) -> None:
126126

127127

128128
@pytest.mark.parametrize("filters", [[], [numcodecs.Delta(dtype="<i4")], [numcodecs.Zlib(level=2)]])
129-
def test_v2_filters_codecs(filters: Any) -> None:
129+
@pytest.mark.parametrize("order", ["C", "F"])
130+
def test_v2_filters_codecs(filters: Any, order: Literal["C", "F"]) -> None:
130131
array_fixture = [42]
131-
arr = zarr.create(shape=1, dtype="<i4", zarr_format=2, filters=filters)
132+
arr = zarr.create(shape=1, dtype="<i4", zarr_format=2, filters=filters, order=order)
132133
arr[:] = array_fixture
133134
result = arr[:]
134135
np.testing.assert_array_equal(result, array_fixture)
136+
137+
138+
@pytest.mark.parametrize("array_order", ["C", "F"])
139+
@pytest.mark.parametrize("data_order", ["C", "F"])
140+
def test_v2_non_contiguous(array_order: Literal["C", "F"], data_order: Literal["C", "F"]) -> None:
141+
arr = zarr.Array.create(
142+
MemoryStore({}),
143+
shape=(10, 8),
144+
chunks=(3, 3),
145+
fill_value=np.nan,
146+
dtype="float64",
147+
zarr_format=2,
148+
exists_ok=True,
149+
order=array_order,
150+
)
151+
152+
# Non-contiguous write
153+
a = np.arange(arr.shape[0] * arr.shape[1]).reshape(arr.shape, order=data_order)
154+
arr[slice(6, 9, None), slice(3, 6, None)] = a[
155+
slice(6, 9, None), slice(3, 6, None)
156+
] # The slice on the RHS is important
157+
np.testing.assert_array_equal(
158+
arr[slice(6, 9, None), slice(3, 6, None)], a[slice(6, 9, None), slice(3, 6, None)]
159+
)
160+
161+
arr = zarr.Array.create(
162+
MemoryStore({}),
163+
shape=(10, 8),
164+
chunks=(3, 3),
165+
fill_value=np.nan,
166+
dtype="float64",
167+
zarr_format=2,
168+
exists_ok=True,
169+
order=array_order,
170+
)
171+
172+
# Contiguous write
173+
a = np.arange(9).reshape((3, 3), order=data_order)
174+
if data_order == "F":
175+
assert a.flags.f_contiguous
176+
else:
177+
assert a.flags.c_contiguous
178+
arr[slice(6, 9, None), slice(3, 6, None)] = a
179+
np.testing.assert_array_equal(arr[slice(6, 9, None), slice(3, 6, None)], a)

0 commit comments

Comments
 (0)