Skip to content

Commit 5926a46

Browse files
committed
Add support for empty lists in VLArray store
1 parent 510ad85 commit 5926a46

5 files changed

Lines changed: 51 additions & 19 deletions

File tree

src/blosc2/_msgpack_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#######################################################################
2+
# Copyright (c) 2019-present, Blosc Development Team <blosc@blosc.org>
3+
# All rights reserved.
4+
#
5+
# SPDX-License-Identifier: BSD-3-Clause
6+
#######################################################################
7+
8+
from __future__ import annotations
9+
10+
from msgpack import packb, unpackb
11+
12+
from blosc2 import blosc2_ext
13+
14+
15+
def msgpack_packb(value):
16+
return packb(value, default=blosc2_ext.encode_tuple, strict_types=True, use_bin_type=True)
17+
18+
19+
def decode_tuple_list_hook(obj):
20+
if obj and obj[0] == "__tuple__":
21+
return tuple(obj[1:])
22+
return obj
23+
24+
25+
def msgpack_unpackb(payload):
26+
return unpackb(payload, list_hook=decode_tuple_list_hook)

src/blosc2/schunk.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
from typing import Any, NamedTuple
1717

1818
import numpy as np
19-
from msgpack import packb, unpackb
2019

2120
import blosc2
2221
from blosc2 import SpecialValue, blosc2_ext
22+
from blosc2._msgpack_utils import msgpack_packb, msgpack_unpackb
2323
from blosc2.info import InfoReporter
2424

2525

@@ -46,12 +46,7 @@ def __setitem__(self, name, content):
4646
return
4747
raise NotImplementedError("Slicing is not supported, unless [:]")
4848
cparams = {"typesize": 1}
49-
content = packb(
50-
content,
51-
default=blosc2_ext.encode_tuple,
52-
strict_types=True,
53-
use_bin_type=True,
54-
)
49+
content = msgpack_packb(content)
5550
super().set_vlmeta(name, content, **cparams)
5651

5752
def __getitem__(self, name):
@@ -60,7 +55,7 @@ def __getitem__(self, name):
6055
# Return all the vlmetalayers
6156
return self.getall()
6257
raise NotImplementedError("Slicing is not supported, unless [:]")
63-
return unpackb(super().get_vlmeta(name), list_hook=blosc2_ext.decode_tuple)
58+
return msgpack_unpackb(super().get_vlmeta(name))
6459

6560
def __delitem__(self, name):
6661
blosc2_ext.check_access_mode(self.urlpath, self.mode)
@@ -120,7 +115,7 @@ def __setitem__(self, key: str, value: bytes) -> None:
120115
..warning: Note that the *length* of the metalayer cannot change,
121116
otherwise an exception will be raised.
122117
"""
123-
value = packb(value, default=blosc2_ext.encode_tuple, strict_types=True, use_bin_type=True)
118+
value = msgpack_packb(value)
124119
blosc2_ext.meta__setitem__(self.schunk, key, value)
125120

126121
def __getitem__(self, item: str | slice) -> bytes | dict[str, bytes]:
@@ -144,10 +139,7 @@ def __getitem__(self, item: str | slice) -> bytes | dict[str, bytes]:
144139
return self.getall()
145140
raise NotImplementedError("Slicing is not supported, unless [:]")
146141
if self.__contains__(item):
147-
return unpackb(
148-
blosc2_ext.meta__getitem__(self.schunk, item),
149-
list_hook=blosc2_ext.decode_tuple,
150-
)
142+
return msgpack_unpackb(blosc2_ext.meta__getitem__(self.schunk, item))
151143
else:
152144
raise KeyError(f"{item} not found")
153145

src/blosc2/vlarray.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@
1111
import pathlib
1212
from typing import TYPE_CHECKING, Any
1313

14-
from msgpack import packb, unpackb
15-
1614
import blosc2
17-
from blosc2 import blosc2_ext
15+
from blosc2._msgpack_utils import msgpack_packb, msgpack_unpackb
1816

1917
if TYPE_CHECKING:
2018
from collections.abc import Iterator
@@ -177,7 +175,7 @@ def _copy_meta(self) -> dict[str, Any]:
177175
return {name: self.meta[name] for name in self.meta}
178176

179177
def _serialize(self, value: Any) -> bytes:
180-
payload = packb(value, default=blosc2_ext.encode_tuple, strict_types=True, use_bin_type=True)
178+
payload = msgpack_packb(value)
181179
_check_serialized_size(payload)
182180
return payload
183181

@@ -244,7 +242,7 @@ def __getitem__(self, index: int) -> Any:
244242
return [self[i] for i in self._slice_indices(index)]
245243
index = self._normalize_index(index)
246244
payload = self.schunk.decompress_chunk(index)
247-
return unpackb(payload, list_hook=blosc2_ext.decode_tuple)
245+
return msgpack_unpackb(payload)
248246

249247
def __setitem__(self, index: int, value: Any) -> None:
250248
if isinstance(index, slice):
@@ -335,7 +333,7 @@ def __repr__(self) -> str:
335333
return f"VLArray(len={len(self)}, urlpath={self.urlpath!r})"
336334

337335

338-
def vlarray_from_cframe(cframe: bytes, copy: bool = False) -> VLArray:
336+
def vlarray_from_cframe(cframe: bytes, copy: bool = True) -> VLArray:
339337
"""Deserialize a CFrame buffer into a :class:`VLArray`."""
340338

341339
schunk = blosc2.schunk_from_cframe(cframe, copy=copy)

tests/test_vlarray.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ def test_vlarray_copy():
255255
blosc2.remove_urlpath(copy_path)
256256

257257

258+
def test_vlarray_empty_list_roundtrip():
259+
values = [[], {"a": []}, [[], ["nested"]], None, ("tuple", []), {"rows": [[], []]}]
260+
vlarray = blosc2.VLArray()
261+
vlarray.extend(values)
262+
assert list(vlarray) == values
263+
264+
258265
def test_vlarray_insert_delete_errors():
259266
vlarray = blosc2.VLArray()
260267
vlarray.append("value")

tests/test_vlmeta.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,12 @@ def clear(schunk):
118118

119119
schunk.vlmeta.clear()
120120
assert schunk.vlmeta.__len__() == 0
121+
122+
123+
def test_vlmeta_empty_list_roundtrip():
124+
schunk = blosc2.SChunk()
125+
schunk.vlmeta["empty"] = []
126+
schunk.vlmeta["nested"] = {"rows": [[], ["x"]]}
127+
128+
assert schunk.vlmeta["empty"] == []
129+
assert schunk.vlmeta["nested"] == {"rows": [[], ["x"]]}

0 commit comments

Comments
 (0)