Skip to content

Commit e67d4dc

Browse files
committed
emit warning about unstable dtype when serializing Structured dtype to JSON
1 parent ce0afe3 commit e67d4dc

File tree

7 files changed

+42
-16
lines changed

7 files changed

+42
-16
lines changed

src/zarr/core/dtype/common.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import warnings
34
from dataclasses import dataclass
45
from typing import Final, Literal
56

@@ -43,3 +44,22 @@ class HasItemSize:
4344
@property
4445
def item_size(self) -> int:
4546
raise NotImplementedError
47+
48+
49+
class UnstableSpecificationWarning(FutureWarning): ...
50+
51+
52+
def v3_unstable_dtype_warning(dtype: object) -> None:
53+
"""
54+
Emit this warning when a data type does not have a stable zarr v3 spec
55+
"""
56+
msg = (
57+
f"The data type ({dtype}) does not have a Zarr V3 specification. "
58+
"That means that the representation of data saved with this data type may change without "
59+
"warning in a future version of Zarr Python. "
60+
"Arrays stored with this data type may be unreadable by other Zarr libraries "
61+
"Use this data type at your own risk! "
62+
"Check https://github.com/zarr-developers/zarr-extensions/tree/main/data-types for the "
63+
"status of data type specifications for Zarr V3."
64+
)
65+
warnings.warn(msg, category=UnstableSpecificationWarning, stacklevel=2)

src/zarr/core/dtype/npy/sized.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77
import numpy as np
88

