Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 451
[v3] fix: zarr v2 compatibility fixes for Dask#2186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
fe49f5f9a1580b0d89912d78e384e534279dea4a3d7800f3893b61fc88afe52fb6752d0b1dedc322918aa95d54a128eb533c170ef54ab9ef77f29382295d765879d673940d22File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -3,13 +3,14 @@ | ||
| import json | ||
| from asyncio import gather | ||
| from dataclasses import dataclass, field, replace | ||
| from logging import getLogger | ||
| from typing import TYPE_CHECKING, Any, Literal, cast | ||
| import numpy as np | ||
| import numpy.typing as npt | ||
| from zarr._compat import _deprecate_positional_args | ||
| from zarr.abc.store import set_or_delete | ||
| from zarr.abc.store import Store, set_or_delete | ||
| from zarr.codecs import BytesCodec | ||
| from zarr.codecs._v2 import V2Compressor, V2Filters | ||
| from zarr.core.attributes import Attributes | ||
| @@ -19,7 +20,7 @@ | ||
| NDBuffer, | ||
| default_buffer_prototype, | ||
| ) | ||
| from zarr.core.chunk_grids import RegularChunkGrid, _guess_chunks | ||
| from zarr.core.chunk_grids import RegularChunkGrid, normalize_chunks | ||
| from zarr.core.chunk_key_encodings import ( | ||
| ChunkKeyEncoding, | ||
| DefaultChunkKeyEncoding, | ||
| @@ -67,10 +68,8 @@ | ||
| from zarr.core.metadata.v3 import ArrayV3Metadata | ||
| from zarr.core.sync import collect_aiterator, sync | ||
| from zarr.registry import get_pipeline_class | ||
| from zarr.store import StoreLike, StorePath, make_store_path | ||
| from zarr.store.common import ( | ||
| ensure_no_existing_node, | ||
| ) | ||
| from zarr.storage import StoreLike, make_store_path | ||
| from zarr.storage.common import StorePath, ensure_no_existing_node | ||
| if TYPE_CHECKING: | ||
| from collections.abc import Iterable, Iterator, Sequence | ||
| @@ -82,6 +81,8 @@ | ||
| # Array and AsyncArray are defined in the base ``zarr`` namespace | ||
| __all__ = ["create_codec_pipeline", "parse_array_metadata"] | ||
| logger = getLogger(__name__) | ||
| def parse_array_metadata(data: Any) -> ArrayV2Metadata | ArrayV3Metadata: | ||
| if isinstance(data, ArrayV2Metadata | ArrayV3Metadata): | ||
| @@ -222,15 +223,14 @@ async def create( | ||
| shape = parse_shapelike(shape) | ||
| if chunk_shape is None: | ||
| if chunks is None: | ||
| chunk_shape = chunks = _guess_chunks(shape=shape, typesize=np.dtype(dtype).itemsize) | ||
| else: | ||
| chunks = parse_shapelike(chunks) | ||
| if chunks is not None and chunk_shape is not None: | ||
| raise ValueError("Only one of chunk_shape or chunks can be provided.") | ||
| chunk_shape = chunks | ||
| elif chunks is not None: | ||
| raise ValueError("Only one of chunk_shape or chunks must be provided.") | ||
| dtype = np.dtype(dtype) | ||
| if chunks: | ||
| _chunks = normalize_chunks(chunks, shape, dtype.itemsize) | ||
| else: | ||
| _chunks = normalize_chunks(chunk_shape, shape, dtype.itemsize) | ||
| if zarr_format == 3: | ||
| if dimension_separator is not None: | ||
| @@ -253,7 +253,7 @@ async def create( | ||
| store_path, | ||
| shape=shape, | ||
| dtype=dtype, | ||
| chunk_shape=chunk_shape, | ||
| chunk_shape=_chunks, | ||
| fill_value=fill_value, | ||
| chunk_key_encoding=chunk_key_encoding, | ||
| codecs=codecs, | ||
| @@ -276,7 +276,7 @@ async def create( | ||
| store_path, | ||
| shape=shape, | ||
| dtype=dtype, | ||
| chunks=chunk_shape, | ||
| chunks=_chunks, | ||
| dimension_separator=dimension_separator, | ||
| fill_value=fill_value, | ||
| order=order, | ||
| @@ -404,6 +404,10 @@ async def open( | ||
| metadata_dict = await get_array_metadata(store_path, zarr_format=zarr_format) | ||
| return cls(store_path=store_path, metadata=metadata_dict) | ||
| @property | ||
| def store(self) -> Store: | ||
| return self.store_path.store | ||
| @property | ||
| def ndim(self) -> int: | ||
| return len(self.metadata.shape) | ||
| @@ -831,6 +835,10 @@ def open( | ||
| async_array = sync(AsyncArray.open(store)) | ||
| return cls(async_array) | ||
| @property | ||
| def store(self) -> Store: | ||
| return self._async_array.store | ||
jhamman marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| @property | ||
| def ndim(self) -> int: | ||
| return self._async_array.ndim | ||
| @@ -2380,15 +2388,26 @@ def chunks_initialized(array: Array | AsyncArray) -> tuple[str, ...]: | ||
| def _build_parents(node: AsyncArray | AsyncGroup) -> list[AsyncGroup]: | ||
| from zarr.core.group import AsyncGroup, GroupMetadata | ||
| required_parts = node.store_path.path.split("/")[:-1] | ||
| parents = [] | ||
| store = node.store_path.store | ||
| path = node.store_path.path | ||
| if not path: | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know whether this branch is covered by an existing test? If not, it might be good to add one. MemberAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this path is highly exercised. | ||
| return [] | ||
| required_parts = path.split("/")[:-1] | ||
| parents = [ | ||
| # the root group | ||
| AsyncGroup( | ||
| metadata=GroupMetadata(zarr_format=node.metadata.zarr_format), | ||
| store_path=StorePath(store=store, path=""), | ||
| ) | ||
| ] | ||
| for i, part in enumerate(required_parts): | ||
| path = "/".join(required_parts[:i] + [part]) | ||
| p = "/".join(required_parts[:i] + [part]) | ||
| parents.append( | ||
| AsyncGroup( | ||
| metadata=GroupMetadata(zarr_format=node.metadata.zarr_format), | ||
| store_path=StorePath(store=node.store_path.store, path=path), | ||
| store_path=StorePath(store=store, path=p), | ||
| ) | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -2,11 +2,12 @@ | ||
| import itertools | ||
| import math | ||
| import numbers | ||
| import operator | ||
| from abc import abstractmethod | ||
| from dataclasses import dataclass | ||
| from functools import reduce | ||
| from typing import TYPE_CHECKING | ||
| from typing import TYPE_CHECKING, Any | ||
| import numpy as np | ||
| @@ -97,6 +98,49 @@ def _guess_chunks( | ||
| return tuple(int(x) for x in chunks) | ||
| def normalize_chunks(chunks: Any, shape: tuple[int, ...], typesize: int) -> tuple[int, ...]: | ||
| """Convenience function to normalize the `chunks` argument for an array | ||
| with the given `shape`.""" | ||
| # N.B., expect shape already normalized | ||
| # handle auto-chunking | ||
| if chunks is None or chunks is True: | ||
d-v-b marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| return _guess_chunks(shape, typesize) | ||
| # handle no chunking | ||
| if chunks is False: | ||
| return shape | ||
| # handle 1D convenience form | ||
| if isinstance(chunks, numbers.Integral): | ||
| chunks = tuple(int(chunks) for _ in shape) | ||
| # handle dask-style chunks (iterable of iterables) | ||
| if all(isinstance(c, (tuple | list)) for c in chunks): | ||
| # take first chunk size for each dimension | ||
| chunks = tuple( | ||
| c[0] for c in chunks | ||
| ) # TODO: check/error/warn for irregular chunks (e.g. if c[0] != c[1:-1]) | ||
| # handle bad dimensionality | ||
| if len(chunks) > len(shape): | ||
| raise ValueError("too many dimensions in chunks") | ||
| # handle underspecified chunks | ||
| if len(chunks) < len(shape): | ||
| # assume chunks across remaining dimensions | ||
| chunks += shape[len(chunks) :] | ||
| # handle None or -1 in chunks | ||
| if -1 in chunks or None in chunks: | ||
| chunks = tuple( | ||
| s if c == -1 or c is None else int(c) for s, c in zip(shape, chunks, strict=False) | ||
| ) | ||
| return tuple(int(c) for c in chunks) | ||
| @dataclass(frozen=True) | ||
| class ChunkGrid(Metadata): | ||
| @classmethod | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from zarr.storage.common import StoreLike, StorePath, make_store_path | ||
| from zarr.storage.local import LocalStore | ||
| from zarr.storage.memory import MemoryStore | ||
| from zarr.storage.remote import RemoteStore | ||
| from zarr.storage.zip import ZipStore | ||
| __all__ = [ | ||
| "LocalStore", | ||
| "MemoryStore", | ||
| "RemoteStore", | ||
| "StoreLike", | ||
| "StorePath", | ||
| "ZipStore", | ||
| "make_store_path", | ||
| ] |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.