-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ddd3c2b
commit 3bb96c2
Showing
14 changed files
with
247 additions
and
14 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Copyright (c) dlup contributors |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Empty file.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# Copyright (c) dlup contributors | ||
|
||
import numpy as np | ||
import pytest | ||
from PIL import Image | ||
|
||
from dlup.backends.common import AbstractSlideBackend, numpy_to_pil | ||
|
||
|
||
def test_numpy_to_pil_single_channel(): | ||
arr = np.random.randint(0, 256, (10, 10, 1), dtype=np.uint8) | ||
pil_img = numpy_to_pil(arr) | ||
assert pil_img.mode == "L" | ||
|
||
|
||
def test_numpy_to_pil_rgb(): | ||
arr = np.random.randint(0, 256, (10, 10, 3), dtype=np.uint8) | ||
pil_img = numpy_to_pil(arr) | ||
assert pil_img.mode == "RGB" | ||
|
||
|
||
def test_numpy_to_pil_rgba(): | ||
arr = np.random.randint(0, 256, (10, 10, 4), dtype=np.uint8) | ||
pil_img = numpy_to_pil(arr) | ||
assert pil_img.mode == "RGBA" | ||
|
||
|
||
def test_numpy_to_pil_invalid_channels(): | ||
arr = np.random.randint(0, 256, (10, 10, 5), dtype=np.uint8) | ||
with pytest.raises(RuntimeError): | ||
numpy_to_pil(arr) | ||
|
||
|
||
class TestAbstractBackend: | ||
class DummySlideBackend(AbstractSlideBackend): | ||
# Minimal implementation to avoid the ABC restriction. | ||
def __init__(self, filename: str): | ||
super().__init__(filename) | ||
# Dummy data for testing | ||
self._level_count = 3 | ||
self._downsamples = [1.0, 2.0, 4.0] | ||
self._spacings = [(0.5, 0.5), (1.0, 1.0), (2.0, 2.0)] | ||
self._shapes = [(1000, 1000), (500, 500), (250, 250)] | ||
|
||
def read_region(self, coordinates, level, size) -> Image.Image: | ||
return Image.new("RGB", size, color="white") | ||
|
||
@property | ||
def properties(self): | ||
return {} | ||
|
||
@property | ||
def magnification(self): | ||
return 10.0 | ||
|
||
@property | ||
def vendor(self): | ||
return "TestVendor" | ||
|
||
def close(self): | ||
pass | ||
|
||
def test_dummy_slide_backend_properties(self): | ||
slide = self.DummySlideBackend("test_filename.tiff") | ||
|
||
# Testing the level_count | ||
assert slide.level_count == 3 | ||
|
||
# Testing the dimensions | ||
assert slide.dimensions == (1000, 1000) | ||
|
||
# Testing the spacing | ||
assert slide.spacing == (0.5, 0.5) | ||
|
||
# Testing the level_dimensions | ||
assert slide.level_dimensions == [(1000, 1000), (500, 500), (250, 250)] | ||
|
||
# Testing the level_spacings | ||
assert slide.level_spacings == ((0.5, 0.5), (1.0, 1.0), (2.0, 2.0)) | ||
|
||
# Testing the level_downsamples | ||
assert slide.level_downsamples == (1.0, 2.0, 4.0) | ||
|
||
# Testing slide bounds | ||
assert slide.slide_bounds == ((0, 0), (1000, 1000)) | ||
|
||
# Testing get_best_level_for_downsample | ||
assert slide.get_best_level_for_downsample(0.5) == 0 | ||
assert slide.get_best_level_for_downsample(1.0) == 0 | ||
assert slide.get_best_level_for_downsample(2.0) == 1 | ||
assert slide.get_best_level_for_downsample(3.0) == 1 | ||
assert slide.get_best_level_for_downsample(4.5) == 2 | ||
|
||
def test_repr(self): | ||
slide = self.DummySlideBackend("test_filename.tiff") | ||
assert repr(slide) == "<DummySlideBackend(test_filename.tiff)>" | ||
|
||
def test_spacing_without_set(self): | ||
slide = self.DummySlideBackend("test_filename.tiff") | ||
slide._spacings = None | ||
assert slide.spacing is None | ||
|
||
def test_get_thumbnail(self): | ||
slide = self.DummySlideBackend("test_filename.tiff") | ||
|
||
# Getting a 200x200 thumbnail | ||
thumbnail = slide.get_thumbnail(200) | ||
assert isinstance(thumbnail, Image.Image) | ||
assert thumbnail.size == (200, 200) | ||
|
||
# Getting a 300x150 thumbnail | ||
thumbnail = slide.get_thumbnail((300, 150)) | ||
assert isinstance(thumbnail, Image.Image) | ||
# The aspect ratio should be preserved, so width might be less than 300 | ||
assert thumbnail.size[1] == 150 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import argparse | ||
import pathlib | ||
from argparse import ArgumentTypeError | ||
from unittest.mock import patch | ||
|
||
import pytest | ||
|
||
from dlup.cli import dir_path, file_path, main | ||
|
||
|
||
def test_dir_path_valid_directory(tmpdir): | ||
path = tmpdir.mkdir("subdir") | ||
assert dir_path(str(path)) == pathlib.Path(path) | ||
|
||
|
||
def test_dir_path_invalid_directory(): | ||
with pytest.raises(ArgumentTypeError): | ||
dir_path("/path/which/does/not/exist") | ||
|
||
|
||
def test_file_path_valid_file(tmpdir): | ||
path = tmpdir.join("test_file.txt") | ||
path.write("content") | ||
assert file_path(str(path)) == pathlib.Path(path) | ||
|
||
|
||
def test_file_path_invalid_file(): | ||
with pytest.raises(ArgumentTypeError): | ||
file_path("/path/which/does/not/exist.txt") | ||
|
||
|
||
def test_file_path_no_need_exists(): | ||
_path = "/path/which/does/not/need/to/exist.txt" | ||
assert file_path(_path, need_exists=False) == pathlib.Path(_path) | ||
|
||
|
||
def test_main_no_arguments(capsys): | ||
with patch("sys.argv", ["dlup"]): | ||
with pytest.raises(SystemExit): | ||
main() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import logging | ||
|
||
import pytest | ||
|
||
from dlup.logging import build_cli_logger, setup_logging | ||
|
||
|
||
@pytest.mark.usefixtures("caplog") | ||
class TestLogging: | ||
def test_setup_logging_valid_log_level(self, caplog): | ||
setup_logging(log_level="DEBUG") | ||
assert len(caplog.records) == 0 | ||
|
||
def test_setup_logging_invalid_log_level(self): | ||
with pytest.raises(ValueError, match="Unexpected log level got INVALID"): | ||
setup_logging(log_level="INVALID") | ||
|
||
def test_setup_logging_filename_creation(self, tmp_path): | ||
log_file = tmp_path / "log.txt" | ||
setup_logging(filename=log_file) | ||
assert log_file.exists() | ||
|
||
def test_setup_logging_log_message(self, caplog): | ||
setup_logging(log_level="DEBUG") | ||
logging.debug("This is a debug message.") | ||
assert caplog.records[0].message == "This is a debug message." | ||
|
||
@pytest.mark.usefixtures("tmp_path") | ||
class TestCLILogger: | ||
def test_build_cli_logger_filename_creation(self, tmp_path): | ||
build_cli_logger("test_logger", True, 1, tmp_path) | ||
assert any(tmp_path.iterdir()) # checks if any file is created in tmp_path | ||
|
||
def test_build_cli_logger_valid_verbosity(self, caplog): | ||
build_cli_logger("test_logger", True, 1) | ||
logging.info("This is an info message.") | ||
assert caplog.records[-1].message == "This is an info message." | ||
|
||
def test_build_cli_logger_warning_message(self, caplog): | ||
build_cli_logger("test_logger", True, 1) | ||
assert ( | ||
caplog.records[0].message | ||
== "Beta software. In case you run into issues report at https://github.com/NKI-AI/dlup/." | ||
) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import json | ||
|
||
import numpy as np | ||
import pytest | ||
|
||
from dlup.utils import ArrayEncoder | ||
|
||
|
||
class TestArrayEncoder: | ||
def test_encode_numpy_array(self): | ||
arr = np.array([1, 2, 3, 4, 5]) | ||
result = json.dumps(arr, cls=ArrayEncoder) | ||
assert result == "[1, 2, 3, 4, 5]" | ||
|
||
def test_large_numpy_array_warning(self): | ||
large_arr = np.zeros(int(10e4 + 1)) | ||
with pytest.warns(UserWarning, match=r"Trying to JSON serialize a very large array"): | ||
json.dumps(large_arr, cls=ArrayEncoder) | ||
|
||
def test_encode_numpy_integers(self): | ||
int32_val = np.int32(42) | ||
int64_val = np.int64(42) | ||
result_int32 = json.dumps(int32_val, cls=ArrayEncoder) | ||
result_int64 = json.dumps(int64_val, cls=ArrayEncoder) | ||
assert result_int32 == "42" | ||
assert result_int64 == "42" | ||
|
||
def test_unhandled_data_type(self): | ||
with pytest.raises(TypeError, match=r"Object of type .* is not JSON serializable"): | ||
json.dumps({"key": object()}, cls=ArrayEncoder) # Here `object()` is an unhandled data type |