Skip to content

Commit 0d75e00

Browse files
Support Zarr 2 and 3 (again)
1 parent d0e2e67 commit 0d75e00

6 files changed

Lines changed: 68 additions & 22 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ dependencies = [
3232
"numpy",
3333
"humanize",
3434
"tskit>=1.0.0",
35-
"zarr>=3.1",
35+
"zarr>=2.18",
3636
]
3737
dynamic = ["version"]
3838

tests/test_cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@
3232
import numpy as np
3333
import pytest
3434
import tskit
35-
import zarr
3635

3736
import tszip
3837
import tszip.cli as cli
38+
from tszip import _zarr_compat
3939

4040

4141
def get_stdout_for_pytest():
@@ -265,8 +265,8 @@ def test_chunk_size(self):
265265
assert outpath.exists()
266266
ts = tszip.decompress(outpath)
267267
assert ts.tables == self.ts.tables
268-
store = zarr.storage.ZipStore(str(outpath), mode="r")
269-
root = zarr.open_group(store=store, zarr_format=2, mode="r")
268+
store = _zarr_compat.open_zip_store(outpath, mode="r")
269+
root = _zarr_compat.open_group_for_read(store)
270270
for _, g in root.groups():
271271
for _, a in g.arrays():
272272
assert a.chunks == (20,)

tests/test_compression.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
import numpy as np
3131
import pytest
3232
import tskit
33-
import zarr
3433

3534
import tszip
3635
import tszip.compression as compression
3736
import tszip.exceptions as exceptions
3837
import tszip.provenance as provenance
38+
from tszip import _zarr_compat
3939

4040

4141
class TestMinimalDtype:
@@ -295,17 +295,17 @@ def setup(self, tmp_path):
295295
def test_format_written(self):
296296
ts = msprime.simulate(10, random_seed=1)
297297
tszip.compress(ts, self.path)
298-
with zarr.storage.ZipStore(str(self.path), mode="r") as store:
299-
root = zarr.open_group(store=store, zarr_format=2, mode="r")
298+
with _zarr_compat.open_zip_store(self.path, mode="r") as store:
299+
root = _zarr_compat.open_group_for_read(store)
300300
assert root.attrs["format_name"] == compression.FORMAT_NAME
301301
assert root.attrs["format_version"] == compression.FORMAT_VERSION
302302

