🚀 (zarr) make save_to_disk write path fsspec-aware (#485) - #490
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
How to testAutomated (the 11 new cases + regression): cd src/plaid # repo root
uv sync
uv run pytest tests/storage/test_zarr_fsspec_write.py -v
# and the existing storage suite, to confirm no regression:
uv run pytest tests/storage/test_storage.py tests/storage/test_zarr_init.pyWhat each part covers:
Manual sanity check (no cloud creds needed), in a Python REPL: import fsspec, zarr
from plaid.storage.zarr.writer import _is_local_target, _join_target
# discrimination
assert _is_local_target("/tmp/x") and _is_local_target("file:///tmp/x")
assert not _is_local_target("memory://root")
# URL join no longer collapses "://"
assert _join_target("memory://root", "data", "train") == "memory://root/data/train"
# end-to-end: write a DatasetDict to memory:// and read it back
# (build a small `generators`/`variable_schema` as in the sequential test, then)
# generate_datasetdict_to_disk(output_folder="memory://demo", ...)
group = zarr.open_group("memory://demo/data/train", mode="r")
print(sorted(group.group_keys())) # sample_000000000, ...
import os; assert not os.path.exists("memory:") # no local leak
Testing a real cloud target (optional, outside CI): install the backend ( |
|
Hi @tmolcard — this lands the native remote-write direction we discussed in #478 and tracked in #479: Since your read-from-S3 → build PLAID in memory → write-back-to-S3 pipeline is basically the motivating use case, your feedback would be really valuable if you have a moment. A no-creds sanity check on the branch: uv run pytest tests/storage/test_zarr_fsspec_write.py -vAnd the real thing, if you can point it at a bucket ( save_to_disk(output_folder="s3://your-bucket/prefix", sample_constructor=..., ids=..., backend="zarr", num_proc=N)Two things I'd genuinely like your read on:
|
| @@ -0,0 +1,210 @@ | |||
| """Tests for the fsspec-aware Zarr write path (issue #485). | |||
casenave
left a comment
There was a problem hiding this comment.
Did your check that this works, or at least the local writes are still working as before ?
Summary
Makes the Zarr backend write path fsspec-aware so datasets can be written to any fsspec target (
memory://,s3://,gs://, ...), not only the local filesystem. Scope is limited to sub-issue #485 (write side, zarr backend); the read path and the layer-1 metadata plumbing are tracked separately (#486, #487, #489).Closes #485
Problem
In
plaid/storage/zarr/writer.py::generate_datasetdict_to_disk, the write path was pinned to local storage in two places:zarr.storage.LocalStore(split_root_path). When given a remote URL, this silently wrote the data to a literal local directory named after the URL (e.g. amemory:folder) instead of the intended remote target.Path(output_folder) / "data"+mkdir(...).pathlib.Pathcollapses the://separator (memory://root→memory:/root), corrupting remote targets, andmkdiris meaningless on object stores.Changes
_is_local_target(target)— discriminates local paths /file://URLs from remote fsspec protocols viafsspec.core.url_to_fs. Missing backends surface fsspec's own install hint (e.g.Install s3fs to access S3)._join_target(base, *parts)— joins components while preserving the URL protocol separator for remote targets, keepingPathsemantics for local ones._open_split_group(target, mode)— thin wrapper overzarr.open_group, which already resolves an fsspec URL to aFsspecStore. Used by both the sequential create and the parallel-worker reopen, replacing the hardcodedLocalStore.data/folder is now joined URL-safely andmkdiris only invoked for local targets.zarr.open_groupalready accepts fsspec URLs, andzarrpulls infsspec(already imported at module top in the siblingreader.py), so no new dependency is added.Tests
New
tests/storage/test_zarr_fsspec_write.py(11 cases):_is_local_target(local/relative/file:///memory://, plus the missing-backendImportError) and_join_target(localPathvs remote URL, trailing-slash handling);memory://target, asserting samples land at the intended remote location, the flattened global feature is readable back, and no literalmemory:directory is created locally;_open_split_groupcreate-then-reopen round-trip onmemory://(mirrors the sequential-create / parallel-worker-reopen handshake);num_proc=2) write, guarding against a regression in the store-selection change.Existing storage tests (
test_storage.py,test_zarr_init.py) pass unchanged.ruff check/ruff format --checkclean.Docs & changelog
docs/source/tutorials/storage.md— added an admonition documenting that, with the zarr backend,output_folderaccepts any fsspec URL (with ans3://example and the backend-install caveat).[Unreleased] / Added.Checklist
🔗 Related issues
Closes #485