diff --git a/src/spatialexperiment/SpatialImage.py b/src/spatialexperiment/SpatialImage.py index 925327a..3a90872 100644 --- a/src/spatialexperiment/SpatialImage.py +++ b/src/spatialexperiment/SpatialImage.py @@ -10,10 +10,10 @@ import biocutils as ut import numpy as np import requests -from PIL import Image +from PIL import Image, ImageChops -__author__ = "jkanche" -__copyright__ = "jkanche" +__author__ = "jkanche, keviny2" +__copyright__ = "jkanche, keviny2" __license__ = "MIT" @@ -24,6 +24,21 @@ class VirtualSpatialImage(ABC): def __init__(self, metadata: Optional[dict] = None): self._metadata = metadata if metadata is not None else {} + ######################### + ######>> Equality <<##### + ######################### + + def __eq__(self, other) -> bool: + if not isinstance(other, type(self)): + return False + + return self.metadata == other.metadata + + def __hash__(self): + # Note: This exists primarily to support lru_cache. + # Generally, these classes are mutable and shouldn't be used as dict keys or in sets. + return hash(frozenset(self._metadata.items())) + ########################### ######>> metadata <<####### ########################### @@ -151,6 +166,18 @@ def _define_output(self, in_place: bool = False) -> "LoadedSpatialImage": else: return self.__copy__() + ######################### + ######>> Equality <<##### + ######################### + + def __eq__(self, other) -> bool: + diff = ImageChops.difference(self.image, other.image) + + return super().__eq__(other) and not diff.getbbox() + + def __hash__(self): + return hash((super().__hash__(), self._image.tobytes())) + ######################### ######>> Copying <<###### ######################### @@ -294,6 +321,16 @@ def _define_output(self, in_place: bool = False) -> "LoadedSpatialImage": else: return self.__copy__() + ######################### + ######>> Equality <<##### + ######################### + + def __eq__(self, other): + return super().__eq__(other) and self.path == other.path + + def __hash__(self): + return hash((super().__hash__(), str(self._path))) + ######################### ######>> Copying <<###### ######################### @@ -454,6 +491,16 @@ def _define_output(self, in_place: bool = False) -> "RemoteSpatialImage": else: return self.__copy__() + ######################### + ######>> Equality <<##### + ######################### + + def __eq__(self, other) -> bool: + return super().__eq__(other) and self.url == other.url + + def __hash__(self): + return hash((super().__hash__(), self._url)) + ######################### ######>> Copying <<###### ######################### diff --git a/tests/test_img_data_methods.py b/tests/test_img_data_methods.py index a626afd..d36ef4c 100644 --- a/tests/test_img_data_methods.py +++ b/tests/test_img_data_methods.py @@ -60,7 +60,7 @@ def test_add_img(spe): image_id="unsplash", ) - tspe.img_data.shape[0] == spe.img_data.shape[0] + 1 + assert tspe.img_data.shape[0] == spe.img_data.shape[0] + 1 def test_add_img_already_exists(spe): diff --git a/tests/test_si.py b/tests/test_si.py deleted file mode 100644 index 09503a2..0000000 --- a/tests/test_si.py +++ /dev/null @@ -1,48 +0,0 @@ -import pytest -from PIL import Image -from spatialexperiment import construct_spatial_image_class -from spatialexperiment.SpatialImage import VirtualSpatialImage, StoredSpatialImage, LoadedSpatialImage, RemoteSpatialImage - -__author__ = "keviny2" -__copyright__ = "keviny2" -__license__ = "MIT" - - -def test_si_constructor_path(): - si = construct_spatial_image_class("tests/images/sample_image1.jpg", is_url=False) - - assert issubclass(type(si), VirtualSpatialImage) - assert isinstance(si, StoredSpatialImage) - - assert "tests/images/sample_image1.jpg" in str(si.path) - assert si.path is not None - - -def test_si_constructor_si(): - si_1 = construct_spatial_image_class("tests/images/sample_image1.jpg", is_url=False) - si_2 = construct_spatial_image_class(si_1, is_url=False) - - assert issubclass(type(si_2), VirtualSpatialImage) - assert isinstance(si_2, StoredSpatialImage) - - assert str(si_1.path) == str(si_2.path) - - -def test_si_constructor_image(): - image = Image.open("tests/images/sample_image2.png") - si = construct_spatial_image_class(image, is_url=False) - - assert issubclass(type(si), VirtualSpatialImage) - assert isinstance(si, LoadedSpatialImage) - - assert si.image == image - - -def test_invalid_input(): - si_remote = construct_spatial_image_class("https://i.redd.it/3pw5uah7xo041.jpg", is_url=True) - assert issubclass(type(si_remote), VirtualSpatialImage) - assert isinstance(si_remote, RemoteSpatialImage) - assert si_remote.url == "https://i.redd.it/3pw5uah7xo041.jpg" - - with pytest.raises(Exception): - construct_spatial_image_class(5, is_url=False) diff --git a/tests/test_spi.py b/tests/test_spi.py new file mode 100644 index 0000000..a05c3ed --- /dev/null +++ b/tests/test_spi.py @@ -0,0 +1,72 @@ +import pytest +from PIL import Image +from spatialexperiment import construct_spatial_image_class +from spatialexperiment.SpatialImage import VirtualSpatialImage, StoredSpatialImage, LoadedSpatialImage, RemoteSpatialImage + +__author__ = "keviny2" +__copyright__ = "keviny2" +__license__ = "MIT" + + +def test_spi_constructor_path(): + spi = construct_spatial_image_class("tests/images/sample_image1.jpg", is_url=False) + + assert issubclass(type(spi), VirtualSpatialImage) + assert isinstance(spi, StoredSpatialImage) + + assert "tests/images/sample_image1.jpg" in str(spi.path) + + +def test_spi_constructor_spi(): + spi_1 = construct_spatial_image_class("tests/images/sample_image1.jpg", is_url=False) + spi_2 = construct_spatial_image_class(spi_1, is_url=False) + + assert issubclass(type(spi_2), VirtualSpatialImage) + assert isinstance(spi_2, StoredSpatialImage) + + assert str(spi_1.path) == str(spi_2.path) + + +def test_spi_constructor_image(): + image = Image.open("tests/images/sample_image2.png") + spi = construct_spatial_image_class(image, is_url=False) + + assert issubclass(type(spi), VirtualSpatialImage) + assert isinstance(spi, LoadedSpatialImage) + + assert spi.image == image + + +def test_spi_constructor_url(): + image_url = "https://i.redd.it/3pw5uah7xo041.jpg" + spi_remote = construct_spatial_image_class(image_url, is_url=True) + assert issubclass(type(spi_remote), VirtualSpatialImage) + assert isinstance(spi_remote, RemoteSpatialImage) + assert spi_remote.url == image_url + + +def test_invalid_input(): + with pytest.raises(Exception): + construct_spatial_image_class(5, is_url=False) + +def test_spi_equality(): + spi_path_1 = construct_spatial_image_class("tests/images/sample_image1.jpg", is_url=False) + spi_path_2 = construct_spatial_image_class("tests/images/sample_image1.jpg", is_url=False) + + assert spi_path_1 == spi_path_2 + + image_url = "https://i.redd.it/3pw5uah7xo041.jpg" + spi_url_1 = construct_spatial_image_class(image_url, is_url=True) + spi_url_2 = construct_spatial_image_class(image_url, is_url=True) + + assert spi_url_1 == spi_url_2 + + image = Image.open("tests/images/sample_image2.png") + spi_image_1 = construct_spatial_image_class(image, is_url=False) + spi_image_2 = construct_spatial_image_class(image, is_url=False) + + assert spi_image_1 == spi_image_2 + + assert spi_path_1 != spi_url_1 + assert spi_path_1 != spi_image_1 + assert spi_url_1 != spi_image_1