-
Notifications
You must be signed in to change notification settings - Fork 10
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: Improve test suite for PartSegCore
#1077
Changes from all commits
3a42584
003b7bd
ef6cfea
86c8213
6a48d66
6690abc
87e7711
b318b7c
99d656f
a56b7f9
4415840
5f720d8
8f9bbde
c64aa2f
787c556
0701e71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import warnings | ||
from math import acos, pi, sqrt | ||
|
||
import numpy as np | ||
|
@@ -41,14 +42,15 @@ def find_density_orientation(img, voxel_size, cutoff=1): | |
return vectors, w_n | ||
|
||
|
||
def get_rotation_parameters(isometric_matrix): | ||
def get_rotation_parameters(isometric_matrix): # pragma: no cover | ||
""" | ||
If 3x3 isometric matrix is not rotation matrix | ||
function transform it into rotation matrix | ||
then calculate rotation axis and angel | ||
:param isometric_matrix: 3x3 np.ndarray with determinant equal 1 or -1 | ||
:return: rotation_matrix, rotation axis, rotation angel | ||
""" | ||
warnings.warn("This function is deprecated", FutureWarning, stacklevel=2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding a deprecation warning to |
||
if np.linalg.det(isometric_matrix) < 0: | ||
isometric_matrix = np.dot(np.diag([-1, 1, 1]), isometric_matrix) | ||
angel = acos((np.sum(np.diag(isometric_matrix)) - 1) / 2) * 180 / pi | ||
|
@@ -78,7 +80,7 @@ def density_mass_center(image, voxel_size=(1.0, 1.0, 1.0)): | |
|
||
if len(voxel_size) != image.ndim: | ||
if len(voxel_size) != len(iter_dim): | ||
raise ValueError("Cannot fit voxel size to array") | ||
raise ValueError("Cannot fit voxel size to array") # pragma: no cover | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Excluding the exception handling from test coverage with |
||
voxel_size_array = [0] * image.ndim | ||
for i, item in enumerate(iter_dim): | ||
voxel_size_array[item] = voxel_size[i] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import io | ||
import json | ||
import os | ||
import re | ||
|
@@ -42,7 +43,7 @@ def check_segmentation_type(tar_file: TarFile) -> SegmentationType: | |
return SegmentationType.analysis | ||
if "metadata.json" in names: | ||
return SegmentationType.mask | ||
raise WrongFileTypeException | ||
raise WrongFileTypeException # pragma: no cover | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (llm): Consider providing a specific error message to |
||
|
||
|
||
def get_tarinfo(name, buffer: typing.Union[BytesIO, StringIO]): | ||
|
@@ -56,7 +57,23 @@ def get_tarinfo(name, buffer: typing.Union[BytesIO, StringIO]): | |
return tar_info | ||
|
||
|
||
class SaveBase(AlgorithmDescribeBase, ABC): | ||
class _IOBase(AlgorithmDescribeBase, ABC): | ||
@classmethod | ||
def get_name_with_suffix(cls): | ||
return cls.get_name() | ||
|
||
@classmethod | ||
def get_extensions(cls) -> typing.List[str]: | ||
match = re.match(r".*\((.*)\)", cls.get_name()) | ||
if match is None: | ||
raise ValueError(f"No extensions found in {cls.get_name()}") | ||
extensions = match[1].split(" ") | ||
if not all(x.startswith("*.") for x in extensions): | ||
raise ValueError(f"Error with parsing extensions in {cls.get_name()}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (llm): The error message for parsing extensions is clear, but consider including the incorrect extension format in the message to aid in debugging. |
||
return [x[1:] for x in extensions] | ||
Comment on lines
+60
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The methods |
||
|
||
|
||
class SaveBase(_IOBase, ABC): | ||
need_functions: typing.ClassVar[typing.List[str]] = [ | ||
"save", | ||
"get_short_name", | ||
|
@@ -91,15 +108,6 @@ def save( | |
""" | ||
raise NotImplementedError | ||
|
||
@classmethod | ||
def get_name_with_suffix(cls): | ||
return cls.get_name() | ||
|
||
@classmethod | ||
def get_default_extension(cls): | ||
match = re.search(r"\(\*(\.\w+)", cls.get_name_with_suffix()) | ||
return match[1] if match else "" | ||
|
||
@classmethod | ||
def need_segmentation(cls): | ||
return True | ||
|
@@ -109,23 +117,17 @@ def need_mask(cls): | |
return False | ||
|
||
@classmethod | ||
def get_extensions(cls) -> typing.List[str]: | ||
match = re.match(r".*\((.*)\)", cls.get_name()) | ||
if match is None: | ||
raise ValueError(f"No extensions found in {cls.get_name()}") | ||
extensions = match[1].split(" ") | ||
if not all(x.startswith("*.") for x in extensions): | ||
raise ValueError(f"Error with parsing extensions in {cls.get_name()}") | ||
return [x[1:] for x in extensions] | ||
def get_default_extension(cls): | ||
match = re.search(r"\(\*(\.\w+)", cls.get_name_with_suffix()) | ||
return match[1] if match else "" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question (llm): The use of regex for extracting the default extension is efficient. However, ensure that the regex pattern is robust enough to handle all expected formats of
Comment on lines
+120
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method |
||
|
||
|
||
class LoadBase(AlgorithmDescribeBase, ABC): | ||
class LoadBase(_IOBase, ABC): | ||
need_functions: typing.ClassVar[typing.List[str]] = [ | ||
"load", | ||
"get_short_name", | ||
"get_name_with_suffix", | ||
"number_of_files", | ||
"correct_files_order", | ||
"get_next_file", | ||
"partial", | ||
] | ||
|
@@ -155,20 +157,6 @@ def load( | |
""" | ||
raise NotImplementedError | ||
|
||
@classmethod | ||
def get_name_with_suffix(cls): | ||
return cls.get_name() | ||
|
||
@classmethod | ||
def get_extensions(cls) -> typing.List[str]: | ||
match = re.match(r".*\((.*)\)", cls.get_name()) | ||
if match is None: | ||
raise ValueError(f"No extensions found in {cls.get_name()}") | ||
extensions = match[1].split(" ") | ||
if not all(x.startswith("*.") for x in extensions): | ||
raise ValueError(f"Error with parsing extensions in {cls.get_name()}") | ||
return [x[1:] for x in extensions] | ||
|
||
@classmethod | ||
def get_fields(cls): | ||
return [] | ||
|
@@ -178,10 +166,6 @@ def number_of_files(cls): | |
"""Number of files required for load method""" | ||
return 1 | ||
|
||
@classmethod | ||
def correct_files_order(cls, paths): | ||
return paths | ||
|
||
@classmethod | ||
def get_next_file(cls, file_paths: typing.List[str]): | ||
return file_paths[0] | ||
|
@@ -192,19 +176,19 @@ def partial(cls): | |
return False | ||
|
||
|
||
def load_metadata_base(data: typing.Union[str, Path]): | ||
def load_metadata_base(data: typing.Union[str, Path, typing.TextIO]): | ||
try: | ||
if isinstance(data, typing.TextIO): | ||
if isinstance(data, io.TextIOBase): | ||
decoded_data = json.load(data, object_hook=partseg_object_hook) | ||
elif os.path.exists(data): | ||
with open(data, encoding="utf-8") as ff: | ||
decoded_data = json.load(ff, object_hook=partseg_object_hook) | ||
else: | ||
decoded_data = json.loads(data, object_hook=partseg_object_hook) | ||
except ValueError as e: | ||
except ValueError as e: # pragma: no cover | ||
try: | ||
decoded_data = json.loads(str(data), object_hook=partseg_object_hook) | ||
except Exception: # pragma: no cover | ||
except Exception: | ||
raise e # noqa: B904 | ||
|
||
return decoded_data | ||
|
@@ -299,7 +283,7 @@ def open_tar_file( | |
tar_file = TarFile.open(fileobj=file_data) | ||
file_path = "" | ||
else: | ||
raise ValueError(f"wrong type of file_ argument: {type(file_data)}") | ||
raise ValueError(f"wrong type of file_data argument: {type(file_data)}") | ||
return tar_file, file_path | ||
|
||
|
||
|
@@ -325,13 +309,14 @@ def save( | |
cls, | ||
save_location: typing.Union[str, BytesIO, Path], | ||
project_info, | ||
parameters: dict, | ||
parameters: typing.Optional[dict] = None, | ||
range_changed=None, | ||
step_changed=None, | ||
): | ||
if project_info.image.mask is None and project_info.mask is not None: | ||
ImageWriter.save_mask(project_info.image.substitute(mask=project_info.mask), save_location) | ||
ImageWriter.save_mask(project_info.image, save_location) | ||
else: | ||
ImageWriter.save_mask(project_info.image, save_location) | ||
|
||
|
||
def tar_to_buff(tar_file, member_name) -> BytesIO: | ||
|
@@ -352,7 +337,7 @@ def save( | |
cls, | ||
save_location: typing.Union[str, BytesIO, Path], | ||
project_info, | ||
parameters: dict, | ||
parameters: typing.Optional[dict] = None, | ||
range_changed=None, | ||
step_changed=None, | ||
): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,9 +95,9 @@ def partseg_loader(loader: typing.Type[LoadBase], path: str): | |
|
||
try: | ||
project_info = loader.load(load_locations) | ||
except WrongFileTypeException: | ||
except WrongFileTypeException: # pragma: no cover | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The use of |
||
return None | ||
|
||
if isinstance(project_info, (ProjectTuple, MaskProjectTuple)): | ||
return project_to_layers(project_info) | ||
return None | ||
return None # pragma: no cover | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The return statement at the end of the function is excluded from test coverage with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file contains complex classes with multiple methods and properties. Consider adding comprehensive docstrings to public methods and classes to improve maintainability and understandability.
+ Add comprehensive docstrings to public methods and classes.
The dynamic creation of models using
create_model
in_GetDescriptionClass
is an advanced feature. Ensure that this dynamic behavior is well-documented and tested to avoid confusion and potential bugs.+ Improve documentation and testing for dynamic model creation in _GetDescriptionClass.
The implementation of custom metaclasses, such as
AlgorithmDescribeBaseMeta
andAddRegisterMeta
, introduces complexity. Verify that their use is justified and consider simplifying the design if possible.+ Evaluate the necessity of custom metaclasses and consider simplifying the design.