Skip to content

Commit 29faec3

Browse files
committed
Test structured fill_value parsing
1 parent e3c7659 commit 29faec3

File tree

5 files changed

+90
-3
lines changed

5 files changed

+90
-3
lines changed

src/zarr/core/group.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3458,7 +3458,7 @@ def _build_metadata_v3(zarr_json: dict[str, JSON]) -> ArrayV3Metadata | GroupMet
34583458

34593459

34603460
def _build_metadata_v2(
3461-
zarr_json: dict[str, object], attrs_json: dict[str, JSON]
3461+
zarr_json: dict[str, JSON], attrs_json: dict[str, JSON]
34623462
) -> ArrayV2Metadata | GroupMetadata:
34633463
"""
34643464
Convert a dict representation of Zarr V2 metadata into the corresponding metadata class.

src/zarr/core/metadata/v2.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,9 @@ def parse_metadata(data: ArrayV2Metadata) -> ArrayV2Metadata:
318318
def parse_structured_fill_value(fill_value: Any, dtype: np.dtype[Any]) -> Any:
319319
"""Handle structured dtype/fill value pairs"""
320320
try:
321-
if isinstance(fill_value, (tuple, list)):
321+
if isinstance(fill_value, list):
322+
fill_value = tuple(fill_value)
323+
if isinstance(fill_value, tuple):
322324
fill_value = np.array([fill_value], dtype=dtype)[0]
323325
elif isinstance(fill_value, bytes):
324326
fill_value = np.frombuffer(fill_value, dtype=dtype)[0]

src/zarr/testing/strategies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import hypothesis.extra.numpy as npst
66
import hypothesis.strategies as st
77
import numpy as np
8-
from hypothesis import event, given, settings # noqa: F401
8+
from hypothesis import event
99
from hypothesis.strategies import SearchStrategy
1010

1111
import zarr

tests/test_properties.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import dataclasses
22
import json
33
import numbers
4+
45
import numpy as np
56
import pytest
67
from numpy.testing import assert_array_equal

tests/test_v2.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from zarr import config
1616
from zarr.abc.store import Store
1717
from zarr.core.buffer.core import default_buffer_prototype
18+
from zarr.core.metadata.v2 import parse_structured_fill_value
1819
from zarr.core.sync import sync
1920
from zarr.storage import MemoryStore, StorePath
2021

@@ -315,6 +316,89 @@ def test_structured_dtype_roundtrip(fill_value, tmp_path) -> None:
315316
assert (a == za[:]).all()
316317

317318

319+
@pytest.mark.parametrize(
320+
(
321+
"fill_value",
322+
"dtype",
323+
"expected_result",
324+
),
325+
[
326+
(
327+
("Alice", 30),
328+
np.dtype([("name", "U10"), ("age", "i4")]),
329+
np.array([("Alice", 30)], dtype=[("name", "U10"), ("age", "i4")])[0],
330+
),
331+
(
332+
["Bob", 25],
333+
np.dtype([("name", "U10"), ("age", "i4")]),
334+
np.array([("Bob", 25)], dtype=[("name", "U10"), ("age", "i4")])[0],
335+
),
336+
(
337+
b"\x01\x00\x00\x00\x02\x00\x00\x00",
338+
np.dtype([("x", "i4"), ("y", "i4")]),
339+
np.array([(1, 2)], dtype=[("x", "i4"), ("y", "i4")])[0],
340+
),
341+
(
342+
"BQAAAA==",
343+
np.dtype([("val", "i4")]),
344+
np.array([(5,)], dtype=[("val", "i4")])[0],
345+
),
346+
(
347+
{"x": 1, "y": 2},
348+
np.dtype([("location", "O")]),
349+
np.array([({"x": 1, "y": 2},)], dtype=[("location", "O")])[0],
350+
),
351+
(
352+
{"x": 1, "y": 2, "z": 3},
353+
np.dtype([("location", "O")]),
354+
np.array([({"x": 1, "y": 2, "z": 3},)], dtype=[("location", "O")])[0],
355+
),
356+
],
357+
ids=[
358+
"tuple_input",
359+
"list_input",
360+
"bytes_input",
361+
"string_input",
362+
"dictionary_input",
363+
"dictionary_input_extra_fields",
364+
],
365+
)
366+
def test_parse_structured_fill_value_valid(
367+
fill_value: Any, dtype: np.dtype[Any], expected_result: Any
368+
) -> None:
369+
result = parse_structured_fill_value(fill_value, dtype)
370+
assert result.dtype == expected_result.dtype
371+
assert result == expected_result
372+
if isinstance(expected_result, np.void):
373+
for name in expected_result.dtype.names or []:
374+
assert result[name] == expected_result[name]
375+
376+
377+
@pytest.mark.parametrize(
378+
(
379+
"fill_value",
380+
"dtype",
381+
),
382+
[
383+
(("Alice", 30), np.dtype([("name", "U10"), ("age", "i4"), ("city", "U20")])),
384+
(b"\x01\x00\x00\x00", np.dtype([("x", "i4"), ("y", "i4")])),
385+
("this_is_not_base64", np.dtype([("val", "i4")])),
386+
("hello", np.dtype([("age", "i4")])),
387+
({"x": 1, "y": 2}, np.dtype([("location", "i4")])),
388+
],
389+
ids=[
390+
"tuple_list_wrong_length",
391+
"bytes_wrong_length",
392+
"invalid_base64",
393+
"wrong_data_type",
394+
"wrong_dictionary",
395+
],
396+
)
397+
def test_parse_structured_fill_value_invalid(fill_value: Any, dtype: np.dtype[Any]) -> None:
398+
with pytest.raises(ValueError):
399+
parse_structured_fill_value(fill_value, dtype)
400+
401+
318402
@pytest.mark.parametrize("fill_value", [None, b"x"], ids=["no_fill", "fill"])
319403
def test_other_dtype_roundtrip(fill_value, tmp_path) -> None:
320404
a = np.array([b"a\0\0", b"bb", b"ccc"], dtype="V7")

0 commit comments

Comments
 (0)