|
2 | 2 |
|
3 | 3 | import json |
4 | 4 | import math |
| 5 | +import sys |
5 | 6 | from collections.abc import Mapping |
6 | 7 | from importlib.metadata import version |
7 | 8 | from typing import ( |
|
21 | 22 |
|
22 | 23 | import numpy as np |
23 | 24 | import numpy.typing as npt |
24 | | -import zarr |
25 | | -from numcodecs.abc import Codec |
26 | 25 | from packaging.version import Version |
27 | 26 | from pydantic import AfterValidator, BaseModel, field_validator, model_validator |
28 | 27 | from pydantic.functional_validators import BeforeValidator |
29 | | -from zarr.core.array import Array, AsyncArray |
30 | | -from zarr.core.metadata import ArrayV2Metadata |
31 | | -from zarr.core.sync import sync |
32 | | -from zarr.errors import ContainsArrayError, ContainsGroupError |
33 | | -from zarr.storage._common import make_store_path |
34 | 28 |
|
35 | 29 | from pydantic_zarr.core import ( |
36 | 30 | IncEx, |
|
42 | 36 | ) |
43 | 37 |
|
44 | 38 | if TYPE_CHECKING: |
| 39 | + import zarr |
| 40 | + from numcodecs.abc import Codec |
45 | 41 | from zarr.abc.store import Store |
46 | 42 | from zarr.core.array_spec import ArrayConfigParams |
47 | 43 |
|
@@ -90,7 +86,8 @@ def dictify_codec(value: dict[str, Any] | Codec) -> dict[str, Any]: |
90 | 86 | object is returned. This should be a dict with string keys. All other values pass |
91 | 87 | through unaltered. |
92 | 88 | """ |
93 | | - if isinstance(value, Codec): |
| 89 | + |
| 90 | + if (numcodecs := sys.modules.get("numcodecs")) and isinstance(value, numcodecs.abc.Codec): |
94 | 91 | return value.get_config() |
95 | 92 | return value |
96 | 93 |
|
@@ -334,6 +331,11 @@ def from_zarr(cls, array: zarr.Array) -> Self: |
334 | 331 | ArraySpec(zarr_format=2, attributes={}, shape=(10, 10), chunks=(10, 10), dtype='<f8', fill_value=0.0, order='C', filters=None, dimension_separator='.', compressor={'id': 'blosc', 'cname': 'lz4', 'clevel': 5, 'shuffle': 1, 'blocksize': 0}) |
335 | 332 |
|
336 | 333 | """ |
| 334 | + try: |
| 335 | + from zarr.core.metadata import ArrayV2Metadata |
| 336 | + except ImportError as e: |
| 337 | + raise ImportError("zarr must be installed to use from_zarr") from e |
| 338 | + |
337 | 339 | if not isinstance(array.metadata, ArrayV2Metadata): |
338 | 340 | msg = "Array is not a Zarr format 2 array" |
339 | 341 | raise TypeError(msg) |
@@ -378,6 +380,16 @@ def to_zarr( |
378 | 380 | zarr.Array |
379 | 381 | A Zarr array that is structurally identical to `self`. |
380 | 382 | """ |
| 383 | + try: |
| 384 | + import zarr |
| 385 | + from zarr.core.array import Array, AsyncArray |
| 386 | + from zarr.core.metadata import ArrayV2Metadata |
| 387 | + from zarr.core.sync import sync |
| 388 | + from zarr.errors import ContainsArrayError, ContainsGroupError |
| 389 | + from zarr.storage._common import make_store_path |
| 390 | + except ImportError as e: |
| 391 | + raise ImportError("zarr must be installed to use to_zarr") from e |
| 392 | + |
381 | 393 | store_path = sync(make_store_path(store, path=path)) |
382 | 394 |
|
383 | 395 | extant_node = maybe_node(store, path, zarr_format=2) |
@@ -449,10 +461,10 @@ def like( |
449 | 461 | """ |
450 | 462 |
|
451 | 463 | other_parsed: ArraySpec |
452 | | - if isinstance(other, zarr.Array): |
| 464 | + if (zarr := sys.modules.get("zarr")) and isinstance(other, zarr.Array): |
453 | 465 | other_parsed = ArraySpec.from_zarr(other) |
454 | 466 | else: |
455 | | - other_parsed = other |
| 467 | + other_parsed = other # type: ignore[assignment] |
456 | 468 |
|
457 | 469 | return model_like(self, other_parsed, include=include, exclude=exclude) |
458 | 470 |
|
@@ -505,6 +517,10 @@ def from_zarr(cls, group: zarr.Group, *, depth: int = -1) -> Self: |
505 | 517 | ------- |
506 | 518 | An instance of GroupSpec that represents the structure of the Zarr hierarchy. |
507 | 519 | """ |
| 520 | + try: |
| 521 | + import zarr |
| 522 | + except ImportError as e: |
| 523 | + raise ImportError("zarr must be installed to use from_zarr") from e |
508 | 524 |
|
509 | 525 | result: GroupSpec[TAttr, TItem] |
510 | 526 | attributes = group.attrs.asdict() |
@@ -563,6 +579,12 @@ def to_zarr( |
563 | 579 | A zarr group that is structurally identical to `self`. |
564 | 580 |
|
565 | 581 | """ |
| 582 | + try: |
| 583 | + import zarr |
| 584 | + from zarr.errors import ContainsArrayError, ContainsGroupError |
| 585 | + except ImportError as e: |
| 586 | + raise ImportError("zarr must be installed to use to_zarr") from e |
| 587 | + |
566 | 588 | spec_dict = self.model_dump(exclude={"members": True}) |
567 | 589 | attrs = spec_dict.pop("attributes") |
568 | 590 | extant_node = maybe_node(store, path, zarr_format=2) |
@@ -660,10 +682,10 @@ def like( |
660 | 682 | """ |
661 | 683 |
|
662 | 684 | other_parsed: GroupSpec |
663 | | - if isinstance(other, zarr.Group): |
| 685 | + if (zarr := sys.modules.get("zarr")) and isinstance(other, zarr.Group): |
664 | 686 | other_parsed = GroupSpec.from_zarr(other) |
665 | 687 | else: |
666 | | - other_parsed = other |
| 688 | + other_parsed = other # type: ignore[assignment] |
667 | 689 |
|
668 | 690 | return model_like(self, other_parsed, include=include, exclude=exclude) |
669 | 691 |
|
@@ -764,6 +786,7 @@ def from_zarr(element: zarr.Array | zarr.Group, depth: int = -1) -> AnyArraySpec |
764 | 786 | An instance of `GroupSpec` or `ArraySpec` that models the structure of the input Zarr group |
765 | 787 | or array. |
766 | 788 | """ |
| 789 | + import zarr |
767 | 790 |
|
768 | 791 | if isinstance(element, zarr.Array): |
769 | 792 | return ArraySpec.from_zarr(element) |
|
0 commit comments