Skip to content

Commit

Permalink
Skip lossy jpeg 2000 on macos (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikogabrielsson authored Nov 22, 2024
1 parent 8cbda8b commit 269e8f8
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 54 deletions.
67 changes: 48 additions & 19 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,47 +92,76 @@ def wsi_names(cls, tiling: Optional[str] = None) -> Iterable[str]:
)

@classmethod
def read_region(cls) -> Iterable[Tuple[str, Dict[str, Any]]]:
return cls._get_dict("read_region")
def read_region(cls) -> Iterable[Tuple[str, UID, Dict[str, Any]]]:
return cls._get_test_values_and_transfer_syntax(
"read_region", "level_transfer_syntax"
)

@classmethod
def read_region_mm(cls) -> Iterable[Tuple[str, Dict[str, Any]]]:
return cls._get_dict("read_region_mm")
def read_region_mm(cls) -> Iterable[Tuple[str, UID, Dict[str, Any]]]:
return cls._get_test_values_and_transfer_syntax(
"read_region_mm", "level_transfer_syntax"
)

@classmethod
def read_region_mpp(cls) -> Iterable[Tuple[str, Dict[str, Any]]]:
return cls._get_dict("read_region_mpp")
def read_region_mpp(cls) -> Iterable[Tuple[str, UID, Dict[str, Any]]]:
return cls._get_test_values_and_transfer_syntax(
"read_region_mpp", "level_transfer_syntax"
)

@classmethod
def read_tile(cls) -> Iterable[Tuple[str, Dict[str, Any]]]:
return cls._get_dict("read_tile")
def read_tile(cls) -> Iterable[Tuple[str, UID, Dict[str, Any]]]:
return cls._get_test_values_and_transfer_syntax(
"read_tile", "level_transfer_syntax"
)

@classmethod
def read_encoded_tile(cls) -> Iterable[Tuple[str, Dict[str, Any]]]:
return cls._get_dict("read_encoded_tile")
def read_encoded_tile(cls) -> Iterable[Tuple[str, UID, Dict[str, Any]]]:
return cls._get_test_values_and_transfer_syntax(
"read_encoded_tile", "level_transfer_syntax"
)

@classmethod
def read_thumbnail(cls) -> Iterable[Tuple[str, Dict[str, Any]]]:
return cls._get_dict("read_thumbnail")
def read_thumbnail(cls) -> Iterable[Tuple[str, UID, Dict[str, Any]]]:
return cls._get_test_values_and_transfer_syntax(
"read_thumbnail", "level_transfer_syntax"
)

@classmethod
def levels(cls) -> Iterable[Tuple[str, int]]:
return cls._get_parameter("levels")

@classmethod
def label_hash(cls) -> Iterable[Tuple[str, Optional[str]]]:
return cls._get_parameter("label")
def label_hash(cls) -> Iterable[Tuple[str, UID, Optional[str]]]:
return cls._get_parameter_and_transfer_syntax("label", "label_transfer_syntax")

@classmethod
def overview_hash(cls) -> Iterable[Tuple[str, UID, Optional[str]]]:
return cls._get_parameter_and_transfer_syntax(
"overview", "overview_transfer_syntax"
)

@classmethod
def overview_hash(cls) -> Iterable[Tuple[str, Optional[str]]]:
return cls._get_parameter("overview")
def _get_test_values_and_transfer_syntax(
cls, test_value_name: str, transfer_syntax_name: str
) -> Iterable[Tuple[str, UID, Dict[str, Any]]]:
return [
(wsi_name, UID(wsi_definition[transfer_syntax_name]), region)
for wsi_name, wsi_definition in cls.test_definitions.items()
for region in wsi_definition[test_value_name]
]

@classmethod
def _get_dict(cls, region_name: str) -> Iterable[Tuple[str, Dict[str, Any]]]:
def _get_parameter_and_transfer_syntax(
cls, parameter_name: str, transfer_syntax_name: str
) -> Iterable[Tuple[str, UID, Any]]:
return [
(wsi_name, region)
(
wsi_name,
UID(wsi_definition[transfer_syntax_name]),
wsi_definition[parameter_name],
)
for wsi_name, wsi_definition in cls.test_definitions.items()
for region in wsi_definition[region_name]
]

@classmethod
Expand Down
94 changes: 62 additions & 32 deletions tests/test_wsidicom_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import platform
from hashlib import md5
from pathlib import Path
from typing import Any, Callable, Dict, Optional

import numpy as np
import pytest
from PIL import Image as Pillow
from pydicom.uid import JPEG2000, UID

