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
10 changes: 6 additions & 4 deletions hs2p/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
)
from hs2p.configs.resolvers import build_default_sampling_spec
from hs2p.progress import emit_progress, emit_progress_log
from hs2p.stderr_utils import run_with_filtered_stderr
from hs2p.wsi import (
CoordinateOutputMode,
CoordinateSelectionStrategy,
Expand All @@ -33,7 +32,7 @@
overlay_mask_on_slide as _overlay_mask_on_slide,
write_coordinate_preview,
)
from hs2p.wsi.backend import resolve_backend
from hs2p.wsi.backend import coerce_wsd_path, resolve_backend


@dataclass(frozen=True)
Expand Down Expand Up @@ -645,7 +644,7 @@ def _iter_cucim_tile_arrays_for_tar_extraction(
if result.backend != "cucim":
return None
try:
cucim = run_with_filtered_stderr(lambda: importlib.import_module("cucim"))
cucim = importlib.import_module("cucim")
except ModuleNotFoundError:
warnings.warn(
"CuCIM is unavailable for backend='cucim'; falling back to sequential wholeslidedata tile extraction.",
Expand Down Expand Up @@ -695,7 +694,10 @@ def _iter_wsd_tile_arrays_for_tar_extraction(
):
import wholeslidedata as wsd

wsi = wsd.WholeSlideImage(result.image_path, backend=result.backend)
wsi = wsd.WholeSlideImage(
coerce_wsd_path(result.image_path, backend=result.backend),
backend=result.backend,
)
read_step_px = _resolve_read_step_px(result)
step_px_lv0 = _resolve_step_px_lv0(result)
for read_plan in _iter_grouped_read_plans_for_tar_extraction(
Expand Down
18 changes: 16 additions & 2 deletions hs2p/wsi/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ def _normalize_path(path: Path | None) -> str | None:
return str(Path(path))


def coerce_wsd_path(path: Path | str, *, backend: str) -> Path | str:
"""Return a path object compatible with the requested WSD backend.

CuCIM-backed WSD opens require plain strings, while the other backends
accept pathlib objects.
"""
if backend == "cucim":
return str(path)
return Path(path)


def _is_cucim_supported_format(wsi_path: Path) -> bool:
suffix = wsi_path.suffix.lower()
return suffix in CUCIM_SUPPORTED_SUFFIXES
Expand All @@ -37,9 +48,12 @@ def _backend_can_open_slide(
backend: str,
) -> bool:
try:
wsd.WholeSlideImage(Path(wsi_path), backend=backend)
wsd.WholeSlideImage(coerce_wsd_path(wsi_path, backend=backend), backend=backend)
if mask_path is not None:
wsd.WholeSlideImage(Path(mask_path), backend=backend)
wsd.WholeSlideImage(
coerce_wsd_path(mask_path, backend=backend),
backend=backend,
)
return True
except Exception:
return False
Expand Down
12 changes: 9 additions & 3 deletions hs2p/wsi/wsi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from PIL import Image

from hs2p.configs import FilterConfig, SegmentationConfig, TilingConfig
from hs2p.wsi.backend import resolve_backend
from hs2p.wsi.backend import coerce_wsd_path, resolve_backend
from hs2p.wsi.utils import HasEnoughTissue, ResolvedTileGeometry

# ignore all warnings from wholeslidedata
Expand Down Expand Up @@ -78,7 +78,10 @@ def __init__(
self.requested_backend = backend
selection = resolve_backend(backend, wsi_path=path, mask_path=mask_path)
self.backend = selection.backend
self.wsi = wsd.WholeSlideImage(path, backend=self.backend)
self.wsi = wsd.WholeSlideImage(
coerce_wsd_path(path, backend=self.backend),
backend=self.backend,
)

self._scaled_contours_cache = {} # add a cache for scaled contours
self._scaled_holes_cache = {} # add a cache for scaled holes
Expand All @@ -97,7 +100,10 @@ def __init__(
raise ValueError(
"sampling_spec is required when loading a mask-backed slide"
)
self.mask = wsd.WholeSlideImage(mask_path, backend=self.backend)
self.mask = wsd.WholeSlideImage(
coerce_wsd_path(mask_path, backend=self.backend),
backend=self.backend,
)
self.seg_level = self.load_segmentation(
segment_params,
sampling_spec=sampling_spec,
Expand Down
5 changes: 2 additions & 3 deletions scripts/benchmark_tile_read_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
TimeRemainingColumn,
)

from hs2p.stderr_utils import run_with_filtered_stderr

MODE_CONFIG = {
"regular_wsd": {
Expand Down Expand Up @@ -380,7 +379,7 @@ def benchmark_wsd_mode(

def _require_cucim():
try:
return run_with_filtered_stderr(lambda: importlib.import_module("cucim"))
return importlib.import_module("cucim")
except ModuleNotFoundError as exc:
raise RuntimeError(
"CuCIM is required for the requested benchmark modes but is not installed."
Expand All @@ -398,7 +397,7 @@ def benchmark_cucim_batch_mode(
from hs2p.benchmarking import group_read_plans_by_read_size

cucim = _require_cucim()
cu_image = run_with_filtered_stderr(lambda: cucim.CuImage(str(result.image_path)))
cu_image = cucim.CuImage(str(result.image_path))
tile_size_px = int(result.read_tile_size_px)
checksum = 0
tile_count = 0
Expand Down
Loading
Loading