303303
def test_provenance(self):
304304
ts = msprime.simulate(10, random_seed=1)
305305
for variants_only in [True, False]:
306306
tszip.compress(ts, self.path, variants_only=variants_only)
307-
with zarr.storage.ZipStore(str(self.path), mode="r") as store:
308-
root = zarr.open_group(store=store, zarr_format=2, mode="r")
307+
with _zarr_compat.open_zip_store(self.path, mode="r") as store:
308+
root = _zarr_compat.open_group_for_read(store)
309309
assert root.attrs["provenance"] == provenance.get_provenance_dict(
310310
{
311311
"variants_only": variants_only,
@@ -314,8 +314,8 @@ def test_provenance(self):
314314
)
315315

316316
def write_file(self, attrs, path):
317-
with zarr.storage.ZipStore(str(path), mode="w") as store:
318-
root = zarr.open_group(store=store, zarr_format=2, mode="a")
317+
with _zarr_compat.open_zip_store(path, mode="w") as store:
318+
root = _zarr_compat.open_group_for_write(store)
319319
root.attrs.update(attrs)
320320

321321
def test_missing_format_keys(self):
@@ -538,8 +538,8 @@ def test_good_chunks(self, tmpdir, chunk_size):
538538
ts2 = tszip.decompress(path)
539539
assert ts1 == ts2
540540

541-
store = zarr.storage.ZipStore(str(path), mode="r")
542-
root = zarr.open_group(store=store, zarr_format=2, mode="r")
541+
store = _zarr_compat.open_zip_store(path, mode="r")
542+
root = _zarr_compat.open_group_for_read(store)
543543
for _, g in root.groups():
544544
for _, a in g.arrays():
545545
assert a.chunks == (chunk_size,)

tszip/_zarr_compat.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import zarr
2+
3+
_ZARR_V3 = int(zarr.__version__.split(".")[0]) >= 3
4+
5+
6+
def open_zip_store(path, mode):
7+
"""Open a ZipStore compatible with zarr v2 and v3."""
8+
return zarr.storage.ZipStore(str(path), mode=mode)
9+
10+
11+
def open_group_for_read(store):
12+
"""Open a zarr group for reading in zarr v2 format."""
13+
if _ZARR_V3:
14+
return zarr.open_group(store=store, zarr_format=2, mode="r")
15+
else:
16+
return zarr.open_group(store=store, mode="r")
17+
18+
19+
def open_group_for_write(store):
20+
"""Open a zarr group for writing in zarr v2 format."""
21+
if _ZARR_V3:
22+
return zarr.open_group(store=store, zarr_format=2, mode="a")
23+
else:
24+
return zarr.open_group(store=store, mode="a")
25+
26+
27+
def empty_array(root, name, shape, dtype, chunks, filters, compressor):
28+
"""Create an empty zarr array in zarr v2 format."""
29+
if _ZARR_V3:
30+
return root.empty(
31+
name=name,
32+
shape=shape,
33+
dtype=dtype,
34+
chunks=chunks,
35+
zarr_format=2,
36+
filters=filters,
37+
compressor=compressor,
38+
)
39+
else:
40+
return root.empty(
41+
name=name,
42+
shape=shape,
43+
dtype=dtype,
44+
chunks=chunks,
45+
filters=filters,
46+
compressor=compressor,
47+
)

tszip/compression.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@
3939
import numpy as np
4040
import tskit
4141
import zarr
42-
from zarr.storage import ZipStore
4342

44-
from . import exceptions, provenance
43+
from . import _zarr_compat, exceptions, provenance
4544

4645
logger = logging.getLogger(__name__)
4746

@@ -106,8 +105,8 @@ def compress(ts, destination, variants_only=False, *, chunk_size=None):
106105
with tempfile.TemporaryDirectory(dir=destdir, prefix=".tszip_work_") as tmpdir:
107106
filename = pathlib.Path(tmpdir, "tmp.trees.tgz")
108107
logging.debug(f"Writing to temporary file {filename}")
109-
with ZipStore(filename, mode="w") as store:
110-
root = zarr.open_group(store=store, zarr_format=2, mode="a")
108+
with _zarr_compat.open_zip_store(filename, mode="w") as store:
109+
root = _zarr_compat.open_group_for_write(store)
111110
compress_zarr(ts, root, variants_only=variants_only, chunk_size=chunk_size)
112111
if is_path:
113112
os.replace(filename, destination)
@@ -151,12 +150,12 @@ def compress(self, root, compressor):
151150
filters = None
152151
if self.delta_filter:
153152
filters = [numcodecs.Delta(dtype=dtype)]
154-
compressed_array = root.empty(
153+
compressed_array = _zarr_compat.empty_array(
154+
root,
155155
name=self.name,
156156
shape=shape,
157157
dtype=dtype,
158158
chunks=self.chunks,
159-
zarr_format=2,
160159
filters=filters,
161160
compressor=compressor,
162161
)
@@ -296,8 +295,8 @@ def check_format(root):
296295
def load_zarr(path):
297296
path = str(path)
298297
try:
299-
store = ZipStore(path, mode="r")
300-
root = zarr.open_group(store=store, zarr_format=2, mode="r")
298+
store = _zarr_compat.open_zip_store(path, mode="r")
299+
root = _zarr_compat.open_group_for_read(store)
301300
except zipfile.BadZipFile as bzf:
302301
raise exceptions.FileFormatError("File is not in tszip format") from bzf
303302

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)