from tests.conftest import WsiInputType, WsiTestDefinitions
from wsidicom import WsiDicom
Expand All @@ -35,15 +37,19 @@
],
)
class TestWsiDicomIntegration:
@pytest.mark.parametrize(["wsi_name", "region"], WsiTestDefinitions.read_region())
@pytest.mark.parametrize(
["wsi_name", "transfer_syntax", "region"], WsiTestDefinitions.read_region()
)
def test_read_region(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
region: Dict[str, Any],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand All @@ -58,16 +64,18 @@ def test_read_region(
assert checksum == region["md5"], (region, checksum)

@pytest.mark.parametrize(
["wsi_name", "region"], WsiTestDefinitions.read_region_mm()
["wsi_name", "transfer_syntax", "region"], WsiTestDefinitions.read_region_mm()
)
def test_read_region_mm(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
region: Dict[str, Any],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand All @@ -82,16 +90,18 @@ def test_read_region_mm(
assert checksum == region["md5"], (region, checksum)

@pytest.mark.parametrize(
["wsi_name", "region"], WsiTestDefinitions.read_region_mpp()
["wsi_name", "transfer_syntax", "region"], WsiTestDefinitions.read_region_mpp()
)
def test_read_region_mpp(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
region: Dict[str, Any],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand All @@ -105,15 +115,19 @@ def test_read_region_mpp(
checksum = md5(im.tobytes()).hexdigest()
assert checksum == region["md5"], (region, checksum)

@pytest.mark.parametrize(["wsi_name", "region"], WsiTestDefinitions.read_tile())
@pytest.mark.parametrize(
["wsi_name", "transfer_syntax", "region"], WsiTestDefinitions.read_tile()
)
def test_read_tile(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
region: Dict[str, Any],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand All @@ -127,16 +141,19 @@ def test_read_tile(
assert checksum == region["md5"], (region, checksum)

@pytest.mark.parametrize(
["wsi_name", "region"], WsiTestDefinitions.read_encoded_tile()
["wsi_name", "transfer_syntax", "region"],
WsiTestDefinitions.read_encoded_tile(),
)
def test_read_encoded_tile(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
region: Dict[str, Any],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand All @@ -150,16 +167,18 @@ def test_read_encoded_tile(
assert checksum == region["md5"], (region, checksum)

@pytest.mark.parametrize(
["wsi_name", "region"], WsiTestDefinitions.read_thumbnail()
["wsi_name", "transfer_syntax", "region"], WsiTestDefinitions.read_thumbnail()
)
def test_read_thumbnail(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
region: Dict[str, Any],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand All @@ -174,9 +193,9 @@ def test_read_thumbnail(
)
def test_number_of_levels(
self,
wsi_name: Path,
wsi_name: str,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
expected_level_count: int,
):
# Arrange
Expand All @@ -189,16 +208,19 @@ def test_number_of_levels(
assert levels_count == expected_level_count

@pytest.mark.parametrize(
["wsi_name", "expected_label_hash"], WsiTestDefinitions.label_hash()
["wsi_name", "transfer_syntax", "expected_label_hash"],
WsiTestDefinitions.label_hash(),
)
def test_has_label(
def test_read_label(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
expected_label_hash: Optional[bool],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand All @@ -211,16 +233,19 @@ def test_has_label(
assert checksum == expected_label_hash

@pytest.mark.parametrize(
["wsi_name", "expected_overview_hash"], WsiTestDefinitions.overview_hash()
["wsi_name", "transfer_syntax", "expected_overview_hash"],
WsiTestDefinitions.overview_hash(),
)
def test_has_overview(
def test_read_overview(
self,
wsi_name: Path,
wsi_name: str,
transfer_syntax: UID,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
expected_overview_hash: Optional[str],
):
# Arrange
self._skip_lossy_jpeg2000_tests_on_macos(transfer_syntax)
wsi = wsi_factory(wsi_name, input_type)

# Act
Expand Down Expand Up @@ -253,9 +278,9 @@ def test_save_replace_label(
@pytest.mark.parametrize("wsi_name", WsiTestDefinitions.wsi_names("full"))
def test_levels_returns_selected_pyramid(
self,
wsi_name: Path,
wsi_name: str,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
):
# Arrange
wsi = wsi_factory(wsi_name, input_type)
Expand All @@ -270,9 +295,9 @@ def test_levels_returns_selected_pyramid(
@pytest.mark.parametrize("wsi_name", WsiTestDefinitions.wsi_names("full"))
def test_pyramid_returns_selected_pyramid(
self,
wsi_name: Path,
wsi_name: str,
input_type: WsiInputType,
wsi_factory: Callable[[Path, WsiInputType], WsiDicom],
wsi_factory: Callable[[str, WsiInputType], WsiDicom],
):
# Arrange
wsi = wsi_factory(wsi_name, input_type)
Expand All @@ -283,3 +308,8 @@ def test_pyramid_returns_selected_pyramid(
# Assert
assert isinstance(pyramid, Pyramid)
assert pyramid == wsi.pyramids[wsi.selected_pyramid]

def _skip_lossy_jpeg2000_tests_on_macos(self, transfer_syntax: UID):
"""Lossy Jpeg2000 does not produce same output on macOS."""
if platform.system() == "Darwin" and transfer_syntax == JPEG2000:
pytest.skip("Lossy JPEG2000 does not produce same output on macOS.")
Loading

0 comments on commit 269e8f8

Please sign in to comment.