3
3
import asyncio
4
4
from collections .abc import Mapping
5
5
from dataclasses import dataclass , replace
6
+ from enum import Enum
6
7
from functools import cached_property
7
8
from typing import (
8
9
TYPE_CHECKING ,
34
35
from zarr .core .array_spec import ArraySpec
35
36
from zarr .core .buffer import Buffer
36
37
37
- BloscShuffle = Literal ["noshuffle" , "shuffle" , "bitshuffle" ]
38
+
39
+ class BloscShuffle (Enum ):
40
+ """
41
+ Enum for shuffle filter used by blosc.
42
+ """
43
+
44
+ noshuffle = "noshuffle"
45
+ shuffle = "shuffle"
46
+ bitshuffle = "bitshuffle"
47
+
48
+ @classmethod
49
+ def from_int (cls , num : int ) -> BloscShuffle :
50
+ blosc_shuffle_int_to_str = {
51
+ 0 : "noshuffle" ,
52
+ 1 : "shuffle" ,
53
+ 2 : "bitshuffle" ,
54
+ }
55
+ if num not in blosc_shuffle_int_to_str :
56
+ raise ValueError (f"Value must be between 0 and 2. Got { num } ." )
57
+ return BloscShuffle [blosc_shuffle_int_to_str [num ]]
58
+
59
+
60
+ class BloscCname (Enum ):
61
+ """
62
+ Enum for compression library used by blosc.
63
+ """
64
+
65
+ lz4 = "lz4"
66
+ lz4hc = "lz4hc"
67
+ blosclz = "blosclz"
68
+ zstd = "zstd"
69
+ snappy = "snappy"
70
+ zlib = "zlib"
71
+
72
+
73
+ # TODO: Rename this when we retire the enums
74
+ BloscShuffle_lit = Literal ["noshuffle" , "shuffle" , "bitshuffle" ]
75
+ """The names of the shuffle options used by the blosc codec."""
38
76
BLOSC_SHUFFLE : Final = ("noshuffle" , "shuffle" , "bitshuffle" )
39
77
40
- BloscCname = Literal ["lz4" , "lz4hc" , "blosclz" , "zstd" , "snappy" , "zlib" ]
78
+ # TODO: rename this when we retire the enums
79
+ BloscCname_lit = Literal ["lz4" , "lz4hc" , "blosclz" , "zstd" , "snappy" , "zlib" ]
80
+ """The names of the compression libraries used by the blosc codec"""
41
81
BLOSC_CNAME : Final = ("lz4" , "lz4hc" , "blosclz" , "zstd" , "snappy" , "zlib" )
42
82
43
83
44
84
class BloscConfigV2 (TypedDict ):
45
- cname : BloscCname
85
+ cname : BloscCname_lit
46
86
clevel : int
47
87
shuffle : int
48
88
blocksize : int
49
89
typesize : NotRequired [int ]
50
90
51
91
52
92
class BloscConfigV3 (TypedDict ):
53
- cname : BloscCname
93
+ cname : BloscCname_lit
54
94
clevel : int
55
- shuffle : BloscShuffle
95
+ shuffle : BloscShuffle_lit
56
96
blocksize : int
57
97
typesize : int
58
98
@@ -91,9 +131,14 @@ def check_json_v3(data: object) -> TypeGuard[BloscJSON_V3]:
91
131
92
132
93
133
def parse_cname (value : object ) -> BloscCname :
94
- if value not in BLOSC_CNAME :
95
- raise ValueError (f"Value must be one of { BLOSC_CNAME } . Got { value } instead." )
96
- return value # type: ignore[return-value]
134
+ if isinstance (value , BloscCname ):
135
+ return value
136
+ if isinstance (value , str ):
137
+ if value not in BLOSC_CNAME :
138
+ raise ValueError (f"Value must be one of { BLOSC_CNAME } . Got { value } instead." )
139
+ return BloscCname [value ]
140
+ msg = f"Value must be an instance of `BloscCname` or a string in { BLOSC_CNAME } . Got { value } instead."
141
+ raise TypeError (msg )
97
142
98
143
99
144
# See https://zarr.readthedocs.io/en/stable/user-guide/performance.html#configuring-blosc
@@ -125,8 +170,10 @@ def parse_blocksize(data: JSON) -> int:
125
170
126
171
127
172
def parse_shuffle (data : object ) -> BloscShuffle :
173
+ if isinstance (data , BloscShuffle ):
174
+ return data
128
175
if data in BLOSC_SHUFFLE :
129
- return data # type: ignore[return-value ]
176
+ return BloscShuffle [ data ] # type: ignore[misc ]
130
177
raise TypeError (f"Value must be one of { BLOSC_SHUFFLE } . Got { data } instead." )
131
178
132
179
@@ -144,9 +191,9 @@ def __init__(
144
191
self ,
145
192
* ,
146
193
typesize : int | None = None ,
147
- cname : BloscCname = "zstd" ,
194
+ cname : BloscCname_lit | BloscCname = "zstd" ,
148
195
clevel : int = 5 ,
149
- shuffle : BloscShuffle | None = None ,
196
+ shuffle : BloscShuffle_lit | BloscShuffle | None = None ,
150
197
blocksize : int = 0 ,
151
198
) -> None :
152
199
typesize_parsed = parse_typesize (typesize ) if typesize is not None else None
@@ -174,8 +221,8 @@ def to_dict(self) -> dict[str, JSON]:
174
221
"name" : "blosc" ,
175
222
"configuration" : {
176
223
"clevel" : self .clevel ,
177
- "cname" : self .cname ,
178
- "shuffle" : self .shuffle ,
224
+ "cname" : self .cname . value ,
225
+ "shuffle" : self .shuffle . value ,
179
226
"typesize" : self .typesize ,
180
227
"blocksize" : self .blocksize ,
181
228
},
@@ -226,8 +273,8 @@ def to_json(self, zarr_format: ZarrFormat) -> BloscJSON_V2 | BloscJSON_V3:
226
273
return {
227
274
"id" : "blosc" ,
228
275
"clevel" : self .clevel ,
229
- "cname" : self .cname ,
230
- "shuffle" : BLOSC_SHUFFLE .index (self .shuffle ),
276
+ "cname" : self .cname . value ,
277
+ "shuffle" : BLOSC_SHUFFLE .index (self .shuffle . value ),
231
278
"blocksize" : self .blocksize ,
232
279
}
233
280
elif zarr_format == 3 :
@@ -244,7 +291,10 @@ def evolve_from_array_spec(self, array_spec: ArraySpec) -> Self:
244
291
if new_codec .typesize is None :
245
292
new_codec = replace (new_codec , typesize = item_size )
246
293
if new_codec .shuffle is None :
247
- new_codec = replace (new_codec , shuffle = "bitshuffle" if item_size == 1 else "shuffle" )
294
+ new_codec = replace (
295
+ new_codec ,
296
+ shuffle = BloscShuffle .bitshuffle if item_size == 1 else BloscShuffle .shuffle ,
297
+ )
248
298
249
299
return new_codec
250
300
@@ -255,9 +305,9 @@ def _blosc_codec(self) -> Blosc:
255
305
if self .typesize is None :
256
306
raise ValueError ("`typesize` needs to be set for decoding and encoding." )
257
307
config_dict = {
258
- "cname" : self .cname ,
308
+ "cname" : self .cname . value ,
259
309
"clevel" : self .clevel ,
260
- "shuffle" : BLOSC_SHUFFLE .index (self .shuffle ),
310
+ "shuffle" : BLOSC_SHUFFLE .index (self .shuffle . value ),
261
311
"blocksize" : self .blocksize ,
262
312
}
263
313
# See https://github.com/zarr-developers/numcodecs/pull/713
0 commit comments