diff --git a/src/blosc2/schunk.py b/src/blosc2/schunk.py index 33452acae..97cecb04f 100644 --- a/src/blosc2/schunk.py +++ b/src/blosc2/schunk.py @@ -1874,12 +1874,9 @@ def _open_special_store(urlpath, mode, offset, *, deserialize=DeserializeMode.SA from blosc2.remote_store import RemoteStore return RemoteStore._open_artifact(urlpath, mode=mode, **kwargs) - if "b2embed" in schunk_meta: - if offset != 0: - raise ValueError("Offset must be 0 for EmbedStore") - from blosc2.embed_store import EmbedStore - - return EmbedStore(urlpath, mode=mode, deserialize=deserialize, **kwargs) + # No "b2embed" check: the embed.b2e of a .b2d/.b2z written by python-blosc2 + # <= 4.0.0 carries that marker too (b2dict and b2tree came in 4.1.0), so it + # does not tell the store type. Those stores and .b2e files go by extension. if "b2dict" in schunk_meta: if offset != 0: raise ValueError("Offset must be 0 for DictStore") diff --git a/tests/data/legacy_store_v4.0.0/dictstore.b2z b/tests/data/legacy_store_v4.0.0/dictstore.b2z new file mode 100644 index 000000000..d45f14c38 Binary files /dev/null and b/tests/data/legacy_store_v4.0.0/dictstore.b2z differ diff --git a/tests/test_dict_store.py b/tests/test_dict_store.py index b8f14b0a6..98a90f808 100644 --- a/tests/test_dict_store.py +++ b/tests/test_dict_store.py @@ -167,6 +167,31 @@ def test_extensionless_store_is_a_directory(tmp_path): assert np.array_equal(opened["/node1"][:], np.arange(4)) +@pytest.mark.parametrize(("suffix", "store_type"), [("b2z", blosc2.TreeStore), ("b2d", blosc2.DictStore)]) +def test_open_store_written_by_4_0_0(tmp_path, suffix, store_type): + # A DictStore written by 4.0.0 (no b2dict marker yet) with an embedded leaf, + # an external one and a nested key; it opens by its extension, as in 4.0.0 + fixture = pathlib.Path(__file__).parent / "data" / "legacy_store_v4.0.0" / "dictstore.b2z" + path = tmp_path / f"legacy.{suffix}" + if suffix == "b2z": + shutil.copy(fixture, path) + else: # the same members, unzipped + with zipfile.ZipFile(fixture) as zf: + zf.extractall(path) + expected = { + "/embedded": np.arange(12, dtype="