Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1c11b1e
REL: Release 1.3.0 (#496)
shaneahmed Oct 21, 2022
075c472
:bookmark: REL: Release 1.3.0 (#523)
shaneahmed Dec 20, 2022
79d26e9
:bookmark: REL: Release 1.3.1 (#523)
shaneahmed Dec 20, 2022
ce788a3
Merge remote-tracking branch 'origin/master'
shaneahmed Dec 20, 2022
24390e5
🔖 REL: Release 1.3.2 (#541)
shaneahmed Feb 17, 2023
d548b33
🔖 REL: Release 1.3.3 (#552)
shaneahmed Mar 2, 2023
5231f9d
🔖 Release 1.4.0 (#599)
shaneahmed May 5, 2023
51f504b
🚑 Release 1.4.1 (#661)
shaneahmed Jul 25, 2023
bba59ba
🔖 Release 1.5.0 (#757)
shaneahmed Dec 15, 2023
490be26
🚑 Release 1.5.1 (#764)
shaneahmed Dec 16, 2023
e14a4fc
🔖 Release 1.6.0 (#895)
shaneahmed Dec 12, 2024
2275bf0
🔖 Release 2.0.0 (#1031)
shaneahmed Mar 11, 2026
26f099f
:bookmark: Release 2.0.1 (#1039)
shaneahmed Mar 16, 2026
99636c5
🔖 Release 2.1.0 (#1064)
shaneahmed May 19, 2026
5086d48
♻️ Refactor: Split monolithic wsireader into modular package
shaneahmed Jun 5, 2026
25e51f5
fix: Add missing module exports to wsireader for backward compatibility
shaneahmed Jun 5, 2026
399597b
:bug: Fix imports
shaneahmed Jun 5, 2026
5542e46
:bug: Fix `json` imports
shaneahmed Jun 5, 2026
3254ccc
:bug: Fix `fsspec` imports
shaneahmed Jun 5, 2026
be0e3b5
:bug: Fix imports
shaneahmed Jun 5, 2026
6a0fb88
:bug: Fix imports
shaneahmed Jun 5, 2026
e9fbb98
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 5, 2026
5c5ef12
:fire: Remove REFACTORING_SUMMARY.md
shaneahmed Jun 5, 2026
c8389e2
Merge remote-tracking branch 'origin/refactor/split-wsireader-into-mo…
shaneahmed Jun 5, 2026
3c06afa
:art: Sort imports
shaneahmed Jun 8, 2026
f59f3b7
:bug: Fix tests for wsireader
shaneahmed Jun 8, 2026
dbca748
:bug: Fix `ruff` tests
shaneahmed Jun 8, 2026
9f56088
Merge remote-tracking branch 'origin/develop' into refactor/split-wsi…
shaneahmed Jun 9, 2026
c950fe2
Merge remote-tracking branch 'origin/develop' into refactor/split-wsi…
shaneahmed Jun 9, 2026
05dd4bd
Merge remote-tracking branch 'origin/develop' into refactor/split-wsi…
shaneahmed Jun 9, 2026
831d888
:bug: Fix missing changes from #1076
shaneahmed Jun 9, 2026
9e3790b
:bug: Fix Deepsource error
shaneahmed Jun 9, 2026
fa80984
:bug: Fix pre-commit errors
shaneahmed Jun 9, 2026
3984144
:bug: Fix Deepsource and AI errors
shaneahmed Jun 9, 2026
cadd8f1
:bug: Fix tests `test_tiffreader.py`
shaneahmed Jun 10, 2026
0d0bf1a
Merge branch 'develop' into refactor/split-wsireader-into-modules
shaneahmed Jun 12, 2026
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
29 changes: 18 additions & 11 deletions tests/test_tiffreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from unittest.mock import MagicMock

from tiatoolbox.wsicore import wsireader
from tiatoolbox.wsicore.wsireader import tiff


def test_ome_missing_instrument_ref(
Expand Down Expand Up @@ -154,7 +155,7 @@ def __init__(
assert isinstance(reader, wsireader.VirtualWSIReader)


def test_try_tiff_raises_other_valueerror(
def test_try_tiff_raises_other_value_error(
monkeypatch: pytest.MonkeyPatch, track_tmp_path: Path
) -> None:
"""Test try_tiff raises ValueError if not an unsupported TIFF format."""
Expand All @@ -174,7 +175,7 @@ def raise_other_valueerror(*args: object, **kwargs: object) -> None:
msg = "Some other TIFF error"
raise ValueError(msg)

monkeypatch.setattr(wsireader, "TIFFWSIReader", raise_other_valueerror)
monkeypatch.setattr(tiff, "TIFFWSIReader", raise_other_valueerror)

with pytest.raises(ValueError, match="Some other TIFF error"):
wsireader.WSIReader.try_tiff(
Expand Down Expand Up @@ -619,11 +620,11 @@ def test_handle_tiff_wsi_returns_tiff_reader(
image.save(tiff_path)

# Patch is_tiled_tiff to return True
monkeypatch.setattr(wsireader, "is_tiled_tiff", lambda _: True)
monkeypatch.setattr(wsireader.base, "is_tiled_tiff", lambda _: True)

# Patch TIFFWSIReader.__init__ to bypass internal checks
with patch(
"tiatoolbox.wsicore.wsireader.TIFFWSIReader.__init__", return_value=None
"tiatoolbox.wsicore.wsireader.tiff.TIFFWSIReader.__init__", return_value=None
):
reader = wsireader._handle_tiff_wsi(
input_path=tiff_path,
Expand All @@ -639,7 +640,7 @@ def raise_openslide_error(*args: object, **kwargs: object) -> None:
_ = args
_ = kwargs
msg = "mock error"
raise wsireader.openslide.OpenSlideError(msg)
raise wsireader.openslide.openslide.OpenSlideError(msg)


def test_handle_tiff_wsi_openslide_error(
Expand All @@ -651,19 +652,23 @@ def test_handle_tiff_wsi_openslide_error(
Image.new("RGB", (10, 10), color="white").save(tiff_path)

# Patch detect_format to return a non-None value
monkeypatch.setattr(wsireader.openslide.OpenSlide, "detect_format", lambda _: "SVS")
monkeypatch.setattr(
wsireader.openslide.openslide.OpenSlide, "detect_format", lambda _: "SVS"
)

# Patch OpenSlideWSIReader to raise OpenSlideError
monkeypatch.setattr(wsireader, "OpenSlideWSIReader", raise_openslide_error)
monkeypatch.setattr(
wsireader.openslide, "OpenSlideWSIReader", raise_openslide_error
)

# Patch is_tiled_tiff to return True so fallback to TIFFWSIReader is triggered
monkeypatch.setattr(wsireader, "is_tiled_tiff", lambda _: True)
monkeypatch.setattr(wsireader.base, "is_tiled_tiff", lambda _: True)

# Patch TIFFWSIReader.__init__ to bypass internal checks
with patch(
"tiatoolbox.wsicore.wsireader.TIFFWSIReader.__init__", return_value=None
"tiatoolbox.wsicore.wsireader.tiff.TIFFWSIReader.__init__", return_value=None
):
result = wsireader._handle_tiff_wsi(
result = wsireader.base._handle_tiff_wsi(
input_path=tiff_path,
mpp=(0.5, 0.5),
power=20.0,
Expand All @@ -681,7 +686,9 @@ def test_handle_tiff_wsi_openslide_success(
Image.new("RGB", (10, 10), color="white").save(tiff_path)

# Patch detect_format to return a valid format
monkeypatch.setattr(wsireader.openslide.OpenSlide, "detect_format", lambda _: "SVS")
monkeypatch.setattr(
wsireader.openslide.openslide.OpenSlide, "detect_format", lambda _: "SVS"
)

# Patch OpenSlideWSIReader.__init__ to bypass actual init logic
with patch.object(wsireader.OpenSlideWSIReader, "__init__", return_value=None):
Expand Down
14 changes: 8 additions & 6 deletions tests/test_wsireader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3125,7 +3125,9 @@ def test_fsspec_json_wsi_reader_instantiation() -> None:
"tiatoolbox.wsicore.wsireader.FsspecJsonWSIReader.is_valid_zarr_fsspec",
return_value=True,
),
patch("tiatoolbox.wsicore.wsireader.FsspecJsonWSIReader") as mock_reader,
patch(
"tiatoolbox.wsicore.wsireader.fsspec_json.FsspecJsonWSIReader"
) as mock_reader,
):
WSIReader.open(input_path, mpp, power)
mock_reader.assert_called_once_with(input_path, mpp=mpp, power=power)
Expand Down Expand Up @@ -3785,14 +3787,14 @@ def test_virtualwsireader_mode_detection_edge_cases() -> None:
"""Test VirtualWSIReader mode detection with various image types."""
# Test with 2D image (should set mode to 'feature')
img_2d = np.ones((100, 100), dtype=np.uint8)
with patch("tiatoolbox.wsicore.wsireader.logger") as mock_logger:
with patch("tiatoolbox.wsicore.wsireader.base.logger") as mock_logger:
wsi = VirtualWSIReader(img_2d, mode="rgb")
mock_logger.warning.assert_called()
assert wsi.mode == "feature"

# Test with 5-channel image (should set mode to 'feature')
img_5ch = np.ones((100, 100, 5), dtype=np.uint8)
with patch("tiatoolbox.wsicore.wsireader.logger") as mock_logger:
with patch("tiatoolbox.wsicore.wsireader.base.logger") as mock_logger:
wsi = VirtualWSIReader(img_5ch, mode="rgb")
mock_logger.warning.assert_called()
assert wsi.mode == "feature"
Expand All @@ -3811,7 +3813,7 @@ def test_openslide_estimate_mpp_edge_cases() -> None:
"tiff.ResolutionUnit": "inch",
# Missing YResolution
}
with patch("tiatoolbox.wsicore.wsireader.logger") as mock_logger:
with patch("tiatoolbox.wsicore.wsireader.openslide.logger") as mock_logger:
result = OpenSlideWSIReader._estimate_mpp(props)
mock_logger.warning.assert_called()
assert result is None
Expand Down Expand Up @@ -4263,7 +4265,7 @@ def test_virtual_read_rect_resolution_coord_space_roundtrip() -> None:
class TestTryOpenSlide:
"""Unit tests for the WSIReader.try_openslide static method."""

@patch("tiatoolbox.wsicore.wsireader.OpenSlideWSIReader")
@patch("tiatoolbox.wsicore.wsireader.openslide.OpenSlideWSIReader")
def test_tiff_suffix_success(self, mock_reader: MagicMock) -> None:
"""Test that a valid TIFF file results in an OpenSlideWSIReader instance."""
mock_instance = MagicMock()
Expand All @@ -4283,7 +4285,7 @@ def test_tiff_suffix_success(self, mock_reader: MagicMock) -> None:
)
assert result is mock_instance

@patch("tiatoolbox.wsicore.wsireader.OpenSlideWSIReader")
@patch("tiatoolbox.wsicore.wsireader.openslide.OpenSlideWSIReader")
def test_tiff_suffix_raises_openslide_error(self, mock_reader: MagicMock) -> None:
"""Test that OpenSlide errors are caught and the function returns None."""
mock_reader.side_effect = openslide.OpenSlideError("bad file")
Expand Down
5 changes: 3 additions & 2 deletions tiatoolbox/wsicore/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Package to read whole slide images."""

from typing import TypedDict
from numbers import Number
from typing import TYPE_CHECKING, TypedDict

from tiatoolbox.wsicore import metadata, wsimeta, wsireader

from .wsimeta import WSIMeta
from .wsireader import Number, WSIReader
from .wsireader import WSIReader

# Top level imports
__all__ = [
Expand Down
Loading
Loading