numcodecs 0.13.1__cp311-cp311-macosx_11_0_arm64.whl → 0.14.1__cp311-cp311-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of numcodecs might be problematic. Click here for more details.

Files changed (46) hide show
  1. numcodecs/__init__.py +12 -6
  2. numcodecs/_shuffle.cpython-311-darwin.so +0 -0
  3. numcodecs/abc.py +2 -1
  4. numcodecs/bitround.py +2 -1
  5. numcodecs/blosc.cpython-311-darwin.so +0 -0
  6. numcodecs/checksum32.py +86 -10
  7. numcodecs/compat.py +2 -4
  8. numcodecs/compat_ext.cpython-311-darwin.so +0 -0
  9. numcodecs/delta.py +5 -1
  10. numcodecs/fletcher32.cpython-311-darwin.so +0 -0
  11. numcodecs/jenkins.cpython-311-darwin.so +0 -0
  12. numcodecs/lz4.cpython-311-darwin.so +0 -0
  13. numcodecs/lzma.py +5 -2
  14. numcodecs/ndarray_like.py +1 -1
  15. numcodecs/packbits.py +0 -3
  16. numcodecs/pcodec.py +2 -3
  17. numcodecs/registry.py +9 -8
  18. numcodecs/tests/test_bitround.py +3 -3
  19. numcodecs/tests/test_blosc.py +2 -2
  20. numcodecs/tests/test_checksum32.py +113 -17
  21. numcodecs/tests/test_compat.py +3 -0
  22. numcodecs/tests/test_delta.py +1 -0
  23. numcodecs/tests/test_entrypoints.py +1 -1
  24. numcodecs/tests/test_entrypoints_backport.py +3 -2
  25. numcodecs/tests/test_fixedscaleoffset.py +13 -5
  26. numcodecs/tests/test_json.py +1 -1
  27. numcodecs/tests/test_lzma.py +4 -0
  28. numcodecs/tests/test_msgpacks.py +4 -1
  29. numcodecs/tests/test_pcodec.py +1 -1
  30. numcodecs/tests/test_registry.py +12 -10
  31. numcodecs/tests/test_shuffle.py +3 -3
  32. numcodecs/tests/test_zarr3.py +246 -0
  33. numcodecs/tests/test_zarr3_import.py +13 -0
  34. numcodecs/tests/test_zfpy.py +6 -0
  35. numcodecs/version.py +2 -2
  36. numcodecs/vlen.cpython-311-darwin.so +0 -0
  37. numcodecs/zarr3.py +379 -0
  38. numcodecs/zfpy.py +4 -2
  39. numcodecs/zstd.cpython-311-darwin.so +0 -0
  40. {numcodecs-0.13.1.dist-info → numcodecs-0.14.1.dist-info}/METADATA +20 -19
  41. numcodecs-0.14.1.dist-info/RECORD +78 -0
  42. {numcodecs-0.13.1.dist-info → numcodecs-0.14.1.dist-info}/WHEEL +1 -1
  43. numcodecs-0.14.1.dist-info/entry_points.txt +22 -0
  44. numcodecs-0.13.1.dist-info/RECORD +0 -74
  45. {numcodecs-0.13.1.dist-info → numcodecs-0.14.1.dist-info}/LICENSE.txt +0 -0
  46. {numcodecs-0.13.1.dist-info → numcodecs-0.14.1.dist-info}/top_level.txt +0 -0
