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

test: Add tests files to calcualate coverage #655

Merged
merged 9 commits into from
Jun 21, 2022
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test_prereleases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
with:
python-version: ${{ matrix.python }}
cache: 'pip'
cache-dependency-path: 'requirements/requirements_pyinstaller.txt'

- name: Install Windows OpenGL
if: runner.os == 'Windows'
Expand Down Expand Up @@ -104,7 +105,6 @@ jobs:
name: Install Python 3.9
with:
python-version: 3.9
cache: 'pip'
- name: Install ubuntu libraries
if: runner.os == 'Linux'
run: |
Expand Down
4 changes: 4 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ coverage:
target: auto
threshold: 0.5% # coverage can drop by up to 0.5% while still posting success
paths: [ 'package/PartSegImage/.*' ]
Tests:
target: auto
threshold: 1% # coverage can drop by up to 0.5% while still posting success
paths: [ 'package/tests/.*' ]
comment:
require_changes: true # if true: only post the PR comment if coverage changes
14 changes: 2 additions & 12 deletions package/tests/test_PartSeg/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from contextlib import suppress

import pytest
from qtpy.QtWidgets import QApplication, QDialog, QMessageBox
from qtpy.QtWidgets import QDialog, QMessageBox

from PartSeg._roi_analysis.partseg_settings import PartSettings
from PartSeg._roi_mask.main_window import ChosenComponents
Expand Down Expand Up @@ -133,16 +133,6 @@ def clean_settings():
yield


@pytest.fixture
def leaked_widgets():
initial = QApplication.topLevelWidgets()
yield
QApplication.processEvents()
leak = set(QApplication.topLevelWidgets()).difference(initial)
if any(n.__class__.__name__ != "CanvasBackendDesktop" for n in leak):
raise AssertionError(f"Widgets ({len(leak)}) leaked!: {leak}")


@pytest.fixture(autouse=True)
def reset_napari_settings(monkeypatch, tmp_path):
def _mock_save(self, path=None, **dict_kwargs):
Expand All @@ -161,7 +151,7 @@ def _mock_save(self, path=None, **dict_kwargs):
@pytest.fixture(autouse=True)
def block_message_box(monkeypatch, request):
def raise_on_call(*_, **__):
raise RuntimeError("exec_ call")
raise RuntimeError("exec_ call") # pragma: no cover

monkeypatch.setattr(QMessageBox, "exec_", raise_on_call)
monkeypatch.setattr(QMessageBox, "critical", raise_on_call)
Expand Down
4 changes: 0 additions & 4 deletions package/tests/test_PartSeg/test_check_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ def urlopen_mock(url):
)
)

def message_box_block(self, *args):
raise RuntimeError(f"call of message box {self.text()}")

monkeypatch.setattr(urllib.request, "urlopen", urlopen_mock)
monkeypatch.setattr(check_version.QMessageBox, "exec_", message_box_block)
assert packaging.version.parse("0.10.0") < packaging.version.parse("0.11.0")
chk_thr = check_version.CheckVersionThread(package_name, base_version="0.11.0")
chk_thr.release = "0.10.0"
Expand Down
19 changes: 2 additions & 17 deletions package/tests/test_PartSeg/test_common_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,11 @@ def __init__(self, raise_=False, return_none=False):

@classmethod
def support_time(cls):
return False
return False # for class interfce, # pragma: no cover

@classmethod
def support_z(cls):
return True
return True # for class interfce, # pragma: no cover

def calculation_run(self, report_fun: Callable[[str, int], None]) -> Optional[ROIExtractionResult]:
if self.raise_:
Expand Down Expand Up @@ -389,14 +389,8 @@ class TestDict(partially_const_dict.PartiallyConstDict):


class TestLoadBackup:
@staticmethod
def block_exec(*args, **kwargs):
raise RuntimeError("aa")

def test_no_backup(self, monkeypatch, tmp_path):
monkeypatch.setattr(load_backup.state_store, "save_folder", tmp_path)
monkeypatch.setattr(load_backup.QMessageBox, "exec_", self.block_exec)
monkeypatch.setattr(load_backup.QMessageBox, "question", self.block_exec)
monkeypatch.setattr(load_backup, "parsed_version", parse("0.13.13"))
load_backup.import_config()

Expand All @@ -405,8 +399,6 @@ def test_no_backup(self, monkeypatch, tmp_path):

def test_no_backup_old(self, monkeypatch, tmp_path):
monkeypatch.setattr(load_backup.state_store, "save_folder", tmp_path / "0.13.13")
monkeypatch.setattr(load_backup.QMessageBox, "exec_", self.block_exec)
monkeypatch.setattr(load_backup.QMessageBox, "question", self.block_exec)
monkeypatch.setattr(load_backup, "parsed_version", parse("0.13.13"))
(tmp_path / "0.13.14").mkdir()
(tmp_path / "0.13.15").mkdir()
Expand All @@ -425,7 +417,6 @@ def question(*args, **kwargs):
return response

