Repository navigation
fix: open_wsi keeps slides out of each other's stores - #88
Merged
Merged
Conversation
open_wsi(slide, store="data") made data the store of the first slide when data did not exist yet, so every later slide opened with store="data" loaded that store, and its write() went into it. A new store path without a .zarr suffix is now a directory that holds a store for each slide, data/<stem>.zarr, as an existing directory already was. A .zarr path, an existing store and an existing file are the store, as before. A store whose slide has another level-0 shape than the opened slide now raises a ValueError instead of being loaded and overwritten. The stores written before hold the shape too, so the data stores the bug has made are caught.
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The implementation matches the documented behavior and includes focused regression coverage.
Review effort: Balanced
Findings: None
What changed in this PR
Fixes open_wsi store collisions between slides.
Changes:
- Treats new non-
.zarrpaths as store directories. - Validates reused stores against the slide’s level-0 shape.
- Adds regression tests for isolation and mismatched stores.
| File | Description |
|---|---|
wsidata/io/_wsi.py |
Resolves safe store paths and validates slide shape. |
tests/test_wsidata.py |
Covers per-slide stores and mismatch rejection. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…-ef8a18 # Conflicts: # tests/test_wsidata.py
…-ef8a18 # Conflicts: # tests/test_wsidata.py
…-ef8a18 # Conflicts: # tests/test_wsidata.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New store folders.
open_wsi(slide, store="data")tookdataas a folder of stores only when it already existed. On a fresh disk it madedatathe store of the first slide. Every later slide opened withstore="data"then founddatato be a zarr store and used it, and itswrite()went into the first slide's store. In the lazyslide-tutorialsmultiple_slidesnotebook, 45 GTEx slides went into one store nameddata, andagg_wsithen raised "File data/.zarr not existed." The notebook worked wheredata/already existed.A new store path is now the store only with a
.zarrsuffix. Any other new path is a directory, as an existing one already was:store="data"givesdata/<stem>.zarr(ordata/<stem>.scene-<scene>.zarr), andwrite()createsdata/. Unchanged:.zarrpaths, new or existing; existing zarr stores, whatever their name; existing directories; existing files.The store of another slide raises.
_validate_store_sceneonly checks the scene. So the store of another slide was loaded,WSIDatareplaced its slide properties with the opened slide's, and the nextwrite()merged the two slides.open_wsinow compares the level-0shapein the store'sslide_propertieswith the reader's, and raises aValueErrornaming both when they differ:Every store written since the slide properties moved to
attrsholds the shape, so this also catches thedatastores the bug has already made. Stores without a shape are not checked.Behaviour changes:
.zarrthat was meant as the store itself, such asstore="out/a", is now a folder: the store goes toout/a/<stem>.zarr. LazySlide's source and the tutorials pass.zarrpaths (sample.zarr,temp.zarr) or a folder ("data").Options weighed
.zarris a folder: done, only for paths that do not exist yet.Tests
Each failed before the fix:
test_store_folder_keeps_the_stores_of_slides_apart: two slides opened withstore=str(tmp_path / "data"), each written.data/holdsGTEX-1117F-0526.zarrandsample.zarr; before, it was one store (['zarr.json']).test_store_of_another_slide_raises:datawritten as the store ofsample.svs, thenopen_wsi(GTEX-1117F-0526.svs, store="data")raises; before, it did not.The repro from the report, with lazyslide
find_tissuesandwrite(), now givesdata/GTEX-O5YU-0926.zarranddata/GTEX-111YS-2226.zarr.Full suite, merged with main: 129 passed, 14 skipped on Python 3.14; 138 passed, 5 skipped on 3.13 with pylibCZIrw (multi-scene stores). ruff passes.
Once released, the
store=f"data/{slide}.zarr"workaround in lazyslide-tutorials (ci/hf-heavy-render) is no longer needed, though it keeps working.Not fixed
Two slides of one level-0 shape given one store, such as same-named slides from different folders opened with one store folder, still share it without an error. A slide id in the store would catch that.