numcodecs/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # ruff: noqa: E402,F401
1
+ # ruff: noqa: E402
2
2
  """Numcodecs is a Python package providing buffer compression and
3
3
  transformation codecs for use in data storage and communication
4
4
  applications. These include:
@@ -21,8 +21,9 @@ import atexit
21
21
  import multiprocessing
22
22
  from contextlib import suppress
23
23
 
24
- from numcodecs.registry import get_codec, register_codec
25
- from numcodecs.version import version as __version__
24
+ from numcodecs.registry import get_codec as get_codec
25
+ from numcodecs.registry import register_codec
26
+ from numcodecs.version import version as __version__ # noqa: F401
26
27
  from numcodecs.zlib import Zlib
27
28
 
28
29
  register_codec(Zlib)
@@ -55,13 +56,13 @@ with suppress(ImportError):
55
56
  atexit.register(blosc.destroy)
56
57
 
57
58
  with suppress(ImportError):
58
- from numcodecs import zstd
59
+ from numcodecs import zstd as zstd
59
60
  from numcodecs.zstd import Zstd
60
61
 
61
62
  register_codec(Zstd)
62
63
 
63
64
  with suppress(ImportError):
64
- from numcodecs import lz4
65
+ from numcodecs import lz4 as lz4
65
66
  from numcodecs.lz4 import LZ4
66
67
 
67
68
  register_codec(LZ4)
@@ -122,12 +123,17 @@ register_codec(CRC32)
122
123
  register_codec(Adler32)
123
124
  register_codec(JenkinsLookup3)
124
125
 
126
+ with suppress(ImportError):
127
+ from numcodecs.checksum32 import CRC32C
128
+
129
+ register_codec(CRC32C)
130
+
125
131
  from numcodecs.json import JSON
126
132
 
127
133
  register_codec(JSON)
128
134
 
129
135
  with suppress(ImportError):
130
- from numcodecs import vlen
136
+ from numcodecs import vlen as vlen
131
137
  from numcodecs.vlen import VLenArray, VLenBytes, VLenUTF8
132
138
 
133
139
  register_codec(VLenUTF8)
Binary file
numcodecs/abc.py CHANGED
@@ -29,13 +29,14 @@ other and vice versa.
29
29
  """
30
30
 
31
31
  from abc import ABC, abstractmethod
32
+ from typing import Optional
32
33
 
33
34
 
34
35
  class Codec(ABC):
35
36
  """Codec abstract base class."""
36
37
 
37
38
  # override in sub-class
38
- codec_id = None
39
+ codec_id: Optional[str] = None
39
40
  """Codec identifier."""
40
41
 
41
42
  @abstractmethod
numcodecs/bitround.py CHANGED
@@ -59,7 +59,8 @@ class BitRound(Codec):
59
59
  return a
60
60
  if self.keepbits > bits:
61
61
  raise ValueError("Keepbits too large for given dtype")
62
- b = a.view(a_int_dtype)
62
+ b = a.copy()
63
+ b = b.view(a_int_dtype)
63
64
  maskbits = bits - self.keepbits
64
65
  mask = (all_set >> maskbits) << maskbits
65
66
  half_quantum1 = (1 << (maskbits - 1)) - 1
Binary file
numcodecs/checksum32.py CHANGED
@@ -1,5 +1,9 @@
1
1
  import struct
2
2
  import zlib
3
+ from collections.abc import Callable
4
+ from contextlib import suppress
5
+ from types import ModuleType
6
+ from typing import TYPE_CHECKING, Literal, Optional
3
7
 
4
8
  import numpy as np
5
9
 
@@ -7,36 +11,89 @@ from .abc import Codec
7
11
  from .compat import ensure_contiguous_ndarray, ndarray_copy
8
12
  from .jenkins import jenkins_lookup3
9
13
 
14
+ _crc32c: Optional[ModuleType] = None
15
+ with suppress(ImportError):
16
+ import crc32c as _crc32c # type: ignore[no-redef]
17
+
18
+ if TYPE_CHECKING: # pragma: no cover
19
+ from typing_extensions import Buffer
20
+
21
+ CHECKSUM_LOCATION = Literal['start', 'end']
22
+
10
23
 
11
24
  class Checksum32(Codec):
12
25
  # override in sub-class
13
- checksum = None
26
+ checksum: Callable[["Buffer", int], int] | None = None
27
+ location: CHECKSUM_LOCATION = 'start'
28
+
29
+ def __init__(self, location: CHECKSUM_LOCATION | None = None):
30
+ if location is not None:
31
+ self.location = location
32
+ if self.location not in ['start', 'end']:
33
+ raise ValueError(f"Invalid checksum location: {self.location}")
14
34
 
