Skip to content

Commit 3842634

Browse files
Add ManifestStore support for empty chunks. (#668)
1 parent 7dabefe commit 3842634

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

virtualizarr/manifests/manifest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ def with_validation(
4848
"""
4949

5050
# note: we can't just use `__init__` or a dataclass' `__post_init__` because we need `fs_root` to be an optional kwarg
51-
52-
path = validate_and_normalize_path_to_uri(path, fs_root=fs_root)
51+
if path != "":
52+
path = validate_and_normalize_path_to_uri(path, fs_root=fs_root)
5353
validate_byte_range(offset=offset, length=length)
5454
return ChunkEntry(path=path, offset=offset, length=length)
5555

virtualizarr/manifests/store.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,10 @@ async def get(
252252
chunk_indexes = parse_manifest_index(
253253
key, marr.metadata.chunk_key_encoding.separator
254254
)
255+
255256
path = manifest._paths[chunk_indexes]
257+
if path == "":
258+
return None
256259
offset = manifest._offsets[chunk_indexes]
257260
length = manifest._lengths[chunk_indexes]
258261
# Get the configured object store instance that matches the path

virtualizarr/tests/test_manifests/test_store.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,31 @@ def s3_store(minio_bucket):
126126
)
127127

128128

129+
@pytest.fixture()
130+
def empty_memory_store():
131+
import obstore as obs
132+
133+
store = obs.store.MemoryStore()
134+
prefix = get_store_prefix("")
135+
chunk_dict = {
136+
"0.0": {"path": "", "offset": 0, "length": 4},
137+
}
138+
manifest = ChunkManifest(entries=chunk_dict)
139+
codecs = [{"configuration": {"endian": "little"}, "name": "bytes"}]
140+
array_metadata = create_v3_array_metadata(
141+
shape=(1, 1),
142+
chunk_shape=(1, 1),
143+
data_type=np.dtype("int32"),
144+
codecs=codecs,
145+
chunk_key_encoding={"name": "default", "separator": "."},
146+
fill_value=0,
147+
)
148+
manifest_array = ManifestArray(metadata=array_metadata, chunkmanifest=manifest)
149+
manifest_group = ManifestGroup(arrays={"foo": manifest_array})
150+
registry = ObjectStoreRegistry({prefix: store})
151+
return ManifestStore(store_registry=registry, group=manifest_group)
152+
153+
129154
@requires_obstore
130155
class TestManifestStore:
131156
def test_manifest_store_properties(self, local_store):
@@ -135,6 +160,16 @@ def test_manifest_store_properties(self, local_store):
135160
assert not local_store.supports_writes
136161
assert not local_store.supports_partial_writes
137162

163+
@pytest.mark.asyncio
164+
@pytest.mark.parametrize(
165+
"manifest_store",
166+
["empty_memory_store"],
167+
)
168+
async def test_get_empty_chunk(self, manifest_store, request):
169+
store = request.getfixturevalue(manifest_store)
170+
observed = await store.get("foo/c/0.0", prototype=default_buffer_prototype())
171+
assert observed is None
172+
138173
@pytest.mark.asyncio
139174
@pytest.mark.parametrize(
140175
"manifest_store",

0 commit comments

Comments
 (0)