Skip to content

Commit c2e03c3

Browse files
dstansbynormanrz
andauthored
Add numpy to mypy pre-commit check env (#1893)
* Add numpy to mypy pre-commit check env * fixes for zstd * Ignore errors in zarr.buffer --------- Co-authored-by: Norman Rzepka <[email protected]>
1 parent 0c513fc commit c2e03c3

File tree

8 files changed

+30
-24
lines changed

8 files changed

+30
-24
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ repos:
2626
hooks:
2727
- id: mypy
2828
files: src
29-
args: []
3029
additional_dependencies:
3130
- types-redis
3231
- types-setuptools
3332
- pytest
33+
- numpy

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ module = [
230230
"zarr.v2.*",
231231
"zarr.array_v2",
232232
"zarr.array",
233+
"zarr.buffer"
233234
]
234235
disallow_untyped_calls = false
235236

src/zarr/array.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ async def setitem(
419419
# We accept any ndarray like object from the user and convert it
420420
# to a NDBuffer (or subclass). From this point onwards, we only pass
421421
# Buffer and NDBuffer between components.
422-
value = factory(value)
422+
value_buffer = factory(value)
423423

424424
# merging with existing data and encoding chunks
425425
await self.metadata.codec_pipeline.write(
@@ -432,7 +432,7 @@ async def setitem(
432432
)
433433
for chunk_coords, chunk_selection, out_selection in indexer
434434
],
435-
value,
435+
value_buffer,
436436
)
437437

438438
async def resize(

src/zarr/buffer.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
)
1212

1313
import numpy as np
14+
import numpy.typing as npt
1415

1516
if TYPE_CHECKING:
1617
from typing_extensions import Self
@@ -20,8 +21,8 @@
2021

2122
# TODO: create a protocol for the attributes we need, for now we alias Numpy's ndarray
2223
# both for the array-like and ndarray-like
23-
ArrayLike: TypeAlias = np.ndarray
24-
NDArrayLike: TypeAlias = np.ndarray
24+
ArrayLike: TypeAlias = npt.NDArray[Any]
25+
NDArrayLike: TypeAlias = npt.NDArray[Any]
2526

2627

2728
def check_item_key_is_1d_contiguous(key: Any) -> None:
@@ -40,7 +41,7 @@ def __call__(
4041
self,
4142
*,
4243
shape: Iterable[int],
43-
dtype: np.DTypeLike,
44+
dtype: npt.DTypeLike,
4445
order: Literal["C", "F"],
4546
fill_value: Any | None,
4647
) -> NDBuffer:
@@ -163,7 +164,7 @@ def as_array_like(self) -> NDArrayLike:
163164
"""
164165
return self._data
165166

166-
def as_nd_buffer(self, *, dtype: np.DTypeLike) -> NDBuffer:
167+
def as_nd_buffer(self, *, dtype: npt.DTypeLike) -> NDBuffer:
167168
"""Create a new NDBuffer from this one.
168169
169170
This will never copy data.
@@ -179,7 +180,7 @@ def as_nd_buffer(self, *, dtype: np.DTypeLike) -> NDBuffer:
179180
"""
180181
return NDBuffer.from_ndarray_like(self._data.view(dtype=dtype))
181182

182-
def as_numpy_array(self) -> np.ndarray:
183+
def as_numpy_array(self) -> npt.NDArray[Any]:
183184
"""Return the buffer as a NumPy array (host memory).
184185
185186
Warning
@@ -271,7 +272,7 @@ def create(
271272
cls,
272273
*,
273274
shape: Iterable[int],
274-
dtype: np.DTypeLike,
275+
dtype: npt.DTypeLike,
275276
order: Literal["C", "F"] = "C",
276277
fill_value: Any | None = None,
277278
) -> Self:
@@ -298,7 +299,7 @@ def create(
298299
A subclass can overwrite this method to create a ndarray-like object
299300
other then the default Numpy array.
300301
"""
301-
ret = cls(np.empty(shape=shape, dtype=dtype, order=order))
302+
ret = cls(np.empty(shape=tuple(shape), dtype=dtype, order=order))
302303
if fill_value is not None:
303304
ret.fill(fill_value)
304305
return ret
@@ -319,7 +320,7 @@ def from_ndarray_like(cls, ndarray_like: NDArrayLike) -> Self:
319320
return cls(ndarray_like)
320321

321322
@classmethod
322-
def from_numpy_array(cls, array_like: np.ArrayLike) -> Self:
323+
def from_numpy_array(cls, array_like: npt.ArrayLike) -> Self:
323324
"""Create a new buffer of Numpy array-like object
324325
325326
Parameters
@@ -360,7 +361,7 @@ def as_buffer(self) -> Buffer:
360361
data = np.ascontiguousarray(self._data)
361362
return Buffer(data.reshape(-1).view(dtype="b")) # Flatten the array without copy
362363

363-
def as_numpy_array(self) -> np.ndarray:
364+
def as_numpy_array(self) -> npt.NDArray[Any]:
364365
"""Return the buffer as a NumPy array (host memory).
365366
366367
Warning
@@ -393,9 +394,9 @@ def byteorder(self) -> Endian:
393394
return Endian(sys.byteorder)
394395

395396
def reshape(self, newshape: Iterable[int]) -> Self:
396-
return self.__class__(self._data.reshape(newshape))
397+
return self.__class__(self._data.reshape(tuple(newshape)))
397398

398-
def astype(self, dtype: np.DTypeLike, order: Literal["K", "A", "C", "F"] = "K") -> Self:
399+
def astype(self, dtype: npt.DTypeLike, order: Literal["K", "A", "C", "F"] = "K") -> Self:
399400
return self.__class__(self._data.astype(dtype=dtype, order=order))
400401

401402
def __getitem__(self, key: Any) -> Self:
@@ -418,11 +419,11 @@ def fill(self, value: Any) -> None:
418419
def copy(self) -> Self:
419420
return self.__class__(self._data.copy())
420421

421-
def transpose(self, *axes: np.SupportsIndex) -> Self:
422+
def transpose(self, *axes: np.SupportsIndex) -> Self: # type: ignore[name-defined]
422423
return self.__class__(self._data.transpose(*axes))
423424

424425

425-
def as_numpy_array_wrapper(func: Callable[[np.ndarray], bytes], buf: Buffer) -> Buffer:
426+
def as_numpy_array_wrapper(func: Callable[[npt.NDArray[Any]], bytes], buf: Buffer) -> Buffer:
426427
"""Converts the input of `func` to a numpy array and the output back to `Buffer`.
427428
428429
This function is useful when calling a `func` that only support host memory such

src/zarr/codecs/bytes.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ async def _encode_single(
9292
assert isinstance(chunk_array, NDBuffer)
9393
if chunk_array.dtype.itemsize > 1:
9494
if self.endian is not None and self.endian != chunk_array.byteorder:
95-
new_dtype = chunk_array.dtype.newbyteorder(self.endian.name)
95+
# type-ignore is a numpy bug
96+
# see https://github.com/numpy/numpy/issues/26473
97+
new_dtype = chunk_array.dtype.newbyteorder(self.endian.name) # type: ignore[arg-type]
9698
chunk_array = chunk_array.astype(new_dtype)
9799
return chunk_array.as_buffer()
98100

src/zarr/codecs/sharding.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from typing import TYPE_CHECKING, NamedTuple
99

1010
import numpy as np
11+
import numpy.typing as npt
1112

1213
from zarr.abc.codec import (
1314
ArrayBytesCodec,
@@ -85,7 +86,7 @@ async def delete(self) -> None:
8586

8687
class _ShardIndex(NamedTuple):
8788
# dtype uint64, shape (chunks_per_shard_0, chunks_per_shard_1, ..., 2)
88-
offsets_and_lengths: np.ndarray
89+
offsets_and_lengths: npt.NDArray[np.uint64]
8990

9091
@property
9192
def chunks_per_shard(self) -> ChunkCoords:
@@ -100,7 +101,7 @@ def _localize_chunk(self, chunk_coords: ChunkCoords) -> ChunkCoords:
100101
def is_all_empty(self) -> bool:
101102
return bool(np.array_equiv(self.offsets_and_lengths, MAX_UINT_64))
102103

103-
def get_full_chunk_map(self) -> np.ndarray:
104+
def get_full_chunk_map(self) -> npt.NDArray[np.bool_]:
104105
return self.offsets_and_lengths[..., 0] != MAX_UINT_64
105106

106107
def get_chunk_slice(self, chunk_coords: ChunkCoords) -> tuple[int, int] | None:

src/zarr/codecs/zstd.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from __future__ import annotations
22

33
from dataclasses import dataclass
4-
from typing import TYPE_CHECKING
4+
from typing import TYPE_CHECKING, Any
55

6+
import numpy.typing as npt
67
from zstandard import ZstdCompressor, ZstdDecompressor
78

89
from zarr.abc.codec import BytesBytesCodec
@@ -52,11 +53,11 @@ def from_dict(cls, data: dict[str, JSON]) -> Self:
5253
def to_dict(self) -> dict[str, JSON]:
5354
return {"name": "zstd", "configuration": {"level": self.level, "checksum": self.checksum}}
5455

55-
def _compress(self, data: bytes) -> bytes:
56+
def _compress(self, data: npt.NDArray[Any]) -> bytes:
5657
ctx = ZstdCompressor(level=self.level, write_checksum=self.checksum)
5758
return ctx.compress(data)
5859

59-
def _decompress(self, data: bytes) -> bytes:
60+
def _decompress(self, data: npt.NDArray[Any]) -> bytes:
6061
ctx = ZstdDecompressor()
6162
return ctx.decompress(data)
6263

src/zarr/store/local.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ def _put(
5858
if start is not None:
5959
with path.open("r+b") as f:
6060
f.seek(start)
61-
f.write(value.as_numpy_array())
61+
f.write(value.as_numpy_array().tobytes())
6262
return None
6363
else:
64-
return path.write_bytes(value.as_numpy_array())
64+
return path.write_bytes(value.as_numpy_array().tobytes())
6565

6666

6767
class LocalStore(Store):

0 commit comments

Comments
 (0)