15
35
  def encode(self, buf):
16
36
  arr = ensure_contiguous_ndarray(buf).view('u1')
17
37
  checksum = self.checksum(arr) & 0xFFFFFFFF
18
38
  enc = np.empty(arr.nbytes + 4, dtype='u1')
19
- enc[:4].view('<u4')[0] = checksum
20
- ndarray_copy(arr, enc[4:])
39
+ if self.location == 'start':
40
+ checksum_view = enc[:4]
41
+ payload_view = enc[4:]
42
+ else:
43
+ checksum_view = enc[-4:]
44
+ payload_view = enc[:-4]
45
+ checksum_view.view('<u4')[0] = checksum
46
+ ndarray_copy(arr, payload_view)
21
47
  return enc
22
48
 
23
49
  def decode(self, buf, out=None):
50
+ if len(buf) < 4:
51
+ raise ValueError("Input buffer is too short to contain a 32-bit checksum.")
52
+ if out is not None:
53
+ ensure_contiguous_ndarray(out) # check that out is a valid ndarray
54
+
24
55
  arr = ensure_contiguous_ndarray(buf).view('u1')
25
- expect = arr[:4].view('<u4')[0]
26
- checksum = self.checksum(arr[4:]) & 0xFFFFFFFF
56
+ if self.location == 'start':
57
+ checksum_view = arr[:4]
58
+ payload_view = arr[4:]
59
+ else:
60
+ checksum_view = arr[-4:]
61
+ payload_view = arr[:-4]
62
+ expect = checksum_view.view('<u4')[0]
63
+ checksum = self.checksum(payload_view) & 0xFFFFFFFF
27
64
  if expect != checksum:
28
- raise RuntimeError('checksum failed')
29
- return ndarray_copy(arr[4:], out)
65
+ raise RuntimeError(
66
+ f"Stored and computed {self.codec_id} checksum do not match. Stored: {expect}. Computed: {checksum}."
67
+ )
68
+ return ndarray_copy(payload_view, out)
30
69
 
31
70
 
32
71
  class CRC32(Checksum32):
72
+ """Codec add a crc32 checksum to the buffer.
73
+
74
+ Parameters
75
+ ----------
76
+ location : 'start' or 'end'
77
+ Where to place the checksum in the buffer.
78
+ """
79
+
33
80
  codec_id = 'crc32'
34
81
  checksum = zlib.crc32
82
+ location = 'start'
35
83
 
36
84
 
37
85
  class Adler32(Checksum32):
86
+ """Codec add a adler32 checksum to the buffer.
87
+
88
+ Parameters
89
+ ----------
90
+ location : 'start' or 'end'
91
+ Where to place the checksum in the buffer.
92
+ """
93
+
38
94
  codec_id = 'adler32'
39
95
  checksum = zlib.adler32
96
+ location = 'start'
40
97
 
41
98
 
42
99
  class JenkinsLookup3(Checksum32):
@@ -50,9 +107,12 @@ class JenkinsLookup3(Checksum32):
50
107
  the data portion and compared with the four-byte checksum, raising
51
108
  RuntimeError if inconsistent.
52
109
 
