From 224e93aca60faccfd268dace10ac52551e648570 Mon Sep 17 00:00:00 2001 From: James Meakin Date: Wed, 12 Feb 2020 07:01:19 +0100 Subject: [PATCH] Adds flake8 --- .pre-commit-config.yaml | 12 + docs/conf.py | 3 +- evalutils/__init__.py | 2 +- evalutils/cli.py | 1 - evalutils/evalutils.py | 27 ++- evalutils/io.py | 6 +- evalutils/stats.py | 2 +- .../algorithm/hooks/post_gen_project.py | 3 +- .../evaluation/hooks/post_gen_project.py | 2 +- evalutils/utils.py | 2 +- setup.cfg | 2 +- setup.py | 7 +- tests/test_algorithm.py | 12 +- tests/test_io.py | 4 +- tests/test_stats.py | 229 +++++++++--------- tests/test_validators.py | 4 +- 16 files changed, 173 insertions(+), 145 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 088e8f7..a19d0da 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,18 @@ repos: hooks: - id: black language: python + - repo: https://gitlab.com/pycqa/flake8 + rev: 3.7.9 + hooks: + - id: flake8 + language: python + additional_dependencies: + - flake8-bugbear + - flake8-import-order + - pep8-naming + # The following is disabled due to a runtime error + # - flake8-docstrings + - mccabe - repo: https://github.com/mgedmin/check-manifest rev: "0.40" hooks: diff --git a/docs/conf.py b/docs/conf.py index 6e28252..04688e6 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ sys.path.insert(0, os.path.abspath("..")) -import evalutils +import evalutils # noqa: E402 # -- General configuration --------------------------------------------- @@ -83,6 +83,7 @@ # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False + # Always document the __init__ method def skip(app, what, name, obj, skip, options): if name == "__init__": diff --git a/evalutils/__init__.py b/evalutils/__init__.py index ca6717f..63091ff 100644 --- a/evalutils/__init__.py +++ b/evalutils/__init__.py @@ -1,9 +1,9 @@ from .__version__ import __version__ as _version from .evalutils import ( + BaseAlgorithm, ClassificationEvaluation, DetectionEvaluation, Evaluation, - BaseAlgorithm, ) __author__ = """James Meakin""" diff --git a/evalutils/cli.py b/evalutils/cli.py index 9d6063c..5136d9c 100644 --- a/evalutils/cli.py +++ b/evalutils/cli.py @@ -1,5 +1,4 @@ import re - from pathlib import Path import click diff --git a/evalutils/evalutils.py b/evalutils/evalutils.py index c316dcd..05c8f98 100644 --- a/evalutils/evalutils.py +++ b/evalutils/evalutils.py @@ -3,19 +3,26 @@ from abc import ABC, abstractmethod from os import PathLike from pathlib import Path -from typing import Tuple, Dict, Set, Callable, List, Union, Pattern +from typing import Callable, Dict, List, Pattern, Set, Tuple, Union from warnings import warn -from pandas import DataFrame, merge, Series, concat +from pandas import DataFrame, Series, concat, merge -from .exceptions import FileLoaderError, ValidationError, ConfigurationError -from .io import first_int_in_filename_key, FileLoader, CSVLoader +from .exceptions import ConfigurationError, FileLoaderError, ValidationError +from .io import CSVLoader, FileLoader, first_int_in_filename_key from .scorers import score_detection from .validators import DataFrameValidator logger = logging.getLogger(__name__) +DEFAULT_INPUT_PATH = Path("/input/") +DEFAULT_ALGORITHM_OUTPUT_IMAGES_PATH = Path("/output/images/") +DEFAULT_ALGORITHM_OUTPUT_FILE_PATH = Path("/output/results.json") +DEFAULT_GROUND_TRUTH_PATH = Path("/opt/evaluation/ground-truth/") +DEFAULT_EVALUATION_OUTPUT_FILE_PATH = Path("/output/metrics.json") + + class BaseAlgorithm(ABC): def __init__( self, @@ -23,11 +30,11 @@ def __init__( index_key: str, file_loaders: Dict[str, FileLoader], file_filters: Dict[str, Pattern[str]] = None, - input_path: Path = Path("/input/"), - output_path: Path = Path("/output/images/"), + input_path: Path = DEFAULT_INPUT_PATH, + output_path: Path = DEFAULT_ALGORITHM_OUTPUT_IMAGES_PATH, file_sorter_key: Callable = None, validators: Dict[str, Tuple[DataFrameValidator, ...]], - output_file: PathLike = Path("/output/results.json"), + output_file: PathLike = DEFAULT_ALGORITHM_OUTPUT_FILE_PATH, ): """ The base class for all algorithms. Sets the environment and controls @@ -159,14 +166,14 @@ class BaseEvaluation(ABC): def __init__( self, *, - ground_truth_path: Path = Path("/opt/evaluation/ground-truth/"), - predictions_path: Path = Path("/input/"), + ground_truth_path: Path = DEFAULT_GROUND_TRUTH_PATH, + predictions_path: Path = DEFAULT_INPUT_PATH, file_sorter_key: Callable = first_int_in_filename_key, file_loader: FileLoader, validators: Tuple[DataFrameValidator, ...], join_key: str = None, aggregates: Set[str] = None, - output_file: PathLike = Path("/output/metrics.json"), + output_file: PathLike = DEFAULT_EVALUATION_OUTPUT_FILE_PATH, ): """ The base class for all evaluations. Sets the environment and controls diff --git a/evalutils/io.py b/evalutils/io.py index 6c57caf..2dec773 100644 --- a/evalutils/io.py +++ b/evalutils/io.py @@ -2,12 +2,12 @@ import re from abc import ABC, abstractmethod from pathlib import Path -from typing import Union, Dict, List +from typing import Dict, List, Union -from SimpleITK import ReadImage, GetArrayFromImage +from SimpleITK import GetArrayFromImage, ReadImage from imageio import imread from pandas import read_csv -from pandas.errors import ParserError, EmptyDataError +from pandas.errors import EmptyDataError, ParserError from .exceptions import FileLoaderError diff --git a/evalutils/stats.py b/evalutils/stats.py index a1c2abe..c873d7d 100644 --- a/evalutils/stats.py +++ b/evalutils/stats.py @@ -8,7 +8,7 @@ from scipy.ndimage.morphology import binary_erosion, generate_binary_structure -def distance_transform_edt_float32( +def distance_transform_edt_float32( # noqa: C901 input, sampling=None, return_distances=True, diff --git a/evalutils/templates/algorithm/hooks/post_gen_project.py b/evalutils/templates/algorithm/hooks/post_gen_project.py index e451fb3..06e345b 100644 --- a/evalutils/templates/algorithm/hooks/post_gen_project.py +++ b/evalutils/templates/algorithm/hooks/post_gen_project.py @@ -1,12 +1,12 @@ import os import shutil from pathlib import Path + from evalutils.utils import ( bootstrap_development_distribution, convert_line_endings, ) - ALGORITHM_NAME = "{{ cookiecutter.algorithm_name }}" IS_DEV_BUILD = int("{{ cookiecutter.dev_build }}") == 1 @@ -16,7 +16,6 @@ for f in templated_python_files: shutil.move(f.name, f.stem) - convert_line_endings() if IS_DEV_BUILD: diff --git a/evalutils/templates/evaluation/hooks/post_gen_project.py b/evalutils/templates/evaluation/hooks/post_gen_project.py index a68f1de..002d89c 100644 --- a/evalutils/templates/evaluation/hooks/post_gen_project.py +++ b/evalutils/templates/evaluation/hooks/post_gen_project.py @@ -1,6 +1,7 @@ import os import shutil from pathlib import Path + from evalutils.utils import ( bootstrap_development_distribution, convert_line_endings, @@ -45,7 +46,6 @@ def remove_detection_files(): if CHALLENGE_KIND.lower() != "classification": remove_classification_files() - convert_line_endings() if IS_DEV_BUILD: diff --git a/evalutils/utils.py b/evalutils/utils.py index c425bed..2aae715 100644 --- a/evalutils/utils.py +++ b/evalutils/utils.py @@ -1,5 +1,5 @@ -from pathlib import Path import shutil +from pathlib import Path EOL_UNIX = b"\n" EOL_WIN = b"\r\n" diff --git a/setup.cfg b/setup.cfg index 11b2d66..dcbb23e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ collect_ignore = ['setup.py'] [flake8] application-import-names = - gcapi + evalutils tests import-order-style = pycharm docstring-convention = numpy diff --git a/setup.py b/setup.py index 53e3bd4..832f453 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ import os -from setuptools import setup, find_packages +from setuptools import find_packages, setup NAME = "evalutils" REQUIRES_PYTHON = ">=3.6.0" @@ -46,7 +46,10 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", ], - description="evalutils helps challenge administrators easily create evaluation containers for grand-challenge.org.", + description=( + "evalutils helps challenge administrators easily create evaluation " + "containers for grand-challenge.org." + ), extras_require={"test": test_requirements}, install_requires=requirements, license="MIT license", diff --git a/tests/test_algorithm.py b/tests/test_algorithm.py index b31aa28..5022bde 100644 --- a/tests/test_algorithm.py +++ b/tests/test_algorithm.py @@ -1,16 +1,18 @@ +import json +import os +import re +import shutil from pathlib import Path + import SimpleITK -import shutil import numpy as np from pandas import DataFrame -import re -import os -import json + from evalutils import BaseAlgorithm from evalutils.io import SimpleITKLoader from evalutils.validators import ( - UniquePathIndicesValidator, UniqueImagesValidator, + UniquePathIndicesValidator, ) diff --git a/tests/test_io.py b/tests/test_io.py index 5e6053a..e89e63d 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -7,11 +7,11 @@ from evalutils.exceptions import FileLoaderError from evalutils.io import ( - get_first_int_in, - ImageIOLoader, CSVLoader, + ImageIOLoader, SimpleITKLoader, first_int_in_filename_key, + get_first_int_in, ) diff --git a/tests/test_stats.py b/tests/test_stats.py index 9a85c4e..c99a6aa 100644 --- a/tests/test_stats.py +++ b/tests/test_stats.py @@ -1,4 +1,4 @@ -import SimpleITK as sitk +import SimpleITK import numpy as np import pytest import scipy.ndimage as ndimage @@ -16,16 +16,16 @@ def reset_seeds(): @pytest.mark.parametrize( - "Y_true", [np.random.randint(0, 2, (30, 20, 10)).astype(np.int)] + "y_true", [np.random.randint(0, 2, (30, 20, 10)).astype(np.int)] ) @pytest.mark.parametrize( - "Y_pred", [np.random.randint(0, 2, (30, 20, 10)).astype(np.int)] + "y_pred", [np.random.randint(0, 2, (30, 20, 10)).astype(np.int)] ) @pytest.mark.parametrize("labels", [[0], [0, 1], [0, 2], [0, 1, 2]]) -def test_calculate_confusion_matrix(Y_true, Y_pred, labels): - result = stats.calculate_confusion_matrix(Y_true, Y_pred, labels) +def test_calculate_confusion_matrix(y_true, y_pred, labels): + result = stats.calculate_confusion_matrix(y_true, y_pred, labels) result2 = sklearn.metrics.confusion_matrix( - Y_true.flatten(), Y_pred.flatten(), labels + y_true.flatten(), y_pred.flatten(), labels ) assert result.shape[0] == len(labels) and result.shape[1] == len(labels) assert np.equal(result, result2).all() @@ -64,10 +64,10 @@ def test_dice_from_cm(): def test_ravd(): - A = np.array([[1, 0, 0], [1, 1, 1], [0, 1, 1]], dtype=np.bool) - B = np.array([[1, 0, 1], [1, 0, 1], [0, 0, 1]], dtype=np.bool) - r1 = stats.relative_absolute_volume_difference(A, B) - r2 = stats.relative_absolute_volume_difference(B, A) + a = np.array([[1, 0, 0], [1, 1, 1], [0, 1, 1]], dtype=np.bool) + b = np.array([[1, 0, 1], [1, 0, 1], [0, 0, 1]], dtype=np.bool) + r1 = stats.relative_absolute_volume_difference(a, b) + r2 = stats.relative_absolute_volume_difference(b, a) assert r1 != r2 assert r1 == (6.0 - 5.0) / 6.0 assert r2 == (6.0 - 5.0) / 5.0 @@ -75,21 +75,22 @@ def test_ravd(): @pytest.mark.parametrize("voxelspace", [None, (0.3, 0.8)]) def test_avd(voxelspace): - A = np.array([[1, 0, 0], [1, 1, 1], [0, 1, 1]], dtype=np.bool) - B = np.array([[1, 0, 1], [1, 0, 1], [0, 0, 1]], dtype=np.bool) - r1 = stats.absolute_volume_difference(A, B, voxelspace) - r2 = stats.absolute_volume_difference(B, A, voxelspace) + a = np.array([[1, 0, 0], [1, 1, 1], [0, 1, 1]], dtype=np.bool) + b = np.array([[1, 0, 1], [1, 0, 1], [0, 0, 1]], dtype=np.bool) + r1 = stats.absolute_volume_difference(a, b, voxelspace) + r2 = stats.absolute_volume_difference(b, a, voxelspace) assert r1 == r2 assert r1 == (6.0 - 5.0) * ( 1 if voxelspace is None else np.prod(voxelspace) ) -# A connectivity of 1 was omitted, because the HausdorffDistanceImageFilter does not support it. -# A connectivity of 0 and 2 appear to achieve similar Hausdorff metrics, although only one is used within the -# HausdorffDistanceImageFilter +# A connectivity of 1 was omitted, because the HausdorffDistanceImageFilter +# does not support it. +# A connectivity of 0 and 2 appear to achieve similar Hausdorff metrics, +# although only one is used within the HausdorffDistanceImageFilter @pytest.mark.parametrize( - "A,B", + "a,b", [ [ np.random.randint(0, 2, (6, 6), dtype=np.bool), @@ -124,22 +125,22 @@ def test_avd(voxelspace): ) @pytest.mark.parametrize("voxelspace", [None, (0.3, 0.8), (12.0, 4.0)]) @pytest.mark.parametrize("connectivity", [0, 2]) -def test_hd(A, B, voxelspace, connectivity): - hd = stats.hausdorff_distance(A, B, voxelspace, connectivity=connectivity) - hd2 = stats.hausdorff_distance(B, A, voxelspace, connectivity=connectivity) +def test_hd(a, b, voxelspace, connectivity): + hd = stats.hausdorff_distance(a, b, voxelspace, connectivity=connectivity) + hd2 = stats.hausdorff_distance(b, a, voxelspace, connectivity=connectivity) assert hd == hd2 - A2 = sitk.GetImageFromArray(A.astype(np.uint8)) - B2 = sitk.GetImageFromArray(B.astype(np.uint8)) + a2 = SimpleITK.GetImageFromArray(a.astype(np.uint8)) + b2 = SimpleITK.GetImageFromArray(b.astype(np.uint8)) if voxelspace is None: voxelspace = [1, 1] - A2.SetSpacing(voxelspace[::-1]) - B2.SetSpacing(voxelspace[::-1]) - hdfilter = sitk.HausdorffDistanceImageFilter() - hdfilter.Execute(A2, B2) + a2.SetSpacing(voxelspace[::-1]) + b2.SetSpacing(voxelspace[::-1]) + hdfilter = SimpleITK.HausdorffDistanceImageFilter() + hdfilter.Execute(a2, b2) hd3 = hdfilter.GetHausdorffDistance() - hdfilter.Execute(B2, A2) + hdfilter.Execute(b2, a2) hd4 = hdfilter.GetHausdorffDistance() assert np.isclose(hd, hd3) @@ -147,7 +148,7 @@ def test_hd(A, B, voxelspace, connectivity): @pytest.mark.parametrize( - "A,B", + "a,b", [ [ np.random.randint(0, 2, (6, 6), dtype=np.bool), @@ -158,13 +159,13 @@ def test_hd(A, B, voxelspace, connectivity): ) @pytest.mark.parametrize("voxelspace", [None, (0.3, 0.8)]) @pytest.mark.parametrize("connectivity", [0, 1, 2]) -def test_modified_hd(A, B, voxelspace, connectivity): - dA = sitk_surface_distance(A, B, voxelspace, connectivity) - dB = sitk_surface_distance(B, A, voxelspace, connectivity) - mhd = max(dA.mean(), dB.mean()) +def test_modified_hd(a, b, voxelspace, connectivity): + d_a = sitk_surface_distance(a, b, voxelspace, connectivity) + d_b = sitk_surface_distance(b, a, voxelspace, connectivity) + mhd = max(d_a.mean(), d_b.mean()) - mhd2 = stats.modified_hausdorff_distance(A, B, voxelspace, connectivity) - mhd3 = stats.modified_hausdorff_distance(B, A, voxelspace, connectivity) + mhd2 = stats.modified_hausdorff_distance(a, b, voxelspace, connectivity) + mhd3 = stats.modified_hausdorff_distance(b, a, voxelspace, connectivity) assert np.isclose(mhd, mhd2) assert np.isclose(mhd, mhd3) @@ -172,7 +173,7 @@ def test_modified_hd(A, B, voxelspace, connectivity): @pytest.mark.parametrize( - "A,B", + "a,b", [ [ np.random.randint(0, 2, (6, 6), dtype=np.bool), @@ -184,21 +185,21 @@ def test_modified_hd(A, B, voxelspace, connectivity): @pytest.mark.parametrize("voxelspace", [None, (0.3, 0.8)]) @pytest.mark.parametrize("connectivity", [0, 1, 2]) @pytest.mark.parametrize("percentile", [0, 0.8, 0.95, 1]) -def test_percentile_hd(A, B, voxelspace, connectivity, percentile): - dA = sitk_surface_distance(A, B, voxelspace, connectivity) - dB = sitk_surface_distance(B, A, voxelspace, connectivity) - dA.sort() - dB.sort() +def test_percentile_hd(a, b, voxelspace, connectivity, percentile): + d_a = sitk_surface_distance(a, b, voxelspace, connectivity) + d_b = sitk_surface_distance(b, a, voxelspace, connectivity) + d_a.sort() + d_b.sort() phd = max( - dA[int((len(dA) - 1) * percentile)], - dB[int((len(dB) - 1) * percentile)], + d_a[int((len(d_a) - 1) * percentile)], + d_b[int((len(d_b) - 1) * percentile)], ) phd2 = stats.percentile_hausdorff_distance( - A, B, percentile, voxelspace, connectivity + a, b, percentile, voxelspace, connectivity ) phd3 = stats.percentile_hausdorff_distance( - B, A, percentile, voxelspace, connectivity + b, a, percentile, voxelspace, connectivity ) assert np.isclose(phd, phd2) @@ -207,7 +208,7 @@ def test_percentile_hd(A, B, voxelspace, connectivity, percentile): @pytest.mark.parametrize( - "A,B", + "a,b", [ [ np.random.randint(0, 2, (6, 6), dtype=np.bool), @@ -217,100 +218,104 @@ def test_percentile_hd(A, B, voxelspace, connectivity, percentile): ], ) @pytest.mark.parametrize("voxelspace", [None, (0.3, 0.8)]) -def test_mean_contour_distance(A, B, voxelspace): - dA = sitk_directed_contour_distance(A, B, voxelspace) - dB = sitk_directed_contour_distance(B, A, voxelspace) - mhd = max(dA.mean(), dB.mean()) +def test_mean_contour_distance(a, b, voxelspace): + d_a = sitk_directed_contour_distance(a, b, voxelspace) + d_b = sitk_directed_contour_distance(b, a, voxelspace) + mhd = max(d_a.mean(), d_b.mean()) - mhd2 = stats.mean_contour_distance(A, B, voxelspace) - mhd3 = stats.mean_contour_distance(B, A, voxelspace) + mhd2 = stats.mean_contour_distance(a, b, voxelspace) + mhd3 = stats.mean_contour_distance(b, a, voxelspace) assert np.isclose(mhd, mhd2) assert np.isclose(mhd, mhd3) assert mhd2 == mhd3 -def sitk_surface_distance(A, B, voxelspace, connectivity): - A2 = sitk.GetImageFromArray((A == 1).astype(np.uint8)) - B2 = sitk.GetImageFromArray((B == 1).astype(np.uint8)) +def sitk_surface_distance(a, b, voxelspace, connectivity): + a2 = SimpleITK.GetImageFromArray((a == 1).astype(np.uint8)) + b2 = SimpleITK.GetImageFromArray((b == 1).astype(np.uint8)) if voxelspace is None: voxelspace = [1, 1] - A2.SetSpacing(voxelspace[::-1]) - B2.SetSpacing(voxelspace[::-1]) + a2.SetSpacing(voxelspace[::-1]) + b2.SetSpacing(voxelspace[::-1]) if connectivity > 0: - eroder = sitk.BinaryErodeImageFilter() + eroder = SimpleITK.BinaryErodeImageFilter() eroder.SetBackgroundValue(0) eroder.SetKernelType( - sitk.sitkCross if connectivity <= 1 else sitk.sitkBox + SimpleITK.sitkCross if connectivity <= 1 else SimpleITK.sitkBox ) eroder.SetKernelRadius(1) eroder.BoundaryToForegroundOff() - A2 = sitk.And(A2, sitk.InvertIntensity(eroder.Execute(A2), maximum=1)) - B2 = sitk.And(B2, sitk.InvertIntensity(eroder.Execute(B2), maximum=1)) + a2 = SimpleITK.And( + a2, SimpleITK.InvertIntensity(eroder.Execute(a2), maximum=1) + ) + b2 = SimpleITK.And( + b2, SimpleITK.InvertIntensity(eroder.Execute(b2), maximum=1) + ) - padf = sitk.ConstantPadImageFilter() + padf = SimpleITK.ConstantPadImageFilter() padf.SetConstant(0) padf.SetPadLowerBound((1, 1)) padf.SetPadUpperBound((1, 1)) - B2p = padf.Execute(B2) + b2p = padf.Execute(b2) - f = sitk.SignedMaurerDistanceMapImageFilter() + f = SimpleITK.SignedMaurerDistanceMapImageFilter() f.SetUseImageSpacing(True) f.SetBackgroundValue(1) f.InsideIsPositiveOn() f.SetSquaredDistance(False) - D = -sitk.GetArrayFromImage( - f.Execute(sitk.InvertIntensity(B2p, maximum=1)) + d = -SimpleITK.GetArrayFromImage( + f.Execute(SimpleITK.InvertIntensity(b2p, maximum=1)) )[1:-1, :][:, 1:-1] - D[D < 0] = 0 + d[d < 0] = 0 - return D[sitk.GetArrayFromImage(A2) == 1] + return d[SimpleITK.GetArrayFromImage(a2) == 1] -def sitk_directed_contour_distance(A, B, voxelspace): - A2 = sitk.GetImageFromArray((A == 1).astype(np.uint8)) - B2 = sitk.GetImageFromArray((B == 1).astype(np.uint8)) +def sitk_directed_contour_distance(a, b, voxelspace): + a2 = SimpleITK.GetImageFromArray((a == 1).astype(np.uint8)) + b2 = SimpleITK.GetImageFromArray((b == 1).astype(np.uint8)) if voxelspace is None: voxelspace = [1, 1] - A2.SetSpacing(voxelspace[::-1]) - B2.SetSpacing(voxelspace[::-1]) + a2.SetSpacing(voxelspace[::-1]) + b2.SetSpacing(voxelspace[::-1]) - footprint = generate_binary_structure(A.ndim, A.ndim) - footprint = sitk.GetImageFromArray(footprint.astype(np.uint8)) - conv = sitk.ConvolutionImageFilter() + footprint = generate_binary_structure(a.ndim, a.ndim) + footprint = SimpleITK.GetImageFromArray(footprint.astype(np.uint8)) + conv = SimpleITK.ConvolutionImageFilter() conv.SetBoundaryCondition( BoundaryCondition=1 ) # ZeroFluxNeumannBoundaryCondition enum conv.NormalizeOff() - mask = sitk.GetArrayFromImage(conv.Execute(A2, footprint)) < np.sum( + mask = SimpleITK.GetArrayFromImage(conv.Execute(a2, footprint)) < np.sum( footprint ) - padf = sitk.ConstantPadImageFilter() + padf = SimpleITK.ConstantPadImageFilter() padf.SetConstant(0) padf.SetPadLowerBound((1, 1)) padf.SetPadUpperBound((1, 1)) - B2p = padf.Execute(B2) + b2p = padf.Execute(b2) - f = sitk.SignedMaurerDistanceMapImageFilter() + f = SimpleITK.SignedMaurerDistanceMapImageFilter() f.SetUseImageSpacing(True) f.SetBackgroundValue(1) f.InsideIsPositiveOn() f.SetSquaredDistance(False) - D = -sitk.GetArrayFromImage( - f.Execute(sitk.InvertIntensity(B2p, maximum=1)) + d = -SimpleITK.GetArrayFromImage( + f.Execute(SimpleITK.InvertIntensity(b2p, maximum=1)) )[1:-1, :][:, 1:-1] - D[D < 0] = 0 + d[d < 0] = 0 - return D[(sitk.GetArrayFromImage(A2) == 1) & mask] + return d[(SimpleITK.GetArrayFromImage(a2) == 1) & mask] @pytest.mark.parametrize( - "A,B", + "a,b", [ [ np.random.randint(0, 2, (6, 6), dtype=np.bool), @@ -320,11 +325,11 @@ def sitk_directed_contour_distance(A, B, voxelspace): ], ) @pytest.mark.parametrize("voxelspace", [None, (0.3, 0.8)]) -def test_directed_contour_distance(A, B, voxelspace): - sd = stats.__directed_contour_distances(A, B, voxelspace) - sd2 = stats.__directed_contour_distances(B, A, voxelspace) - sd3 = sitk_directed_contour_distance(A, B, voxelspace) - sd4 = sitk_directed_contour_distance(B, A, voxelspace) +def test_directed_contour_distance(a, b, voxelspace): + sd = stats.__directed_contour_distances(a, b, voxelspace) + sd2 = stats.__directed_contour_distances(b, a, voxelspace) + sd3 = sitk_directed_contour_distance(a, b, voxelspace) + sd4 = sitk_directed_contour_distance(b, a, voxelspace) assert len(sd) == len(sd3) and np.allclose(sd, sd3) assert len(sd2) == len(sd4) and np.allclose(sd2, sd4) @@ -332,7 +337,7 @@ def test_directed_contour_distance(A, B, voxelspace): @pytest.mark.parametrize( - "A,B", + "a,b", [ [ np.random.randint(0, 2, (6, 6), dtype=np.bool), @@ -343,13 +348,13 @@ def test_directed_contour_distance(A, B, voxelspace): ) @pytest.mark.parametrize("voxelspace", [None, (0.3, 0.8)]) @pytest.mark.parametrize("connectivity", [0, 1, 2]) -def test_surface_distance(A, B, voxelspace, connectivity): - sd = stats.__surface_distances(A, B, voxelspace, connectivity=connectivity) +def test_surface_distance(a, b, voxelspace, connectivity): + sd = stats.__surface_distances(a, b, voxelspace, connectivity=connectivity) sd2 = stats.__surface_distances( - B, A, voxelspace, connectivity=connectivity + b, a, voxelspace, connectivity=connectivity ) - sd3 = sitk_surface_distance(A, B, voxelspace, connectivity) - sd4 = sitk_surface_distance(B, A, voxelspace, connectivity) + sd3 = sitk_surface_distance(a, b, voxelspace, connectivity) + sd4 = sitk_surface_distance(b, a, voxelspace, connectivity) assert len(sd) == len(sd3) and np.allclose(sd, sd3) assert len(sd2) == len(sd4) and np.allclose(sd2, sd4) @@ -357,26 +362,26 @@ def test_surface_distance(A, B, voxelspace, connectivity): @pytest.mark.parametrize( - "A", [np.random.randint(0, 2, (30, 20, 10)).astype(np.bool)] + "a", [np.random.randint(0, 2, (30, 20, 10)).astype(np.bool)] ) @pytest.mark.parametrize( - "B", [np.random.randint(0, 2, (30, 20, 10)).astype(np.bool)] + "b", [np.random.randint(0, 2, (30, 20, 10)).astype(np.bool)] ) @pytest.mark.parametrize("voxelspace", [None]) # , (0.3, 0.8, 1.2)]) @pytest.mark.parametrize("connectivity", [0, 1, 2]) -def test_hd_and_contour_functions(A, B, voxelspace, connectivity): - r1 = stats.hausdorff_distance(A, B, voxelspace, connectivity) - r2 = stats.percentile_hausdorff_distance(A, B, 1, voxelspace, connectivity) - r3 = stats.modified_hausdorff_distance(A, B, voxelspace, connectivity) +def test_hd_and_contour_functions(a, b, voxelspace, connectivity): + r1 = stats.hausdorff_distance(a, b, voxelspace, connectivity) + r2 = stats.percentile_hausdorff_distance(a, b, 1, voxelspace, connectivity) + r3 = stats.modified_hausdorff_distance(a, b, voxelspace, connectivity) r4 = stats.percentile_hausdorff_distance( - A, B, 0.95, voxelspace, connectivity + a, b, 0.95, voxelspace, connectivity ) - r5 = stats.relative_absolute_volume_difference(A, B) - r6 = stats.relative_absolute_volume_difference(B, A) - r7 = stats.mean_contour_distance(A, B, voxelspace) - r8 = stats.mean_contour_distance(B, A, voxelspace) + r5 = stats.relative_absolute_volume_difference(a, b) + r6 = stats.relative_absolute_volume_difference(b, a) + r7 = stats.mean_contour_distance(a, b, voxelspace) + r8 = stats.mean_contour_distance(b, a, voxelspace) r = stats.hausdorff_distance_measures( - A, B, voxelspace, connectivity, percentile=0.95 + a, b, voxelspace, connectivity, percentile=0.95 ) r9 = r.distance r10 = r.percentile_distance @@ -394,11 +399,11 @@ def test_hd_and_contour_functions(A, B, voxelspace, connectivity): assert r1 != r7 -@pytest.mark.parametrize("A", [np.random.randint(0, 3, (30, 20, 10))]) -@pytest.mark.parametrize("B", [np.random.randint(0, 3, (30, 20, 10))]) +@pytest.mark.parametrize("a", [np.random.randint(0, 3, (30, 20, 10))]) +@pytest.mark.parametrize("b", [np.random.randint(0, 3, (30, 20, 10))]) @pytest.mark.parametrize("classes", [[0, 1, 2]]) -def test_cm_functions(A, B, classes): - cm = stats.calculate_confusion_matrix(A, B, classes) +def test_cm_functions(a, b, classes): + cm = stats.calculate_confusion_matrix(a, b, classes) r1 = stats.dice_from_confusion_matrix(cm) r2 = stats.jaccard_from_confusion_matrix(cm) r3 = stats.jaccard_to_dice(r2) diff --git a/tests/test_validators.py b/tests/test_validators.py index d3171d0..5c41844 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -6,10 +6,10 @@ from evalutils.exceptions import ValidationError from evalutils.io import ImageIOLoader from evalutils.validators import ( - UniquePathIndicesValidator, ExpectedColumnNamesValidator, - UniqueImagesValidator, NumberOfCasesValidator, + UniqueImagesValidator, + UniquePathIndicesValidator, )