Skip to content

Commit 4d79cfc

Browse files
dstansbyd-v-b
andauthored
Add type hints to zarr.create (#1536)
* Add type hints to zarr.create * Use protocol for MetaArray * Use protocol for Synchronizer * Fix Path typing * Add release note * Fix dim separator typing * Ignore ... in coverage reporting * Fix chunk typing --------- Co-authored-by: Davis Bennett <[email protected]>
1 parent cf32382 commit 4d79cfc

File tree

9 files changed

+67
-29
lines changed

9 files changed

+67
-29
lines changed

docs/release.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ Release notes
1818
Unreleased
1919
----------
2020

21+
Enhancements
22+
~~~~~~~~~~~~
23+
24+
* Added type hints to ``zarr.creation.create()``.
25+
By :user:`David Stansby <dstansby>` :issue:`1536`.
26+
2127
Docs
2228
~~~~
2329

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Homepage = "https://github.com/zarr-developers/zarr-python"
6565
exclude_lines = [
6666
"pragma: no cover",
6767
"pragma: ${PY_MAJOR_VERSION} no cover",
68+
'.*\.\.\.' # Ignore "..." lines
6869
]
6970

7071
[tool.coverage.run]

zarr/_storage/store.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from zarr.meta import Metadata2, Metadata3
1010
from zarr.util import normalize_storage_path
1111
from zarr.context import Context
12+
from zarr.types import ZARR_VERSION
1213

1314
# v2 store keys
1415
array_meta_key = ".zarray"
@@ -19,7 +20,7 @@
1920
meta_root = "meta/root/"
2021
data_root = "data/root/"
2122

22-
DEFAULT_ZARR_VERSION = 2
23+
DEFAULT_ZARR_VERSION: ZARR_VERSION = 2
2324

2425
v3_api_available = os.environ.get("ZARR_V3_EXPERIMENTAL_API", "0").lower() not in ["0", "false"]
2526

zarr/creation.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
from typing import Optional
1+
from collections.abc import MutableMapping
2+
from typing import Optional, Tuple, Union, Sequence
23
from warnings import warn
34

45
import numpy as np
6+
import numpy.typing as npt
7+
from numcodecs.abc import Codec
58
from numcodecs.registry import codec_registry
69

710
from zarr._storage.store import DEFAULT_ZARR_VERSION
@@ -19,32 +22,35 @@
1922
normalize_storage_path,
2023
normalize_store_arg,
2124
)
25+
from zarr._storage.store import StorageTransformer
26+
from zarr.sync import Synchronizer
27+
from zarr.types import ZARR_VERSION, DIMENSION_SEPARATOR, MEMORY_ORDER, MetaArray, PathLike
2228
from zarr.util import normalize_dimension_separator
2329

2430

2531
def create(
26-
shape,
27-
chunks=True,
28-
dtype=None,
32+
shape: Union[int, Tuple[int, ...]],
33+
chunks: Union[int, Tuple[int, ...], bool] = True,
34+
dtype: Optional[npt.DTypeLike] = None,
2935
compressor="default",
3036
fill_value: Optional[int] = 0,
31-
order="C",
32-
store=None,
33-
synchronizer=None,
34-
overwrite=False,
35-
path=None,
36-
chunk_store=None,
37-
filters=None,
38-
cache_metadata=True,
39-
cache_attrs=True,
40-
read_only=False,
41-
object_codec=None,
42-
dimension_separator=None,
43-
write_empty_chunks=True,
37+
order: MEMORY_ORDER = "C",
38+
store: Optional[Union[str, MutableMapping]] = None,
39+
synchronizer: Optional[Synchronizer] = None,
40+
overwrite: bool = False,
41+
path: Optional[PathLike] = None,
42+
chunk_store: Optional[MutableMapping] = None,
43+
filters: Optional[Sequence[Codec]] = None,
44+
cache_metadata: bool = True,
45+
cache_attrs: bool = True,
46+
read_only: bool = False,
47+
object_codec: Optional[Codec] = None,
48+
dimension_separator: Optional[DIMENSION_SEPARATOR] = None,
49+
write_empty_chunks: bool = True,
4450
*,
45-
zarr_version=None,
46-
meta_array=None,
47-
storage_transformers=(),
51+
zarr_version: Optional[ZARR_VERSION] = None,
52+
meta_array: Optional[MetaArray] = None,
53+
storage_transformers: Sequence[StorageTransformer] = (),
4854
**kwargs,
4955
):
5056
"""Create an array.

zarr/storage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from numcodecs.compat import ensure_bytes, ensure_text, ensure_contiguous_ndarray_like
4141
from numcodecs.registry import codec_registry
4242
from zarr.context import Context
43+
from zarr.types import PathLike as Path
4344

4445
from zarr.errors import (
4546
MetadataError,
@@ -105,7 +106,6 @@
105106
default_compressor = Zlib()
106107

107108

108-
Path = Union[str, bytes, None]
109109
# allow MutableMapping for backwards compatibility
110110
StoreLike = Union[BaseStore, MutableMapping]
111111

zarr/sync.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import os
22
from collections import defaultdict
33
from threading import Lock
4+
from typing import Protocol
45

56
import fasteners
67

78

8-
class ThreadSynchronizer:
9+
class Synchronizer(Protocol):
10+
"""Base class for synchronizers."""
11+
12+
def __getitem__(self, item):
13+
...
14+
15+
16+
class ThreadSynchronizer(Synchronizer):
917
"""Provides synchronization using thread locks."""
1018

1119
def __init__(self):
@@ -24,7 +32,7 @@ def __setstate__(self, *args):
2432
self.__init__()
2533

2634

27-
class ProcessSynchronizer:
35+
class ProcessSynchronizer(Synchronizer):
2836
"""Provides synchronization using file locks via the
2937
`fasteners <https://fasteners.readthedocs.io/en/latest/api/inter_process/>`_
3038
package.

