Skip to content

Commit 145f57c

Browse files
jakirkhamdstansby
andauthored
Cleanup crc32c soft dependency (#637)
* Cleanup `crc32c` soft dependency * Add `crc32c` cleanup release note --------- Co-authored-by: David Stansby <[email protected]>
1 parent ad1ad67 commit 145f57c

File tree

5 files changed

+60
-39
lines changed

5 files changed

+60
-39
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ repos:
3131
hooks:
3232
- id: mypy
3333
args: [--config-file, pyproject.toml]
34-
additional_dependencies: [numpy, pytest, zfpy, 'zarr>=3.0.0b2']
34+
additional_dependencies: [numpy, pytest, crc32c, zfpy, 'zarr>=3.0.0b2']

docs/release.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ Release notes
1111
Unreleased
1212
----------
1313

14+
Fixes
15+
~~~~~
16+
* Cleanup ``crc32c`` soft dependency.
17+
By :user:`John Kirkham <jakirkham>`, :issue:`637`
18+
1419

1520
.. _release_0.14.0:
1621

numcodecs/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,17 @@
117117

118118
register_codec(MsgPack)
119119

120-
from numcodecs.checksum32 import CRC32, CRC32C, Adler32, JenkinsLookup3
120+
from numcodecs.checksum32 import CRC32, Adler32, JenkinsLookup3
121121

122122
register_codec(CRC32)
123-
register_codec(CRC32C)
124123
register_codec(Adler32)
125124
register_codec(JenkinsLookup3)
126125

126+
with suppress(ImportError):
127+
from numcodecs.checksum32 import CRC32C
128+
129+
register_codec(CRC32C)
130+
127131
from numcodecs.json import JSON
128132

129133
register_codec(JSON)

numcodecs/checksum32.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import struct
22
import zlib
33
from collections.abc import Callable
4-
from typing import TYPE_CHECKING, Literal
4+
from contextlib import suppress
5+
from types import ModuleType
6+
from typing import TYPE_CHECKING, Literal, Optional
57

68
import numpy as np
79

810
from .abc import Codec
911
from .compat import ensure_contiguous_ndarray, ndarray_copy
1012
from .jenkins import jenkins_lookup3
1113

14+
_crc32c: Optional[ModuleType] = None
15+
with suppress(ImportError):
16+
import crc32c as _crc32c # type: ignore[no-redef]
17+
1218
if TYPE_CHECKING: # pragma: no cover
1319
from typing_extensions import Buffer
1420

@@ -76,28 +82,6 @@ class CRC32(Checksum32):
7682
location = 'start'
7783

7884

79-
class CRC32C(Checksum32):
80-
"""Codec add a crc32c checksum to the buffer.
81-
82-
Parameters
83-
----------
84-
location : 'start' or 'end'
85-
Where to place the checksum in the buffer.
86-
"""
87-
88-
codec_id = 'crc32c'
89-
90-
def checksum(self, buf):
91-
try:
92-
from crc32c import crc32c as crc32c_
93-
94-
return crc32c_(buf)
95-
except ImportError: # pragma: no cover
96-
raise ImportError("crc32c must be installed to use the CRC32C checksum codec.")
97-
98-
location = 'end'
99-
100-
10185
class Adler32(Checksum32):
10286
"""Codec add a adler32 checksum to the buffer.
10387
@@ -168,3 +152,19 @@ def decode(self, buf, out=None):
168152
out.view("uint8")[:] = b[:-4]
169153
return out
170154
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/tests/test_checksum32.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import itertools
2+
from contextlib import suppress
23

34
import numpy as np
45
import pytest
56

6-
try:
7-
from numcodecs.checksum32 import CRC32, CRC32C, Adler32
8-
except ImportError: # pragma: no cover
9-
pytest.skip("numcodecs.checksum32 not available", allow_module_level=True)
10-
7+
from numcodecs.checksum32 import CRC32, Adler32
118
from numcodecs.tests.common import (
129
check_backwards_compatibility,
1310
check_config,
@@ -17,6 +14,12 @@
1714
check_repr,
1815
)
1916

17+
has_crc32c = False
18+
with suppress(ImportError):
19+
from numcodecs.checksum32 import CRC32C
20+
21+
has_crc32c = True
22+
2023
# mix of dtypes: integer, float, bool, string
2124
# mix of shapes: 1D, 2D, 3D
2225
# mix of orders: C, F
@@ -39,11 +42,16 @@
3942
codecs = [
4043
CRC32(),
4144
CRC32(location="end"),
42-
CRC32C(location="start"),
43-
CRC32C(),
4445
Adler32(),
4546
Adler32(location="end"),
4647
]
48+
if has_crc32c:
49+
codecs.extend(
50+
[
51+
CRC32C(location="start"),
52+
CRC32C(),
53+
]
54+
)
4755

4856

4957
@pytest.mark.parametrize(("codec", "arr"), itertools.product(codecs, arrays))
@@ -88,25 +96,28 @@ def test_err_encode_list(codec):
8896
def test_err_location():
8997
with pytest.raises(ValueError):
9098
CRC32(location="foo")
91-
with pytest.raises(ValueError):
92-
CRC32C(location="foo")
9399
with pytest.raises(ValueError):
94100
Adler32(location="foo")
101+
if has_crc32c:
102+
with pytest.raises(ValueError):
103+
CRC32C(location="foo")
95104

96105

97106
def test_repr():
98107
check_repr("CRC32(location='start')")
99-
check_repr("CRC32C(location='start')")
100-
check_repr("Adler32(location='start')")
101108
check_repr("CRC32(location='end')")
102-
check_repr("CRC32C(location='end')")
109+
check_repr("Adler32(location='start')")
103110
check_repr("Adler32(location='end')")
111+
if has_crc32c:
112+
check_repr("CRC32C(location='start')")
113+
check_repr("CRC32C(location='end')")
104114

105115

106116
def test_backwards_compatibility():
107117
check_backwards_compatibility(CRC32.codec_id, arrays, [CRC32()])
108118
check_backwards_compatibility(Adler32.codec_id, arrays, [Adler32()])
109-
check_backwards_compatibility(CRC32C.codec_id, arrays, [CRC32C()])
119+
if has_crc32c:
120+
check_backwards_compatibility(CRC32C.codec_id, arrays, [CRC32C()])
110121

111122

112123
@pytest.mark.parametrize("codec", codecs)
@@ -127,6 +138,7 @@ def test_err_out_too_small(codec):
127138
codec.decode(codec.encode(arr), out)
128139

129140

141+
@pytest.mark.skipif(not has_crc32c, reason="Needs `crc32c` installed")
130142
def test_crc32c_checksum():
131143
arr = np.arange(0, 64, dtype="uint8")
132144
buf = CRC32C(location="end").encode(arr)

0 commit comments

Comments
 (0)