99
from zarr.core.common import JSON, ZarrFormat
10-
from zarr.core.dtype.common import DataTypeValidationError, HasEndianness, HasItemSize, HasLength
10+
from zarr.core.dtype.common import (
11+
DataTypeValidationError,
12+
HasEndianness,
13+
HasItemSize,
14+
HasLength,
15+
v3_unstable_dtype_warning,
16+
)
1117
from zarr.core.dtype.npy.common import (
1218
EndiannessNumpy,
1319
bytes_from_json,
@@ -325,6 +331,7 @@ def to_json(self, zarr_format: ZarrFormat) -> JSON:
325331
if zarr_format == 2:
326332
return fields
327333
elif zarr_format == 3:
334+
v3_unstable_dtype_warning(self)
328335
base_dict = {"name": self._zarr_v3_name}
329336
base_dict["configuration"] = {"fields": fields} # type: ignore[assignment]
330337
return cast("JSON", base_dict)

src/zarr/core/dtype/wrapper.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
from __future__ import annotations
2424

25-
import warnings
2625
from abc import ABC, abstractmethod
2726
from dataclasses import dataclass
2827
from typing import TYPE_CHECKING, ClassVar, Generic, Self, TypeGuard, TypeVar
@@ -336,15 +335,3 @@ def from_json_value(self: Self, data: JSON, *, zarr_format: ZarrFormat) -> TScal
336335
The native scalar value.
337336
"""
338337
...
339-
340-
341-
def v3_unstable_dtype_warning(dtype: ZDType[TBaseDType, TBaseScalar]) -> None:
342-
msg = (
343-
f"You are using a data type ({dtype}) that does not have a stable Zarr V3 specification."
344-
"Be advised that arrays stored with this data type may be unreadable by other Zarr "
345-
"libraries, and possibly future versions of Zarr-Python as well. "
346-
"Use this data type at your own risk."
347-
"See https://github.com/zarr-developers/zarr-extensions/tree/main/data-types for a list"
348-
"of data types with a stable Zarr V3 specification."
349-
)
350-
warnings.warn(msg, category=FutureWarning, stacklevel=2)

tests/test_array.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ def test_array_name_properties_with_group(
189189
assert spam.basename == "spam"
190190

191191

192+
@pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning")
192193
@pytest.mark.parametrize("store", ["memory"], indirect=True)
193194
@pytest.mark.parametrize("specifiy_fill_value", [True, False])
194195
@pytest.mark.parametrize(
@@ -199,7 +200,7 @@ def test_array_fill_value_default(
199200
) -> None:
200201
"""
201202
Test that creating an array with the fill_value parameter set to None, or unspecified,
202-
results in the expected fill_value attribute of the array, i.e. 0 cast to the array's dtype.
203+
results in the expected fill_value attribute of the array, i.e. the default value of the dtype
203204
"""
204205
shape = (10,)
205206
if specifiy_fill_value:
@@ -994,6 +995,7 @@ def test_chunks_and_shards(store: Store) -> None:
994995

995996
@staticmethod
996997
@pytest.mark.parametrize("dtype", zdtype_examples)
998+
@pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning")
997999
def test_default_fill_value(dtype: ZDType[Any, Any], store: Store) -> None:
9981000
"""
9991001
Test that the fill value of an array is set to the default value for the dtype object
@@ -1005,6 +1007,7 @@ def test_default_fill_value(dtype: ZDType[Any, Any], store: Store) -> None:
10051007
assert a.fill_value == dtype.default_value()
10061008

10071009
@staticmethod
1010+
@pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning")
10081011
@pytest.mark.parametrize("dtype", zdtype_examples)
10091012
def test_dtype_forms(dtype: ZDType[Any, Any], store: Store, zarr_format: ZarrFormat) -> None:
10101013
"""
@@ -1050,6 +1053,7 @@ def test_dtype_forms(dtype: ZDType[Any, Any], store: Store, zarr_format: ZarrFor
10501053
assert a.dtype == c.dtype
10511054

10521055
@staticmethod
1056+
@pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning")
10531057
@pytest.mark.parametrize("dtype", zdtype_examples)
10541058
def test_dtype_roundtrip(
10551059
dtype: ZDType[Any, Any], store: Store, zarr_format: ZarrFormat

tests/test_dtype/conftest.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Generate a collection of zdtype instances for use in testing.
2+
import warnings
23
from typing import Any
34

45
import numpy as np
@@ -13,7 +14,11 @@
1314
for wrapper_cls in data_type_registry.contents.values():
1415
# The Structured dtype has to be constructed with some actual fields
1516
if wrapper_cls is Structured:
16-
zdtype_examples += (wrapper_cls.from_dtype(np.dtype([("a", np.float64), ("b", np.int8)])),)
17+
with warnings.catch_warnings():
18+
warnings.simplefilter("ignore")
19+
zdtype_examples += (
20+
wrapper_cls.from_dtype(np.dtype([("a", np.float64), ("b", np.int8)])),
21+
)
1722
elif issubclass(wrapper_cls, HasLength):
1823
zdtype_examples += (wrapper_cls(length=1),)
1924
elif issubclass(wrapper_cls, DateTime64 | TimeDelta64):

tests/test_dtype/test_wrapper.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def test_from_json_roundtrip_v2(self, valid_json_v2: Any) -> None:
105105
zdtype = self.test_cls.from_json(valid_json_v2, zarr_format=2)
106106
assert zdtype.to_json(zarr_format=2) == valid_json_v2
107107

108+
@pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning")
108109
def test_from_json_roundtrip_v3(self, valid_json_v3: Any) -> None:
109110
zdtype = self.test_cls.from_json(valid_json_v3, zarr_format=3)
110111
assert zdtype.to_json(zarr_format=3) == valid_json_v3

tests/test_dtype_registry.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ def test_unregistered_dtype(data_type_registry_fixture: DataTypeRegistry) -> Non
9494
data_type_registry_fixture.get(outside_dtype)
9595

9696
@staticmethod
97+
@pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning")
9798
@pytest.mark.parametrize("zdtype", zdtype_examples)
9899
def test_registered_dtypes(
99100
zdtype: ZDType[TBaseDType, TBaseScalar], zarr_format: ZarrFormat
@@ -111,6 +112,7 @@ def test_registered_dtypes(
111112
)
112113

113114
@staticmethod
115+
@pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning")
114116
@pytest.mark.parametrize("zdtype", zdtype_examples)
115117
def test_match_dtype_unique(
116118
zdtype: ZDType[Any, Any],

0 commit comments

Comments
 (0)