zarr/tests/test_core.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import sys
44
import pickle
55
import shutil
6-
from typing import Any, Literal, Optional, Tuple, Union
6+
from typing import Any, Literal, Optional, Tuple, Union, Sequence
77
import unittest
88
from itertools import zip_longest
99
from tempfile import mkdtemp
@@ -26,6 +26,7 @@
2626
VLenUTF8,
2727
Zlib,
2828
)
29+
from numcodecs.abc import Codec
2930
from numcodecs.compat import ensure_bytes, ensure_ndarray
3031
from numcodecs.tests.common import greetings
3132
from numpy.testing import assert_array_almost_equal, assert_array_equal
@@ -73,6 +74,7 @@
7374
from zarr.tests.test_storage_v3 import DummyStorageTransfomer
7475
from zarr.util import buffer_size
7576
from zarr.tests.util import abs_container, skip_test_env_var, have_fsspec, mktemp
77+
from zarr.types import DIMENSION_SEPARATOR
7678

7779
# noinspection PyMethodMayBeStatic
7880

@@ -82,8 +84,8 @@ class TestArray:
8284
root = ""
8385
path = ""
8486
compressor = Zlib(level=1)
85-
filters = None
86-
dimension_separator: Literal["/", ".", None] = None
87+
filters: Optional[Sequence[Codec]] = None
88+
dimension_separator: Optional[DIMENSION_SEPARATOR] = None
8789
cache_metadata = True
8890
cache_attrs = True
8991
partial_decompress: bool = False

zarr/types.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from typing import Literal, Protocol, Union
2+
3+
ZARR_VERSION = Literal[2, 3]
4+
DIMENSION_SEPARATOR = Literal[".", "/"]
5+
MEMORY_ORDER = Literal["C", "F"]
6+
7+
8+
PathLike = Union[str, bytes, None]
9+
10+
11+
class MetaArray(Protocol):
12+
def __array_function__(self, func, types, args, kwargs):
13+
...

zarr/util.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from numcodecs.ndarray_like import NDArrayLike
3232
from numcodecs.registry import codec_registry
3333
from numcodecs.blosc import cbuffer_sizes, cbuffer_metainfo
34+
from zarr.types import DIMENSION_SEPARATOR
3435

3536
KeyType = TypeVar("KeyType")
3637
ValueType = TypeVar("ValueType")
@@ -284,9 +285,9 @@ def normalize_order(order: str) -> str:
284285
return order
285286

286287

287-
def normalize_dimension_separator(sep: Optional[str]) -> Optional[str]:
288+
def normalize_dimension_separator(sep: Optional[str]) -> Optional[DIMENSION_SEPARATOR]:
288289
if sep in (".", "/", None):
289-
return sep
290+
return cast(Optional[DIMENSION_SEPARATOR], sep)
290291
else:
291292
raise ValueError("dimension_separator must be either '.' or '/', found: %r" % sep)
292293

0 commit comments

Comments
 (0)