53
- Attributes:
54
- initval: initial seed passed to the hash algorithm, default: 0
55
- prefix: bytes prepended to the buffer before evaluating the hash, default: None
110
+ Parameters
111
+ ----------
112
+ initval : int
113
+ initial seed passed to the hash algorithm, default: 0
114
+ prefix : int
115
+ bytes prepended to the buffer before evaluating the hash, default: None
56
116
  """
57
117
 
58
118
  checksum = jenkins_lookup3
@@ -92,3 +152,19 @@ class JenkinsLookup3(Checksum32):
92
152
  out.view("uint8")[:] = b[:-4]
93
153
  return out
94
154
  return memoryview(b[:-4])
155
+
156
+
157
+ if _crc32c:
158
+
159
+ class CRC32C(Checksum32):
160
+ """Codec add a crc32c checksum to the buffer.
161
+
162
+ Parameters
163
+ ----------
164
+ location : 'start' or 'end'
165
+ Where to place the checksum in the buffer.
166
+ """
167
+
168
+ codec_id = 'crc32c'
169
+ checksum = _crc32c.crc32c # type: ignore[union-attr]
170
+ location = 'end'
numcodecs/compat.py CHANGED
@@ -1,7 +1,5 @@
1
- # ruff: noqa: F401
2
1
  import array
3
2
  import codecs
4
- import functools
5
3
 
6
4
  import numpy as np
7
5
 
@@ -102,7 +100,7 @@ def ensure_contiguous_ndarray_like(buf, max_buffer_size=None, flatten=True) -> N
102
100
 
103
101
  # check for datetime or timedelta ndarray, the buffer interface doesn't support those
104
102
  if arr.dtype.kind in "Mm":
105
- arr = arr.view(np.int64)
103
+ arr = arr.view(np.int64) # type: ignore[arg-type]
106
104
 
107
105
  # check memory is contiguous, if so flatten
108
106
  if arr.flags.c_contiguous or arr.flags.f_contiguous:
@@ -119,7 +117,7 @@ def ensure_contiguous_ndarray_like(buf, max_buffer_size=None, flatten=True) -> N
119
117
  return arr
120
118
 
121
119
 
122
- def ensure_contiguous_ndarray(buf, max_buffer_size=None, flatten=True) -> np.array:
120
+ def ensure_contiguous_ndarray(buf, max_buffer_size=None, flatten=True) -> np.ndarray:
123
121
  """Convenience function to coerce `buf` to a numpy array, if it is not already a
124
122
  numpy array. Also ensures that the returned value exports fully contiguous memory,
125
123
  and supports the new-style buffer interface. If the optional max_buffer_size is
Binary file
numcodecs/delta.py CHANGED
@@ -63,7 +63,11 @@ class Delta(Codec):
63
63
  enc[0] = arr[0]
64
64
 
65
65
  # compute differences
66
- enc[1:] = np.diff(arr)
66
+ # using np.subtract for in-place operations
67
+ if arr.dtype == bool:
68
+ np.not_equal(arr[1:], arr[:-1], out=enc[1:])
69
+ else:
70
+ np.subtract(arr[1:], arr[:-1], out=enc[1:])
67
71
 
68
72
  return enc
69
73
 
Binary file
Binary file
Binary file
numcodecs/lzma.py CHANGED
@@ -1,9 +1,12 @@
1
- _lzma = None
1
+ from types import ModuleType
2
+ from typing import Optional
3
+
4
+ _lzma: Optional[ModuleType] = None
2
5
  try:
3
6
  import lzma as _lzma
4
7
  except ImportError: # pragma: no cover
5
8
  try:
6
- from backports import lzma as _lzma
9
+ from backports import lzma as _lzma # type: ignore[no-redef]
7
10
  except ImportError:
8
11
  pass
9
12
 
numcodecs/ndarray_like.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from typing import Any, ClassVar, Optional, Protocol, runtime_checkable
2
2
 
3
3
 
