Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/ndevio/nimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,26 @@ def _initialize_source_state(self, image: ImageLike) -> None:
self.path = source
self._is_remote = True

def set_scene(self, scene_id: str | int) -> None:
"""Switch the operating scene, invalidating cached layer data.

Extends :meth:`BioImage.set_scene` so that switching scenes clears
this image's lazy ``reference_xarray`` / ``layer_data`` /
``_layer_metadata`` caches, which are scene-specific. Callers (scene
widget, reader's open-all-scenes path) get correct reload behaviour
without reaching into privates.

Parameters
----------
scene_id : str | int
The scene id (string) or scene index (integer) to switch to.

"""
super().set_scene(scene_id)
self._reference_xarray = None
self._layer_data = None
self._layer_metadata = None

def _fits_in_memory(self) -> bool:
"""Return True if the uncompressed image fits comfortably in RAM."""
if self.path is None:
Expand Down
4 changes: 0 additions & 4 deletions src/ndevio/widgets/_scene_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,6 @@ def open_scene(self) -> None:
scene_index = int(scene.split(DELIMITER)[0])
self.img.set_scene(scene_index)

# Clear cached data so new scene is loaded
self.img._reference_xarray = None
self.img._layer_data = None

# Get layer tuples and add to viewer using napari's Layer.create()
from napari.layers import Layer

Expand Down
30 changes: 30 additions & 0 deletions tests/test_nimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,36 @@ def test_colormap_three_plus_channels_uses_multi_channel_cycle(
assert colormaps[2] == MULTI_CHANNEL_CYCLE[2] # yellow
assert colormaps[3] == MULTI_CHANNEL_CYCLE[3] # blue


def test_set_scene_invalidates_cached_layer_data(resources_dir: Path):
"""Switching scenes clears the lazy reference_xarray / layer_data caches.

Regression test: the scene widget previously had to clear these privates
by hand, and the reader's open-all-scenes path never did — returning
stale scene-0 data for every scene. ``set_scene`` now owns the
invalidation so every caller reloads the new scene.
"""
img = nImage(resources_dir / CZI_FILE)
assert len(img.scenes) > 1

# Prime the caches on the current scene
img.get_layer_data_tuples()
assert img._reference_xarray is not None
assert img._layer_data is not None
assert img._layer_metadata is not None

img.set_scene(1)

# Caches must be invalidated so the next access reloads the new scene
assert img._reference_xarray is None
assert img._layer_data is None
assert img._layer_metadata is None

# And data reloads lazily for the new scene
assert img.reference_xarray is not None
assert img.layer_scale is not None
assert img._layer_metadata is not None

def test_auto_detect_labels_from_channel_name(self, resources_dir: Path):
"""Test that channels with label-like names are detected as labels."""
import numpy as np
Expand Down