monkeypatch.setattr(load_backup.state_store, "save_folder", tmp_path / "0.13.13")
monkeypatch.setattr(load_backup.QMessageBox, "exec_", self.block_exec)
monkeypatch.setattr(load_backup.QMessageBox, "question", question)
monkeypatch.setattr(load_backup, "parsed_version", parse("0.13.13"))
create_file(tmp_path / "0.13.14" / "14.txt")
Expand All @@ -441,12 +432,6 @@ def question(*args, **kwargs):
assert not (tmp_path / "0.13.13").exists()


class NapariSettingsMock:
@staticmethod
def load():
return 1


@pytest.fixture
def image(tmp_path):
data = np.random.random((10, 10, 2))
Expand Down
6 changes: 3 additions & 3 deletions package/tests/test_PartSeg/test_window_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@
def test_analysis_import():
try:
import PartSeg._roi_analysis.main_window # noqa: F401
except ImportError:
except ImportError: # pragma: no cover
pytest.fail("Error in importing segmentation ui")


def test_launcher_import():
try:
import PartSeg._launcher.main_window # noqa: F401
except ImportError:
except ImportError: # pragma: no cover
pytest.fail("Error in importing launcher ui")


def test_segmentation_import():
try:
import PartSeg._roi_mask.main_window # noqa: F401
except ImportError:
except ImportError: # pragma: no cover
pytest.fail("Error in importing mask segmentation ui")


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ def get_fields(cls) -> typing.List[typing.Union[AlgorithmProperty, str]]:
]

assert SampleSubAlgorithm.get_name() == "sample2"
assert SampleAlgorithm.get_name() == "sample"
with pytest.warns(FutureWarning, match=r"Class has __argument_class__ defined"):
assert len(SampleSubAlgorithm.get_fields()) == 3
with pytest.warns(FutureWarning, match=r"Class has __argument_class__ defined"):
Expand Down
37 changes: 9 additions & 28 deletions package/tests/test_PartSegCore/test_analysis_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import shutil
import sys
import time
import warnings
from glob import glob

import numpy as np
import pandas as pd
import pytest

Expand Down Expand Up @@ -40,8 +40,8 @@
from PartSegCore.mask_create import MaskProperty
from PartSegCore.segmentation.noise_filtering import DimensionType
from PartSegCore.segmentation.restartable_segmentation_algorithms import LowerThresholdFlowAlgorithm
from PartSegCore.universal_const import UNIT_SCALE, Units
from PartSegImage import Image, ImageWriter, TiffImageReader
from PartSegCore.universal_const import Units
from PartSegImage import TiffImageReader

ENGINE = None if pd.__version__ == "0.24.0" else "openpyxl"

Expand All @@ -51,25 +51,6 @@ def __init__(self, file_path):
self.file_path = file_path


@pytest.fixture
def create_test_data(tmpdir):
# for future use
spacing = tuple(x / UNIT_SCALE[Units.nm.value] for x in (210, 70, 70))
res = []
for i in range(8):
mask_data = np.zeros((10, 20, 20 + i), dtype=np.uint8)
mask_data[1:-1, 2:-2, 2:-2] = 1
data = np.zeros(mask_data.shape + (2,), dtype=np.uint16)
data[1:-1, 2:-2, 2:-2] = 15000
data[2:-2, 3:-3, 3:7] = 33000
data[2:-2, 3:-3, -7:-3] = 33000
image = Image(data, spacing, "", mask=mask_data, axes_order="ZYXC")
ImageWriter.save(image, os.path.join(str(tmpdir), f"file_{i}.tif"))
res.append(os.path.join(str(tmpdir), f"file_{i}.tif"))
ImageWriter.save_mask(image, os.path.join(str(tmpdir), f"file_{i}_mask.tif"))
return res


# TODO add check of per component measurements

# noinspection DuplicatedCode
Expand Down Expand Up @@ -453,13 +434,13 @@ def test_full_pipeline(self, tmpdir, data_test_dir, monkeypatch):
time.sleep(0.1)
else:
break
else:
else: # pragma: no cover
manager.kill_jobs()
pytest.fail("jobs hanged")

