From f2e1cf69245c9f7436a39bc0266e86e568447b93 Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Sun, 8 Feb 2026 22:48:55 +0100 Subject: [PATCH 1/3] fix: raise error when encountering nullable string dtype --- src/zarr/core/dtype/registry.py | 7 +++++++ tests/test_dtype_registry.py | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/zarr/core/dtype/registry.py b/src/zarr/core/dtype/registry.py index cb9ab50044..5b947409bb 100644 --- a/src/zarr/core/dtype/registry.py +++ b/src/zarr/core/dtype/registry.py @@ -159,6 +159,13 @@ def match_dtype(self, dtype: TBaseDType) -> ZDType[TBaseDType, TBaseScalar]: "data type, see https://github.com/zarr-developers/zarr-python/issues/3117" ) raise ValueError(msg) + if dtype.kind == "T" and hasattr(dtype, "na_object"): + msg = ( + f"Zarr data type resolution from {dtype} failed. " + "Attempted to resolve a zarr data type from a `numpy.dtypes.StringDType` " + "with `na_object` set, which is not supported." + ) + raise ValueError(msg) matched: list[ZDType[TBaseDType, TBaseScalar]] = [] for val in self.contents.values(): with contextlib.suppress(DataTypeValidationError): diff --git a/tests/test_dtype_registry.py b/tests/test_dtype_registry.py index 58b14fe07a..463602a2b1 100644 --- a/tests/test_dtype_registry.py +++ b/tests/test_dtype_registry.py @@ -15,6 +15,7 @@ get_data_type_from_json, ) from zarr.core.dtype.common import unpack_dtype_json +from zarr.core.dtype.npy.string import _NUMPY_SUPPORTS_VLEN_STRING from zarr.dtype import ( # type: ignore[attr-defined] Bool, FixedLengthUTF32, @@ -74,6 +75,15 @@ def test_match_dtype( data_type_registry_fixture.register(wrapper_cls._zarr_v3_name, wrapper_cls) assert isinstance(data_type_registry_fixture.match_dtype(np.dtype(dtype_str)), wrapper_cls) + @pytest.mark.skipif(not _NUMPY_SUPPORTS_VLEN_STRING, reason="requires numpy with T dtype") + @staticmethod + def test_match_dtype_string_na_object_error( + data_type_registry_fixture: DataTypeRegistry, + ) -> None: + dtype = np.dtypes.StringDType(na_object=None) + with pytest.raises(ValueError, match=r"Zarr data type resolution from StringDType.*failed"): + data_type_registry_fixture.match_dtype(dtype) + @staticmethod def test_unregistered_dtype(data_type_registry_fixture: DataTypeRegistry) -> None: """ From 48b754a232b2cae90e40b723a47db881d76651f8 Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Sun, 8 Feb 2026 22:51:35 +0100 Subject: [PATCH 2/3] add change entry --- changes/3695.bugfix.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/3695.bugfix.md diff --git a/changes/3695.bugfix.md b/changes/3695.bugfix.md new file mode 100644 index 0000000000..a7d847e4f1 --- /dev/null +++ b/changes/3695.bugfix.md @@ -0,0 +1 @@ +Raise error when trying to encode :class:`numpy.dtypes.StringDType` with `na_object` set. \ No newline at end of file From d5cd48418c321325308636f0c2d9c1442f8db420 Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Sun, 8 Feb 2026 22:57:51 +0100 Subject: [PATCH 3/3] fix typing --- tests/test_dtype_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_dtype_registry.py b/tests/test_dtype_registry.py index 463602a2b1..85454a6859 100644 --- a/tests/test_dtype_registry.py +++ b/tests/test_dtype_registry.py @@ -80,7 +80,7 @@ def test_match_dtype( def test_match_dtype_string_na_object_error( data_type_registry_fixture: DataTypeRegistry, ) -> None: - dtype = np.dtypes.StringDType(na_object=None) + dtype: np.dtype[Any] = np.dtypes.StringDType(na_object=None) # type: ignore[call-arg] with pytest.raises(ValueError, match=r"Zarr data type resolution from StringDType.*failed"): data_type_registry_fixture.match_dtype(dtype)