Skip to content

Commit 9c09932

Browse files
committed
per-codec tests for new codecs
1 parent c7e4676 commit 9c09932

31 files changed

+640
-202
lines changed

tests/test_codecs/conftest.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING, Any, ClassVar
4+
5+
if TYPE_CHECKING:
6+
from zarr.abc.codec import Codec
7+
from zarr.core.common import CodecJSON_V2, CodecJSON_V3
8+
9+
10+
class BaseTestCodec:
11+
"""
12+
A base class for testing codec classes.
13+
14+
Attributes
15+
----------
16+
17+
test_cls : type[Codec]
18+
The codec class being tested
19+
valid_json_v2 : ClassVar[tuple[CodecJSON_V2, ...]]
20+
A tuple of valid JSON representations for Zarr format version 2.
21+
valid_json_v2 : ClassVar[tuple[CodecJSON_V2, ...]]
22+
A tuple of valid JSON representations for Zarr format version 2.
23+
"""
24+
25+
test_cls: type[Codec]
26+
valid_json_v2: ClassVar[tuple[CodecJSON_V2, ...]]
27+
valid_json_v3: ClassVar[tuple[CodecJSON_V3, ...]]
28+
29+
def test_from_json_roundtrip_v2(self, valid_json_v2: CodecJSON_V2) -> None:
30+
codec = self.test_cls.from_json(valid_json_v2)
31+
assert codec.to_json(zarr_format=2) == valid_json_v2
32+
33+
def test_from_json_roundtrip_v3(self, valid_json_v3: CodecJSON_V3) -> None:
34+
codec = self.test_cls.from_json(valid_json_v3)
35+
assert codec.to_json(zarr_format=3) == valid_json_v3
36+
37+
38+
def pytest_generate_tests(metafunc: Any) -> None:
39+
"""
40+
This is a pytest hook to parametrize class-scoped fixtures.
41+
42+
This hook allows us to define class-scoped fixtures as class attributes and then
43+
generate the parametrize calls for pytest. This allows the fixtures to be
44+
reused across multiple tests within the same class.
45+
46+
For example, if you had a regular pytest class like this:
47+
48+
class TestClass:
49+
@pytest.mark.parametrize("param_a", [1, 2, 3])
50+
def test_method(self, param_a):
51+
...
52+
53+
Child classes inheriting from ``TestClass`` would not be able to override the ``param_a`` fixture
54+
55+
this implementation of ``pytest_generate_tests`` allows you to define class-scoped fixtures as
56+
class attributes, which allows the following to work:
57+
58+
class TestExample:
59+
param_a = [1, 2, 3]
60+
61+
def test_example(self, param_a):
62+
...
63+
64+
# this class will have its test_example method parametrized with the values of TestB.param_a
65+
class TestB(TestExample):
66+
param_a = [1, 2, 100, 10]
67+
68+
"""
69+
# Iterate over all the fixtures defined in the class
70+
# and parametrize them with the values defined in the class
71+
# This allows us to define class-scoped fixtures as class attributes
72+
# and then generate the parametrize calls for pytest
73+
for fixture_name in metafunc.fixturenames:
74+
if hasattr(metafunc.cls, fixture_name):
75+
params = getattr(metafunc.cls, fixture_name)
76+
# Only parametrize if params is a tuple or list, not a function/method
77+
if isinstance(params, (tuple, list)):
78+
metafunc.parametrize(fixture_name, params, scope="class", ids=str)

tests/test_codecs/test_adler32.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import pytest
2+
3+
from tests.test_codecs.conftest import BaseTestCodec
4+
from zarr.codecs import numcodecs as _numcodecs
5+
6+
7+
@pytest.mark.filterwarnings("ignore::zarr.errors.ZarrUserWarning")
8+
class TestAdler32Codec(BaseTestCodec):
9+
test_cls = _numcodecs.Adler32
10+
valid_json_v2 = ({"id": "adler32"},)
11+
valid_json_v3 = ({"name": "adler32", "configuration": {}},)

tests/test_codecs/test_astype.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
from tests.test_codecs.conftest import BaseTestCodec
4+
from zarr.codecs import numcodecs as _numcodecs
5+
6+
7+
@pytest.mark.filterwarnings("ignore::zarr.errors.ZarrUserWarning")
8+
class TestAsTypeCodec(BaseTestCodec):
9+
test_cls = _numcodecs.AsType
10+
valid_json_v2 = ({"id": "astype", "encode_dtype": "<f4", "decode_dtype": "<f4"},)
11+
valid_json_v3 = (
12+
{
13+
"name": "astype",
14+
"configuration": {"encode_dtype": "<f4", "decode_dtype": "<f4"},
15+
},
16+
)

tests/test_codecs/test_bitround.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
from tests.test_codecs.conftest import BaseTestCodec
4+
from zarr.codecs import numcodecs as _numcodecs
5+
6+
7+
@pytest.mark.filterwarnings("ignore::zarr.errors.ZarrUserWarning")
8+
class TestBitRoundCodec(BaseTestCodec):
9+
test_cls = _numcodecs.BitRound
10+
valid_json_v2 = ({"id": "bitround", "keepbits": 8},)
11+
valid_json_v3 = (
12+
{
13+
"name": "bitround",
14+
"configuration": {"keepbits": 8},
15+
},
16+
)

