From 7b3f23c25ac075ab45d2f1a50d03ead3f4074b2e Mon Sep 17 00:00:00 2001 From: victorwon2001 <192616110+victorwon2001@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:10:20 +0900 Subject: [PATCH 1/4] fix: include required pull request template headings --- src/zarr/core/array.py | 9 ++++++++- tests/test_codecs/test_transpose.py | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index 06f7338755..670b46ff91 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -27,6 +27,7 @@ from zarr.abc.numcodec import Numcodec, _is_numcodec from zarr.codecs._v2 import V2Codec from zarr.codecs.bytes import BytesCodec +from zarr.codecs.transpose import TransposeCodec from zarr.codecs.vlen_utf8 import VLenBytesCodec, VLenUTF8Codec from zarr.codecs.zstd import ZstdCodec from zarr.core._info import ArrayInfo @@ -4681,6 +4682,12 @@ async def init_array( dtype=zdtype, ) sub_codecs = cast("tuple[Codec, ...]", (*array_array, array_bytes, *bytes_bytes)) + + if order is not None and not any( + isinstance(codec, TransposeCodec) for codec in sub_codecs + ): + sub_codecs = (*array_array, TransposeCodec(order=tuple(reversed(range(len(shape_parsed))))), array_bytes, *bytes_bytes) + config = replace(parse_array_config(config), order=order) # A stored chunk grid passed as chunks= / shards= (e.g. by the "keep" # path of from_array) becomes the stored grid verbatim, so the new # array preserves the source grid exactly — including trailing edges @@ -4710,7 +4717,7 @@ async def init_array( else: codecs_out = sub_codecs - if order is not None: + if order is not None and not any(isinstance(codec, TransposeCodec) for codec in sub_codecs): _warn_order_kwarg() meta = AsyncArray._create_metadata_v3( shape=shape_parsed, diff --git a/tests/test_codecs/test_transpose.py b/tests/test_codecs/test_transpose.py index 949bb72a62..f606808395 100644 --- a/tests/test_codecs/test_transpose.py +++ b/tests/test_codecs/test_transpose.py @@ -61,6 +61,29 @@ async def test_transpose( assert read_data.flags["C_CONTIGUOUS"] +@pytest.mark.parametrize("store", ["local", "memory"], indirect=["store"]) +def test_create_array_v3_order_f_preserves_fortran_output(store: Store) -> None: + data = np.arange(12, dtype="float32").reshape((3, 4), order="F") + spath = StorePath(store, "transpose_from_order") + + a = zarr.create_array( + spath, + shape=data.shape, + chunks=data.shape, + dtype=data.dtype, + order="F", + ) + a[:] = data + + reopened = zarr.open_array(spath).with_config({"order": "F"}) + read_data = reopened[:] + + assert np.array_equal(read_data, data) + assert read_data.flags["F_CONTIGUOUS"] + assert not read_data.flags["C_CONTIGUOUS"] + assert any(isinstance(codec, TransposeCodec) for codec in reopened.filters) + + @pytest.mark.parametrize("store", ["local", "memory"], indirect=["store"]) @pytest.mark.parametrize("order", [[1, 2, 0], [1, 2, 3, 0], [3, 2, 4, 0, 1]]) def test_transpose_non_self_inverse(store: Store, order: list[int]) -> None: From a6f702b8ac992dda8339ae22a2d01ec8164b7ccb Mon Sep 17 00:00:00 2001 From: victorwon2001 <192616110+victorwon2001@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:22:41 +0900 Subject: [PATCH 2/4] fix: satisfy transpose test lint checks --- src/zarr/core/array.py | 11 +++++++---- tests/test_codecs/test_transpose.py | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index 670b46ff91..bad3532a81 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -4683,10 +4683,13 @@ async def init_array( ) sub_codecs = cast("tuple[Codec, ...]", (*array_array, array_bytes, *bytes_bytes)) - if order is not None and not any( - isinstance(codec, TransposeCodec) for codec in sub_codecs - ): - sub_codecs = (*array_array, TransposeCodec(order=tuple(reversed(range(len(shape_parsed))))), array_bytes, *bytes_bytes) + if order is not None and not any(isinstance(codec, TransposeCodec) for codec in sub_codecs): + sub_codecs = ( + *array_array, + TransposeCodec(order=tuple(reversed(range(len(shape_parsed))))), + array_bytes, + *bytes_bytes, + ) config = replace(parse_array_config(config), order=order) # A stored chunk grid passed as chunks= / shards= (e.g. by the "keep" # path of from_array) becomes the stored grid verbatim, so the new diff --git a/tests/test_codecs/test_transpose.py b/tests/test_codecs/test_transpose.py index f606808395..f10a8b67d6 100644 --- a/tests/test_codecs/test_transpose.py +++ b/tests/test_codecs/test_transpose.py @@ -76,7 +76,7 @@ def test_create_array_v3_order_f_preserves_fortran_output(store: Store) -> None: a[:] = data reopened = zarr.open_array(spath).with_config({"order": "F"}) - read_data = reopened[:] + read_data = np.asarray(reopened[:]) assert np.array_equal(read_data, data) assert read_data.flags["F_CONTIGUOUS"] From eb3fb6b4287d50eaa52a102794c9229fe3eb1797 Mon Sep 17 00:00:00 2001 From: victorwon2001 <192616110+victorwon2001@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:50:47 +0900 Subject: [PATCH 3/4] fix: preserve zarr v3 order warning behavior --- src/zarr/core/array.py | 4 ++-- tests/test_codecs/test_transpose.py | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index bad3532a81..f289663f53 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -4675,6 +4675,8 @@ async def init_array( attributes=attributes, ) else: + if order is not None and config is None: + _warn_order_kwarg() array_array, array_bytes, bytes_bytes = _parse_chunk_encoding_v3( compressors=compressors, filters=filters, @@ -4720,8 +4722,6 @@ async def init_array( else: codecs_out = sub_codecs - if order is not None and not any(isinstance(codec, TransposeCodec) for codec in sub_codecs): - _warn_order_kwarg() meta = AsyncArray._create_metadata_v3( shape=shape_parsed, dtype=zdtype, diff --git a/tests/test_codecs/test_transpose.py b/tests/test_codecs/test_transpose.py index f10a8b67d6..e34839c054 100644 --- a/tests/test_codecs/test_transpose.py +++ b/tests/test_codecs/test_transpose.py @@ -66,13 +66,14 @@ def test_create_array_v3_order_f_preserves_fortran_output(store: Store) -> None: data = np.arange(12, dtype="float32").reshape((3, 4), order="F") spath = StorePath(store, "transpose_from_order") - a = zarr.create_array( - spath, - shape=data.shape, - chunks=data.shape, - dtype=data.dtype, - order="F", - ) + with pytest.warns(RuntimeWarning, match="The `order` keyword argument has no effect for Zarr format 3 arrays"): + a = zarr.create_array( + spath, + shape=data.shape, + chunks=data.shape, + dtype=data.dtype, + order="F", + ) a[:] = data reopened = zarr.open_array(spath).with_config({"order": "F"}) From 49f8c69daf6bf4655595111a609ac5ba33d7737c Mon Sep 17 00:00:00 2001 From: victorwon2001 <192616110+victorwon2001@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:57:04 +0900 Subject: [PATCH 4/4] style: format transpose regression test --- tests/test_codecs/test_transpose.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_codecs/test_transpose.py b/tests/test_codecs/test_transpose.py index e34839c054..25cb392c1d 100644 --- a/tests/test_codecs/test_transpose.py +++ b/tests/test_codecs/test_transpose.py @@ -66,7 +66,9 @@ def test_create_array_v3_order_f_preserves_fortran_output(store: Store) -> None: data = np.arange(12, dtype="float32").reshape((3, 4), order="F") spath = StorePath(store, "transpose_from_order") - with pytest.warns(RuntimeWarning, match="The `order` keyword argument has no effect for Zarr format 3 arrays"): + with pytest.warns( + RuntimeWarning, match="The `order` keyword argument has no effect for Zarr format 3 arrays" + ): a = zarr.create_array( spath, shape=data.shape,