4
- class _CachedProtocolMeta(Protocol.__class__):
4
+ class _CachedProtocolMeta(Protocol.__class__): # type: ignore[name-defined]
5
5
  """Custom implementation of @runtime_checkable
6
6
 
7
7
  The native implementation of @runtime_checkable is slow,
numcodecs/packbits.py CHANGED
@@ -29,9 +29,6 @@ class PackBits(Codec):
29
29
 
30
30
  codec_id = 'packbits'
31
31
 
32
- def __init__(self):
33
- pass
34
-
35
32
  def encode(self, buf):
36
33
  # normalise input
37
34
  arr = ensure_ndarray(buf).view(bool)
numcodecs/pcodec.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from typing import Literal, Optional
2
2
 
3
- import numcodecs
4
- import numcodecs.abc
3
+ from numcodecs.abc import Codec
5
4
  from numcodecs.compat import ensure_contiguous_ndarray
6
5
 
7
6
  try:
@@ -13,7 +12,7 @@ except ImportError: # pragma: no cover
13
12
  DEFAULT_MAX_PAGE_N = 262144
14
13
 
15
14
 
16
- class PCodec(numcodecs.abc.Codec):
15
+ class PCodec(Codec):
17
16
  """
18
17
  PCodec (or pco, pronounced "pico") losslessly compresses and decompresses
19
18
  numerical sequences with high compression ratio and fast speed.
