Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Add __repr__ and __str__ methods #209

Merged
merged 5 commits into from
Jun 26, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 60 additions & 0 deletions fissa/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,66 @@ def __init__(self, images, rois, folder=None, nRegions=4,
else:
self.load()

def __str__(self):
if isinstance(self.images, basestring):
str_images = repr(self.images)
elif isinstance(self.images, abc.Sequence):
str_images = "<{} of length {}>".format(
self.images.__class__.__name__, len(self.images)
)
else:
str_images = repr(self.images)

if isinstance(self.rois, basestring):
str_rois = repr(self.rois)
elif isinstance(self.rois, abc.Sequence):
str_rois = "<{} of length {}>".format(
self.rois.__class__.__name__, len(self.rois)
)
else:
str_images = repr(self.rois)

fields = [
"folder",
"nRegions",
"expansion",
"alpha",
"ncores_preparation",
"ncores_separation",
"method",
"datahandler",
]
str_parts = [
"{}={}".format(field, repr(getattr(self, field))) for field in fields
]
return "{}.{}(images={}, rois={}, {})".format(
__name__,
self.__class__.__name__,
str_images,
str_rois,
", ".join(str_parts),
)

def __repr__(self):
fields = [
"images",
"rois",
"folder",
"nRegions",
"expansion",
"alpha",
"ncores_preparation",
"ncores_separation",
"method",
"datahandler",
]
repr_parts = [
"{}={}".format(field, repr(getattr(self, field))) for field in fields
]
return "{}.{}({})".format(
__name__, self.__class__.__name__, ", ".join(repr_parts)
)

def clear(self):
r"""
Clear prepared data, and all data downstream of prepared data.
Expand Down
3 changes: 3 additions & 0 deletions fissa/extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class DataHandlerAbstract():
--------
DataHandlerTifffile, DataHandlerPillow
"""
def __repr__(self):
return "{}.{}()".format(__name__, self.__class__.__name__)

@staticmethod
def image2array(image):
"""
Expand Down
114 changes: 109 additions & 5 deletions fissa/tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os, os.path
import shutil
import sys
import types
import unittest

import numpy as np
Expand Down Expand Up @@ -90,7 +91,14 @@ def compare_output(self, actual, separated=True, compare_deltaf=None):
if compare_deltaf and separated:
self.compare_deltaf_result(actual.deltaf_result)

def compare_experiments(self, actual, expected, prepared=True, separated=True):
def compare_experiments(
self,
actual,
expected,
folder=True,
prepared=True,
separated=True,
):
"""
Compare attributes of two experiments.

Expand All @@ -100,13 +108,31 @@ def compare_experiments(self, actual, expected, prepared=True, separated=True):
Actual experiment.
expected : fissa.Experiment
Expected experiment.
folder : bool
Whether to compare the folder values. Default is ``True``.
prepared : bool
Whether to compare results of :meth:`fissa.Experiment.separation_prep`.
Default is ``True``.
separated : bool
Whether to compare results of :meth:`fissa.Experiment.separate`.
Default is ``True``.
"""
# We do all these comparisons explicitly one-by-one instead of in a
# for loop so you can see which one is failing.

# Check the parameters are the same
self.assert_equal(actual.images, expected.images)
self.assert_equal(actual.rois, expected.rois)
if folder:
self.assert_equal(actual.folder, expected.folder)
self.assert_equal(actual.nRegions, expected.nRegions)
self.assert_equal(actual.expansion, expected.expansion)
self.assert_equal(actual.alpha, expected.alpha)
self.assert_equal(actual.ncores_preparation, expected.ncores_preparation)
self.assert_equal(actual.ncores_separation, expected.ncores_separation)
self.assert_equal(actual.method, expected.method)
# self.assert_equal(actual.datahandler, expected.datahandler)

if prepared:
if expected.raw is None:
self.assertIs(actual.raw, expected.raw)
Expand Down Expand Up @@ -200,10 +226,80 @@ def compare_matlab_expected(self, fname, compare_deltaf=True):
self.expected["deltaf_raw"][0, 0],
)

def compare_str_repr_contents(self, actual, params=None):
print("ACTUAL: {}".format(actual))
self.assert_starts_with(actual, "fissa.core.Experiment(")
self.assertTrue(actual[-1] == ")")
self.assertTrue("images=" in actual)
self.assertTrue("rois=" in actual)
if not params:
return
for param, value in params.items():
expected = "{}={},".format(param, repr(value))
print("Testing presence of ~ {} ~".format(expected))
self.assertTrue(expected in actual)

def test_repr_class(self):
exp = core.Experiment(self.images_dir, self.roi_zip_path)
self.compare_str_repr_contents(repr(exp))

def test_str_class(self):
exp = core.Experiment(self.images_dir, self.roi_zip_path)
self.compare_str_repr_contents(str(exp))

def test_str_contains_stuff(self):
params = {
"nRegions": 7,
"expansion": 0.813962,
"alpha": 0.212827,
"ncores_preparation": 1,
"ncores_separation": None,
"method": "nmf",
}
exp = core.Experiment(self.images_dir, self.roi_zip_path, **params)
self.compare_str_repr_contents(str(exp), params)

def test_repr_contains_stuff(self):
params = {
"nRegions": 7,
"expansion": 0.813962,
"alpha": 0.212827,
"ncores_preparation": 1,
"ncores_separation": None,
"method": "nmf",
}
exp = core.Experiment(self.images_dir, self.roi_zip_path, **params)
self.compare_str_repr_contents(repr(exp), params)

def test_repr_eval(self):
params = {
"nRegions": 7,
"expansion": 0.813962,
"alpha": 0.212827,
"ncores_preparation": 1,
"ncores_separation": None,
"method": "nmf",
}
exp = core.Experiment(self.images_dir, self.roi_zip_path, **params)
actual = repr(exp)
# We've done relative imports to test the current version of the code,
# but the repr string expects to be able to find packages at fissa.
# To solve this, we make a dummy package named fissa and put aliases
# to core and extraction on it, so eval can find them.
fissa = types.ModuleType("DummyFissa")
fissa.core = core
fissa.extraction = extraction
print("Evaluating: {}".format(actual))
exp2 = eval(actual)
self.compare_experiments(exp, exp2)


def test_imagedir_roizip(self):
exp = core.Experiment(self.images_dir, self.roi_zip_path)
exp.separate()
self.compare_output(exp)
self.compare_str_repr_contents(str(exp))
self.compare_str_repr_contents(repr(exp))

def test_imagelist_roizip(self):
image_paths = [
Expand All @@ -213,6 +309,8 @@ def test_imagelist_roizip(self):
exp = core.Experiment(image_paths, self.roi_zip_path)
exp.separate()
self.compare_output(exp)
self.compare_str_repr_contents(str(exp))
self.compare_str_repr_contents(repr(exp))

def test_imagelistloaded_roizip(self):
image_paths = [
Expand All @@ -224,6 +322,8 @@ def test_imagelistloaded_roizip(self):
exp = core.Experiment(images, self.roi_zip_path)
exp.separate()
self.compare_output(exp)
self.compare_str_repr_contents(str(exp))
self.compare_str_repr_contents(repr(exp))

@unittest.expectedFailure
def test_imagedir_roilistpath(self):
Expand All @@ -234,6 +334,8 @@ def test_imagedir_roilistpath(self):
exp = core.Experiment(self.images_dir, roi_paths)
exp.separate()
self.compare_output(exp)
self.compare_str_repr_contents(str(exp))
self.compare_str_repr_contents(repr(exp))

@unittest.expectedFailure
def test_imagelist_roilistpath(self):
Expand All @@ -248,6 +350,8 @@ def test_imagelist_roilistpath(self):
exp = core.Experiment(image_paths, roi_paths)
exp.separate()
self.compare_output(exp)
self.compare_str_repr_contents(str(exp))
self.compare_str_repr_contents(repr(exp))

def test_nocache(self):
exp = core.Experiment(self.images_dir, self.roi_zip_path)
Expand Down Expand Up @@ -490,7 +594,7 @@ def test_load_manual_prep(self):
exp = core.Experiment(image_path, roi_path, new_folder)
exp.load(os.path.join(prev_folder, "preparation.npz"))
# Cached prep should now be loaded correctly
self.compare_experiments(exp, exp1)
self.compare_experiments(exp, exp1, folder=False)

def test_load_manual_sep(self):
"""Loading prep results from a different folder."""
Expand All @@ -505,7 +609,7 @@ def test_load_manual_sep(self):
exp = core.Experiment(image_path, roi_path, new_folder)
exp.load(os.path.join(prev_folder, "separated.npz"))
# Cached results should now be loaded correctly
self.compare_experiments(exp, exp1, prepared=False)
self.compare_experiments(exp, exp1, folder=False, prepared=False)

def test_load_manual_directory(self):
"""Loading results from a different folder."""
Expand All @@ -520,7 +624,7 @@ def test_load_manual_directory(self):
exp = core.Experiment(image_path, roi_path, new_folder)
exp.load(prev_folder)
# Cache should now be loaded correctly
self.compare_experiments(exp, exp1)
self.compare_experiments(exp, exp1, folder=False)

def test_load_manual(self):
"""Loading results from a different folder."""
Expand All @@ -539,7 +643,7 @@ def test_load_manual(self):
# Manually trigger loading the new cache
exp.load()
# Cache should now be loaded correctly
self.compare_experiments(exp, exp1)
self.compare_experiments(exp, exp1, folder=False)

def test_load_empty_prep(self):
"""Behaviour when loading a prep cache that is empty."""
Expand Down
17 changes: 17 additions & 0 deletions fissa/tests/test_extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,23 @@ def test_multiframe_mean_higherdim_pillow(base_fname, shp, dtype, datahandler):
datahandler=datahandler,
)

class TestDataHandlerRepr(BaseTestCase):
"""String representations of DataHandler are correct."""

def test_repr_tifffile(self):
datahandler = extraction.DataHandlerTifffile()
self.assert_equal(repr(datahandler), "fissa.extraction.DataHandlerTifffile()")

def test_repr_tifffile_lazy(self):
datahandler = extraction.DataHandlerTifffileLazy()
self.assert_equal(
repr(datahandler), "fissa.extraction.DataHandlerTifffileLazy()"
)

def test_repr_pillow(self):
datahandler = extraction.DataHandlerPillow()
self.assert_equal(repr(datahandler), "fissa.extraction.DataHandlerPillow()")


class Rois2MasksTestMixin:
"""Tests for rois2masks."""
Expand Down