manager.writer.finish()
if sys.platform == "darwin":
time.sleep(2)
time.sleep(2) # pragma: no cover
else:
time.sleep(0.4)
assert os.path.exists(os.path.join(tmpdir, "test.xlsx"))
Expand Down Expand Up @@ -503,7 +484,7 @@ def test_full_pipeline_error(self, tmp_path, data_test_dir, monkeypatch):
manager.get_results()
manager.writer.finish()
if sys.platform == "darwin":
time.sleep(2)
time.sleep(2) # pragma: no cover
else:
time.sleep(0.4)
assert os.path.exists(os.path.join(result_dir, "test.xlsx"))
Expand Down Expand Up @@ -538,7 +519,7 @@ def test_full_pipeline_mask_project(self, tmpdir, data_test_dir):
time.sleep(0.1)
manager.get_results()
if sys.platform == "darwin":
time.sleep(2)
time.sleep(2) # pragma: no cover
else:
time.sleep(0.4)
manager.writer.finish()
Expand Down Expand Up @@ -660,9 +641,9 @@ def test_full_pipeline_component_split(self, tmpdir, data_test_dir):
time.sleep(0.1)
res = manager.get_results()
if res.errors:
print(res.errors, file=sys.stderr)
warnings.warn(str(res.errors)) # pragma: no cover
if sys.platform == "darwin":
time.sleep(2)
time.sleep(2) # pragma: no cover
else:
time.sleep(0.4)
manager.writer.finish()
Expand Down
4 changes: 2 additions & 2 deletions package/tests/test_PartSegCore/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def test_profile_load(self, data_test_dir):
with open(profile_path) as ff:
data = json.load(ff, object_hook=partseg_object_hook)
assert check_loaded_dict(data)
except Exception: # pylint: disable=W0703
except Exception: # pylint: disable=W0703 # pragma: no cover
pytest.fail("Fail in loading profile")

def test_measure_load(self, data_test_dir):
Expand All @@ -277,7 +277,7 @@ def test_measure_load(self, data_test_dir):
with open(profile_path) as ff:
data = json.load(ff, object_hook=partseg_object_hook)
assert check_loaded_dict(data)
except Exception: # pylint: disable=W0703
except Exception: # pylint: disable=W0703 # pragma: no cover
pytest.fail("Fail in loading profile")

def test_json_dump(self):
Expand Down
10 changes: 0 additions & 10 deletions package/tests/test_PartSegCore/test_measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,6 @@ def cube_image_fixture():
return get_cube_image()


@pytest.fixture
def cube_mask_40(cube_image):
return cube_image.get_channel(0)[0] > 40


@pytest.fixture
def cube_mask_60(cube_image):
return cube_image.get_channel(0)[0] > 60


def get_square_image():
return Image(get_cube_array()[:, 25:26], (100, 50, 50), "", axes_order="TZYX")

Expand Down
2 changes: 1 addition & 1 deletion package/tests/test_PartSegCore/test_mso.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ def test_two_components_bridge(self):
arr[2:8, 2:8, 11:18] = 3
assert np.all(res == arr)

def _test_background_simple(self):
def test_background_simple(self):
components = np.ones((20, 20, 20), dtype=np.uint8)
components[1:-1, 1:-1, 1:-1] = 0
components[9:11, 9:11, 9:11] = 2
Expand Down
4 changes: 2 additions & 2 deletions package/tests/test_PartSegCore/test_segmentation_proceses.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


def empty(_a, _b):
pass
pass # pragma: no cover


class TestSegmentation:
Expand All @@ -24,7 +24,7 @@ def test_profile_execute(self, data_test_dir):
try:
data = load_metadata_base(profile_path)
assert check_loaded_dict(data)
except Exception: # pylint: disable=W0703
except Exception: # pylint: disable=W0703 # pragma: no cover
pytest.fail("Fail in loading profile")
return
image = TiffImageReader.read_image(
Expand Down
4 changes: 2 additions & 2 deletions package/tests/test_PartSegCore/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ def fun(self): # pylint: disable=R0201

def test_get_callback():
def call_fun():
return 1
raise NotImplementedError

class A:
def fun(self): # pylint: disable=R0201
return 1
raise NotImplementedError

a = A()

Expand Down
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ test =
tox

[tool:pytest]
addopts = --cov=PartSeg --cov=PartSegCore --cov PartSegImage --maxfail=5 --durations=5
addopts = --maxfail=5 --durations=5
testpaths = package/tests
junit_family = legacy
timeout = 900
Expand Down Expand Up @@ -159,6 +159,7 @@ exclude_lines =
pragma: no cover
raise NotImplementedError
if typing.TYPE_CHECKING
raise RuntimeError()

[flake8]
max-line-length = 120
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ deps =
repo: git+https://github.com/napari/napari.git
commands =
!repo: python -m pytest -v package/tests/test_PartSeg/test_napari_widgets.py --no-cov
repo: python -m pytest --no-cov
repo: python -m pytest --no-cov .

[testenv:py{37,38,39}-PyQt5-coverage]
deps =
{[testenv]deps}
commands =
python -m pytest --cov-report=xml --cov-report html --cov-append --cov {envsitepackagesdir}/PartSeg --cov {envsitepackagesdir}/PartSegCore --cov {envsitepackagesdir}/PartSegImage
python -m pytest --cov-report=xml --cov-report html --cov-append --cov {envsitepackagesdir}/PartSeg --cov {envsitepackagesdir}/PartSegCore --cov {envsitepackagesdir}/PartSegImage --cov package/tests
codecov

[testenv:py37-PyQt5-minimal]
Expand Down