diff --git a/changes/4046.misc.md b/changes/4046.misc.md new file mode 100644 index 0000000000..96c0c7d78a --- /dev/null +++ b/changes/4046.misc.md @@ -0,0 +1 @@ +Replace the internal `DefaultFillValue` sentinel class with a `typing_extensions.Sentinel`, and raise the minimum `typing_extensions` version to 4.14. diff --git a/pyproject.toml b/pyproject.toml index 23eba4e643..9f6005f981 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ dependencies = [ 'numpy>=2', 'numcodecs>=0.14', 'google-crc32c>=1.5', - 'typing_extensions>=4.13', + 'typing_extensions>=4.14', 'donfig>=0.8', ] @@ -256,7 +256,7 @@ extra-dependencies = [ 'fsspec==2023.10.0', 's3fs==2023.10.0', 'universal_pathlib==0.2.0', - 'typing_extensions==4.13.*', + 'typing_extensions==4.14.*', 'donfig==0.8.*', 'obstore==0.5.*', ] diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index 366c19bb0c..9740f575a0 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -18,7 +18,7 @@ from warnings import warn import numpy as np -from typing_extensions import deprecated +from typing_extensions import Sentinel, deprecated import zarr from zarr.abc.codec import ArrayArrayCodec, ArrayBytesCodec, BytesBytesCodec, Codec @@ -162,7 +162,6 @@ # Array and AsyncArray are defined in the base ``zarr`` namespace __all__ = [ "DEFAULT_FILL_VALUE", - "DefaultFillValue", "create_codec_pipeline", "parse_array_metadata", ] @@ -170,22 +169,19 @@ logger = getLogger(__name__) -class DefaultFillValue: - """ - Sentinel class to indicate that the default fill value should be used. - - This class exists because conventional values used to convey "defaultness" like ``None`` or - ``"auto"` are ambiguous when specifying the fill value parameter of a Zarr array. - The value ``None`` is ambiguous because it is a valid fill value for Zarr V2 - (resulting in ``"fill_value": null`` in array metadata). - A string like ``"auto"`` is ambiguous because such a string is a valid fill value for an array - with a string data type. - An instance of this class lies outside the space of valid fill values, which means it can - unambiguously express that the default fill value should be used. - """ - +DEFAULT_FILL_VALUE = Sentinel("DEFAULT_FILL_VALUE") +""" +Sentinel indicating that the default fill value should be used. -DEFAULT_FILL_VALUE = DefaultFillValue() +This sentinel exists because conventional values used to convey "defaultness" like `None` or +`"auto"` are ambiguous when specifying the fill value parameter of a Zarr array. +The value `None` is ambiguous because it is a valid fill value for Zarr V2 +(resulting in `"fill_value": null` in array metadata). +A string like `"auto"` is ambiguous because such a string is a valid fill value for an array +with a string data type. +This sentinel lies outside the space of valid fill values, which means it can +unambiguously express that the default fill value should be used. +""" def _chunk_sizes_from_shape( @@ -541,9 +537,9 @@ def _create_metadata_v3( else: chunk_key_encoding_parsed = chunk_key_encoding - if isinstance(fill_value, DefaultFillValue) or fill_value is None: - # Use dtype's default scalar for DefaultFillValue sentinel - # For v3, None is converted to DefaultFillValue behavior + if fill_value is DEFAULT_FILL_VALUE or fill_value is None: + # Use dtype's default scalar for the DEFAULT_FILL_VALUE sentinel + # For v3, None is converted to DEFAULT_FILL_VALUE behavior fill_value_parsed = dtype.default_scalar() else: fill_value_parsed = fill_value @@ -625,8 +621,8 @@ def _create_metadata_v2( if dimension_separator is None: dimension_separator = "." - # Handle DefaultFillValue sentinel - if isinstance(fill_value, DefaultFillValue): + # Handle the DEFAULT_FILL_VALUE sentinel + if fill_value is DEFAULT_FILL_VALUE: fill_value_parsed: Any = dtype.default_scalar() else: # For v2, preserve None as-is (backward compatibility) diff --git a/uv.lock b/uv.lock index 8f06e43cb6..de7dfed316 100644 --- a/uv.lock +++ b/uv.lock @@ -4055,7 +4055,7 @@ requires-dist = [ { name = "obstore", marker = "extra == 'remote'", specifier = ">=0.5.1" }, { name = "packaging", specifier = ">=22.0" }, { name = "typer", marker = "extra == 'cli'" }, - { name = "typing-extensions", specifier = ">=4.13" }, + { name = "typing-extensions", specifier = ">=4.14" }, { name = "universal-pathlib", marker = "extra == 'optional'" }, ] provides-extras = ["cast-value-rs", "cli", "gpu", "optional", "remote"]