numcodecs/registry.py CHANGED
@@ -2,11 +2,13 @@
2
2
  applications to dynamically register and look-up codec classes."""
3
3
 
4
4
  import logging
5
- from importlib.metadata import entry_points
5
+ from importlib.metadata import EntryPoints, entry_points
6
+
7
+ from numcodecs.abc import Codec
6
8
 
7
9
  logger = logging.getLogger("numcodecs")
8
- codec_registry = {}
9
- entries = {}
10
+ codec_registry: dict[str, Codec] = {}
11
+ entries: dict[str, "EntryPoints"] = {}
10
12
 
11
13
 
12
14
  def run_entrypoints():
@@ -42,11 +44,10 @@ def get_codec(config):
42
44
  config = dict(config)
43
45
  codec_id = config.pop('id', None)
44
46
  cls = codec_registry.get(codec_id)
45
- if cls is None:
46
- if codec_id in entries:
47
- logger.debug("Auto loading codec '%s' from entrypoint", codec_id)
48
- cls = entries[codec_id].load()
49
- register_codec(cls, codec_id=codec_id)
47
+ if cls is None and codec_id in entries:
48
+ logger.debug("Auto loading codec '%s' from entrypoint", codec_id)
49
+ cls = entries[codec_id].load()
50
+ register_codec(cls, codec_id=codec_id)
50
51
  if cls:
51
52
  return cls.from_config(config)
52
53
  raise ValueError(f'codec not available: {codec_id!r}')
@@ -24,21 +24,21 @@ def test_round_zero_to_zero(dtype):
24
24
  # Don't understand Milan's original test:
25
25
  # How is it possible to have negative keepbits?
26
26
  # for k in range(-5, 50):
27
- for k in range(0, max_bits[dtype]):
27
+ for k in range(max_bits[dtype]):
28
28
  ar = round(a, k)
29
29
  np.testing.assert_equal(a, ar)
30
30
 
31
31
 
32
32
  def test_round_one_to_one(dtype):
33
33
  a = np.ones((3, 2), dtype=dtype)
34
- for k in range(0, max_bits[dtype]):
34
+ for k in range(max_bits[dtype]):
35
35
  ar = round(a, k)
36
36
  np.testing.assert_equal(a, ar)
37
37
 
38
38
 
39
39
  def test_round_minus_one_to_minus_one(dtype):
40
40
  a = -np.ones((3, 2), dtype=dtype)
41
- for k in range(0, max_bits[dtype]):
41
+ for k in range(max_bits[dtype]):
42
42
  ar = round(a, k)
43
43
  np.testing.assert_equal(a, ar)
44
44
 
@@ -133,7 +133,7 @@ def test_compress_blocksize_default(use_threads):
133
133
  assert blocksize > 0
134
134
 
135
135
 
136
- @pytest.mark.parametrize('bs', (2**7, 2**8))
136
+ @pytest.mark.parametrize('bs', [2**7, 2**8])
137
137
  def test_compress_blocksize(use_threads, bs):
138
138
  arr = np.arange(1000, dtype='i4')
139
139
 
@@ -225,7 +225,7 @@ def _decode_worker(enc):
225
225
  return data
226
226
 
227
227
 
228
- @pytest.mark.parametrize('pool', (Pool, ThreadPool))
228
+ @pytest.mark.parametrize('pool', [Pool, ThreadPool])
229
229
  def test_multiprocessing(use_threads, pool):
230
230
  data = np.arange(1000000)
231
231
  enc = _encode_worker(data)
@@ -1,4 +1,5 @@
1
1
  import itertools
2
+ from contextlib import suppress
2
3
 
3
4
  import numpy as np
4
5
  import pytest
@@ -8,10 +9,17 @@ from numcodecs.tests.common import (
8
9
  check_backwards_compatibility,
9
10
  check_config,
10
11
  check_encode_decode,
12
+ check_err_decode_object_buffer,
11
13
  check_err_encode_object_buffer,
12
14
  check_repr,
13
15
  )
14
16
 
17
+ has_crc32c = False
18
+ with suppress(ImportError):
19
+ from numcodecs.checksum32 import CRC32C
20
+
21
+ has_crc32c = True
22
+
15
23
  # mix of dtypes: integer, float, bool, string
16
24
  # mix of shapes: 1D, 2D, 3D
17
25
  # mix of orders: C, F
@@ -21,38 +29,126 @@ arrays = [
21
29
  np.random.normal(loc=1000, scale=1, size=(100, 10)),
22
30
  np.random.randint(0, 2, size=1000, dtype=bool).reshape(100, 10, order='F'),
23
31
  np.random.choice([b'a', b'bb', b'ccc'], size=1000).reshape(10, 10, 10),
32
+ np.random.randint(0, 2**60, size=1000, dtype='u8').view('M8[ns]'),
33
+ np.random.randint(0, 2**60, size=1000, dtype='u8').view('m8[ns]'),
34
+ np.random.randint(0, 2**25, size=1000, dtype='u8').view('M8[m]'),
35
+ np.random.randint(0, 2**25, size=1000, dtype='u8').view('m8[m]'),
36
+ np.random.randint(-(2**63), -(2**63) + 20, size=1000, dtype='i8').view('M8[ns]'),
37
+ np.random.randint(-(2**63), -(2**63) + 20, size=1000, dtype='i8').view('m8[ns]'),
38
+ np.random.randint(-(2**63), -(2**63) + 20, size=1000, dtype='i8').view('M8[m]'),
39
+ np.random.randint(-(2**63), -(2**63) + 20, size=1000, dtype='i8').view('m8[m]'),
24
40
  ]
25
41
 
26
- codecs = [CRC32(), Adler32()]
42
+ codecs = [
43
+ CRC32(),
44
+ CRC32(location="end"),
45
+ Adler32(),
46
+ Adler32(location="end"),
47
+ ]
48
+ if has_crc32c:
49
+ codecs.extend(
50
+ [
51
+ CRC32C(location="start"),
52
+ CRC32C(),
53
+ ]
54
+ )
55
+
56
+
57
+ @pytest.mark.parametrize(("codec", "arr"), itertools.product(codecs, arrays))
58
+ def test_encode_decode(codec, arr):
59
+ check_encode_decode(arr, codec)
60
+
61
+
62
+ @pytest.mark.parametrize(("codec", "arr"), itertools.product(codecs, arrays))
63
+ def test_errors(codec, arr):
64
+ enc = codec.encode(arr)
65
+ with pytest.raises(RuntimeError):
66
+ codec.decode(enc[:-1])
67
+
68
+
69
+ @pytest.mark.parametrize("codec", codecs)
70
+ def test_config(codec):
71
+ check_config(codec)
72
+
27
73
 
74
+ @pytest.mark.parametrize("codec", codecs)
75
+ def test_err_input_too_small(codec):
76
+ buf = b'000' # 3 bytes are too little for a 32-bit checksum
77
+ with pytest.raises(ValueError):
78
+ codec.decode(buf)
28
79
 
29
- def test_encode_decode():
30
- for codec, arr in itertools.product(codecs, arrays):
31
- check_encode_decode(arr, codec)
32
80
 
81
+ @pytest.mark.parametrize("codec", codecs)
82
+ def test_err_encode_non_contiguous(codec):
83
+ # non-contiguous memory
84
+ arr = np.arange(1000, dtype='i4')[::2]
85
+ with pytest.raises(ValueError):
86
+ codec.encode(arr)
33
87
 
34
- def test_errors():
35
- for codec, arr in itertools.product(codecs, arrays):
36
- enc = codec.encode(arr)
37
- with pytest.raises(RuntimeError):
38
- codec.decode(enc[:-1])
39
88
 
89
+ @pytest.mark.parametrize("codec", codecs)
90
+ def test_err_encode_list(codec):
91
+ data = ['foo', 'bar', 'baz']
92
+ with pytest.raises(TypeError):
93
+ codec.encode(data)
40
94
 
41
- def test_config():
42
- for codec in codecs:
43
- check_config(codec)
95
+
96
+ def test_err_location():
97
+ with pytest.raises(ValueError):
98
+ CRC32(location="foo")
99
+ with pytest.raises(ValueError):
100
+ Adler32(location="foo")
101
+ if has_crc32c:
102
+ with pytest.raises(ValueError):
103
+ CRC32C(location="foo")
44
104
 
45
105
 
46
106
  def test_repr():
47
- check_repr("CRC32()")
48
- check_repr("Adler32()")
107
+ check_repr("CRC32(location='start')")
108
+ check_repr("CRC32(location='end')")
109
+ check_repr("Adler32(location='start')")
110
+ check_repr("Adler32(location='end')")
111
+ if has_crc32c:
112
+ check_repr("CRC32C(location='start')")
113
+ check_repr("CRC32C(location='end')")
49
114
 
50
115
 
51
116
  def test_backwards_compatibility():
52
117
  check_backwards_compatibility(CRC32.codec_id, arrays, [CRC32()])
53
118
  check_backwards_compatibility(Adler32.codec_id, arrays, [Adler32()])
119
+ if has_crc32c:
120
+ check_backwards_compatibility(CRC32C.codec_id, arrays, [CRC32C()])
121
+
122
+
123
+ @pytest.mark.parametrize("codec", codecs)
124
+ def test_err_encode_object_buffer(codec):
125
+ check_err_encode_object_buffer(codec)
126
+
127
+
128
+ @pytest.mark.parametrize("codec", codecs)
129
+ def test_err_decode_object_buffer(codec):
130
+ check_err_decode_object_buffer(codec)
131
+
132
+
133
+ @pytest.mark.parametrize("codec", codecs)
134
+ def test_err_out_too_small(codec):
135
+ arr = np.arange(10, dtype='i4')
136
+ out = np.empty_like(arr)[:-1]
137
+ with pytest.raises(ValueError):
138
+ codec.decode(codec.encode(arr), out)
139
+
140
+
141
+ @pytest.mark.skipif(not has_crc32c, reason="Needs `crc32c` installed")
142
+ def test_crc32c_checksum():
143
+ arr = np.arange(0, 64, dtype="uint8")
144
+ buf = CRC32C(location="end").encode(arr)
145
+ assert np.frombuffer(buf, dtype="<u4", offset=(len(buf) - 4))[0] == np.uint32(4218238699)
54
146
 
55
147
 
56
- def test_err_encode_object_buffer():
57
- check_err_encode_object_buffer(CRC32())
58
- check_err_encode_object_buffer(Adler32())
148
+ @pytest.mark.parametrize("codec", codecs)
149
+ def test_err_checksum(codec):
150
+ arr = np.arange(0, 64, dtype="uint8")
151
+ buf = bytearray(codec.encode(arr))
152
+ buf[-1] = 0 # corrupt the checksum
153
+ with pytest.raises(RuntimeError):
154
+ codec.decode(buf)
@@ -64,6 +64,9 @@ def test_ensure_bytes_invalid_inputs():
64
64
  ensure_bytes(e)
65
65
 
66
66
 
67
+ @pytest.mark.filterwarnings(
68
+ "ignore:The 'u' type code is deprecated and will be removed in Python 3.16"
69
+ )
67
70
  def test_ensure_contiguous_ndarray_invalid_inputs():
68
71
  # object array not allowed
69
72
  a = np.array(['Xin chào thế giới'], dtype=object)
@@ -14,6 +14,7 @@ from numcodecs.tests.common import (
14
14
  # mix of shapes: 1D, 2D, 3D
15
15
  # mix of orders: C, F
16
16
  arrays = [
17
+ np.random.randint(0, 1, size=110, dtype='?').reshape(10, 11),
17
18
  np.arange(1000, dtype='<i4'),
18
19
  np.linspace(1000, 1001, 1000, dtype='<f4').reshape(100, 10),
19
20
  np.random.normal(loc=1000, scale=1, size=(10, 10, 10)).astype('<f8'),
@@ -8,7 +8,7 @@ import numcodecs.registry
8
8
  here = os.path.abspath(os.path.dirname(__file__))
9
9
 
10
10
 
11
- @pytest.fixture()
11
+ @pytest.fixture
12
12
  def set_path():
13
13
  sys.path.append(here)
14
14
  numcodecs.registry.run_entrypoints()
@@ -1,4 +1,4 @@
1
- import importlib
1
+ import importlib.util
2
2
  import os.path
3
3
  import sys
4
4
  from multiprocessing import Process
@@ -7,7 +7,8 @@ import pytest
7
7
 
8
8
  import numcodecs.registry
9
9
 
10
- if not importlib.util.find_spec("importlib_metadata").loader: # pragma: no cover
10
+ importlib_spec = importlib.util.find_spec("importlib_metadata")
11
+ if importlib_spec is None or importlib_spec.loader is None: # pragma: no cover
11
12
  pytest.skip(
12
13
  "This test module requires importlib_metadata to be installed",
13
14
  allow_module_level=True,
@@ -36,12 +36,20 @@ def test_encode_decode():
36
36
  check_encode_decode(arr, codec, precision=precision)
37
37
 
38
38
 
39
- def test_encode():
39
+ @pytest.mark.parametrize(
40
+ ("offset", "scale", "expected"),
41
+ [
42
+ (1000, 10, [0, 6, 11, 17, 22, 28, 33, 39, 44, 50]),
43
+ (1002.5, 10, [-25, -19, -14, -8, -3, 3, 8, 14, 19, 25]),
44
+ (1000, 0.5, [0, 0, 1, 1, 1, 1, 2, 2, 2, 2]),
45
+ ],
46
+ )
47
+ def test_encode(offset: float, scale: float, expected: list[int]):
40
48
  dtype = '<f8'
41
- astype = '|u1'
42
- codec = FixedScaleOffset(scale=10, offset=1000, dtype=dtype, astype=astype)
43
- arr = np.linspace(1000, 1001, 10, dtype=dtype)
44
- expect = np.array([0, 1, 2, 3, 4, 6, 7, 8, 9, 10], dtype=astype)
49
+ astype = np.int16
50
+ codec = FixedScaleOffset(scale=scale, offset=offset, dtype=dtype, astype=astype)
51
+ arr = np.linspace(1000, 1005, 10, dtype=dtype)
52
+ expect = np.array(expected, dtype=astype)
45
53
  actual = codec.encode(arr)
46
54
  assert_array_equal(expect, actual)
47
55
  assert np.dtype(astype) == actual.dtype
@@ -59,7 +59,7 @@ def test_backwards_compatibility():
59
59
 
60
60
 
61
61
  @pytest.mark.parametrize(
62
- "input_data, dtype",
62
+ ('input_data', 'dtype'),
63
63
  [
64
64
  ([0, 1], None),
65
65
  ([[0, 1], [2, 3]], None),