tests/test_codecs/test_blosc.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from packaging.version import Version
77

88
import zarr
9+
from tests.test_codecs.conftest import BaseTestCodec
910
from zarr.abc.store import Store
1011
from zarr.codecs import BloscCodec
1112
from zarr.codecs.blosc import (
@@ -20,6 +21,31 @@
2021
from zarr.storage import StorePath
2122

2223

24+
class TestBloscCodec(BaseTestCodec):
25+
test_cls = BloscCodec
26+
valid_json_v2 = (
27+
{
28+
"id": "blosc",
29+
"cname": "lz4",
30+
"clevel": 5,
31+
"shuffle": 1,
32+
"blocksize": 0,
33+
},
34+
)
35+
valid_json_v3 = (
36+
{
37+
"name": "blosc",
38+
"configuration": {
39+
"cname": "lz4",
40+
"clevel": 5,
41+
"shuffle": "shuffle",
42+
"blocksize": 0,
43+
"typesize": 1,
44+
},
45+
},
46+
)
47+
48+
2349
@pytest.mark.parametrize("shuffle", BLOSC_SHUFFLE)
2450
@pytest.mark.parametrize("cname", BLOSC_CNAME)
2551
@pytest.mark.parametrize("clevel", [1, 2])
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
from tests.test_codecs.conftest import BaseTestCodec
4+
from zarr.codecs import numcodecs as _numcodecs
5+
6+
7+
@pytest.mark.filterwarnings("ignore::zarr.errors.ZarrUserWarning")
8+
class TestBloscNumcodecsCodec(BaseTestCodec):
9+
test_cls = _numcodecs.Blosc
10+
valid_json_v2 = ({"id": "blosc", "clevel": 5, "shuffle": 1, "blocksize": 0, "cname": "lz4"},)
11+
valid_json_v3 = (
12+
{
13+
"name": "blosc",
14+
"configuration": {"clevel": 5, "shuffle": 1, "blocksize": 0, "cname": "lz4"},
15+
},
16+
)

tests/test_codecs/test_bytes.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pytest
55

66
import zarr
7+
from tests.test_codecs.conftest import BaseTestCodec
78
from zarr.abc.store import Store
89
from zarr.codecs import BytesCodec
910
from zarr.storage import StorePath
@@ -14,6 +15,24 @@
1415
from zarr.codecs.bytes import BytesJSON_V2, BytesJSON_V3
1516

1617

18+
class TestBytesCodec(BaseTestCodec):
19+
test_cls = BytesCodec
20+
valid_json_v2 = (
21+
{
22+
"id": "bytes",
23+
"endian": "little",
24+
},
25+
)
26+
valid_json_v3 = (
27+
{
28+
"name": "bytes",
29+
"configuration": {
30+
"endian": "little",
31+
},
32+
},
33+
)
34+
35+
1736
@pytest.mark.parametrize("endian", ["big", "little"])
1837
def test_bytescodec_to_json(endian: Literal["big", "little"]) -> None:
1938
codec = BytesCodec(endian=endian)

tests/test_codecs/test_bz2.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
from tests.test_codecs.conftest import BaseTestCodec
4+
from zarr.codecs import numcodecs as _numcodecs
5+
6+
7+
@pytest.mark.filterwarnings("ignore::zarr.errors.ZarrUserWarning")
8+
class TestBZ2Codec(BaseTestCodec):
9+
test_cls = _numcodecs.BZ2
10+
valid_json_v2 = ({"id": "bz2", "level": 1},)
11+
valid_json_v3 = (
12+
{
13+
"name": "bz2",
14+
"configuration": {"level": 1},
15+
},
16+
)

tests/test_codecs/test_crc32.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import pytest
2+
3+
from tests.test_codecs.conftest import BaseTestCodec
4+
from zarr.codecs import numcodecs as _numcodecs
5+
6+
7+
@pytest.mark.filterwarnings("ignore::zarr.errors.ZarrUserWarning")
8+
class TestCRC32Codec(BaseTestCodec):
9+
test_cls = _numcodecs.CRC32
10+
valid_json_v2 = ({"id": "crc32"},)
11+
valid_json_v3 = ({"name": "crc32", "configuration": {}},)

tests/test_codecs/test_crc32c.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from crc32c import crc32c
1616

1717
import zarr
18+
from tests.test_codecs.conftest import BaseTestCodec
1819
from zarr.abc.store import Store
1920
from zarr.codecs.crc32c_ import (
2021
Crc32cCodec,
@@ -31,6 +32,12 @@
3132
from zarr.storage import StorePath
3233

3334

35+
class TestCrc32cCodec(BaseTestCodec):
36+
test_cls = Crc32cCodec
37+
valid_json_v2 = ({"id": "crc32c"},)
38+
valid_json_v3 = ({"name": "crc32c"},)
39+
40+
3441
class TestCrc32cCodecJSON:
3542
"""Test JSON serialization and deserialization for Crc32c codec."""
3643

0 commit comments

Comments
 (0)