class TestPartSettingsIO: @pytest.mark.parametrize("method", analysis_save_dict.values()) def test_save(self, method, qtbot, part_settings_with_project, tmp_path): pi = part_settings_with_project.get_project_info() method.save(tmp_path / "data", pi, method.get_default_values()) def test_load_segmentation(self, part_settings, data_test_dir): path = os.path.join(data_test_dir, "stack1_component1_1.tgz") pi = LoadProject.load([path]) part_settings.set_project_info(pi) @pytest.mark.parametrize( "file_name", [ "Image0003_01.oif", "test_czi.czi", "test_lsm.lsm", "test_lsm.tif", "test_lsm2.tif", "test_nucleus.tif", "test_nucleus_mask.tif", ], ) def test_load_images(self, file_name, part_settings, data_test_dir): path = os.path.join(data_test_dir, file_name) pi = LoadStackImage.load([path]) assert isinstance(pi, ProjectTuple) part_settings.set_project_info(pi) def test_load_images_with_mask(self, part_settings, data_test_dir): base_path = Path(os.path.join(data_test_dir, "stack1_components")) pi = LoadImageMask.load([ base_path / "stack1_component1.tif", base_path / "stack1_component1_mask.tif" ]) assert isinstance(pi, ProjectTuple) part_settings.set_project_info(pi) def test_load_mask_project(self, part_settings, data_test_dir): path = os.path.join(data_test_dir, "test_nucleus.seg") pi_l = LoadMaskSegmentation.load([path]) assert isinstance(pi_l, list) for pi in pi_l: part_settings.set_project_info(pi)
def __init__(self, settings: PartSettings): super().__init__() self.settings = settings self.save_translate_dict: typing.Dict[str, SaveBase] = {x.get_short_name(): x for x in save_dict.values()} self.plan = PlanPreview(self) self.save_plan_btn = QPushButton("Save") self.clean_plan_btn = QPushButton("Remove all") self.remove_btn = QPushButton("Remove") self.update_element_chk = QCheckBox("Update element") self.change_root = EnumComboBox(RootType) self.save_choose = QComboBox() self.save_choose.addItem("<none>") self.save_choose.addItems(list(self.save_translate_dict.keys())) self.save_btn = QPushButton("Save") self.segment_profile = SearchableListWidget() self.pipeline_profile = SearchableListWidget() self.segment_stack = QTabWidget() self.segment_stack.addTab(self.segment_profile, "Profile") self.segment_stack.addTab(self.pipeline_profile, "Pipeline") self.generate_mask_btn = QPushButton("Add mask") self.generate_mask_btn.setToolTip("Mask need to have unique name") self.mask_name = QLineEdit() self.mask_operation = EnumComboBox(MaskOperation) self.chanel_num = QSpinBox() self.choose_channel_for_measurements = QComboBox() self.choose_channel_for_measurements.addItems( ["Same as segmentation"] + [str(x + 1) for x in range(MAX_CHANNEL_NUM)] ) self.units_choose = EnumComboBox(Units) self.units_choose.set_value(self.settings.get("units_value", Units.nm)) self.chanel_num.setRange(0, 10) self.expected_node_type = None self.save_constructor = None self.chose_profile_btn = QPushButton("Add Profile") self.get_big_btn = QPushButton("Leave the biggest") self.get_big_btn.hide() self.get_big_btn.setDisabled(True) self.measurements_list = SearchableListWidget(self) self.measurement_name_prefix = QLineEdit(self) self.add_calculation_btn = QPushButton("Add measurement calculation") self.information = QTextEdit() self.information.setReadOnly(True) self.protect = False self.mask_set = set() self.calculation_plan = CalculationPlan() self.plan.set_plan(self.calculation_plan) self.segmentation_mask = MaskWidget(settings) self.file_mask = FileMask() self.change_root.currentIndexChanged.connect(self.change_root_type) self.save_choose.currentTextChanged.connect(self.save_changed) self.measurements_list.currentTextChanged.connect(self.show_measurement) self.segment_profile.currentTextChanged.connect(self.show_segment) self.measurements_list.currentTextChanged.connect(self.show_measurement_info) self.segment_profile.currentTextChanged.connect(self.show_segment_info) self.pipeline_profile.currentTextChanged.connect(self.show_segment_info) self.pipeline_profile.currentTextChanged.connect(self.show_segment) self.mask_name.textChanged.connect(self.mask_name_changed) self.generate_mask_btn.clicked.connect(self.create_mask) self.clean_plan_btn.clicked.connect(self.clean_plan) self.remove_btn.clicked.connect(self.remove_element) self.mask_name.textChanged.connect(self.mask_text_changed) self.chose_profile_btn.clicked.connect(self.add_segmentation) self.get_big_btn.clicked.connect(self.add_leave_biggest) self.add_calculation_btn.clicked.connect(self.add_measurement) self.save_plan_btn.clicked.connect(self.add_calculation_plan) # self.forgot_mask_btn.clicked.connect(self.forgot_mask) # self.cmap_save_btn.clicked.connect(self.save_to_cmap) self.save_btn.clicked.connect(self.add_save_to_project) self.update_element_chk.stateChanged.connect(self.mask_text_changed) self.update_element_chk.stateChanged.connect(self.show_measurement) self.update_element_chk.stateChanged.connect(self.show_segment) self.update_element_chk.stateChanged.connect(self.update_names) self.segment_stack.currentChanged.connect(self.change_segmentation_table) plan_box = QGroupBox("Prepare workflow:") lay = QVBoxLayout() lay.addWidget(self.plan) bt_lay = QGridLayout() bt_lay.setSpacing(1) bt_lay.addWidget(self.save_plan_btn, 0, 0) bt_lay.addWidget(self.clean_plan_btn, 0, 1) bt_lay.addWidget(self.remove_btn, 1, 0) bt_lay.addWidget(self.update_element_chk, 1, 1) lay.addLayout(bt_lay) plan_box.setLayout(lay) plan_box.setStyleSheet(group_sheet) other_box = QGroupBox("Other operations:") other_box.setContentsMargins(0, 0, 0, 0) bt_lay = QVBoxLayout() bt_lay.setSpacing(0) bt_lay.addWidget(QLabel("Root type:")) bt_lay.addWidget(self.change_root) bt_lay.addStretch(1) bt_lay.addWidget(QLabel("Saving:")) bt_lay.addWidget(self.save_choose) bt_lay.addWidget(self.save_btn) other_box.setLayout(bt_lay) other_box.setStyleSheet(group_sheet) mask_box = QGroupBox("Use mask from:") mask_box.setStyleSheet(group_sheet) self.mask_stack = QTabWidget() self.mask_stack.addTab(stretch_widget(self.file_mask), "File") self.mask_stack.addTab(stretch_widget(self.segmentation_mask), "Current ROI") self.mask_stack.addTab(stretch_widget(self.mask_operation), "Operations on masks") self.mask_stack.setTabToolTip(2, "Allows to create mask which is based on masks previously added to plan.") lay = QGridLayout() lay.setSpacing(0) lay.addWidget(self.mask_stack, 0, 0, 1, 2) label = QLabel("Mask name:") label.setToolTip("Needed if you would like to reuse this mask in tab 'Operations on masks'") self.mask_name.setToolTip("Needed if you would like to reuse this mask in tab 'Operations on masks'") lay.addWidget(label, 1, 0) lay.addWidget(self.mask_name, 1, 1) lay.addWidget(self.generate_mask_btn, 2, 0, 1, 2) mask_box.setLayout(lay) segment_box = QGroupBox("ROI extraction:") segment_box.setStyleSheet(group_sheet) lay = QVBoxLayout() lay.setSpacing(0) lay.addWidget(self.segment_stack) lay.addWidget(self.chose_profile_btn) lay.addWidget(self.get_big_btn) segment_box.setLayout(lay) measurement_box = QGroupBox("Set of measurements:") measurement_box.setStyleSheet(group_sheet) lay = QGridLayout() lay.setSpacing(0) lay.addWidget(self.measurements_list, 0, 0, 1, 2) lab = QLabel("Name prefix:") lab.setToolTip("Prefix added before each column name") lay.addWidget(lab, 1, 0) lay.addWidget(self.measurement_name_prefix, 1, 1) lay.addWidget(QLabel("Channel:"), 2, 0) lay.addWidget(self.choose_channel_for_measurements, 2, 1) lay.addWidget(QLabel("Units:"), 3, 0) lay.addWidget(self.units_choose, 3, 1) lay.addWidget(self.add_calculation_btn, 4, 0, 1, 2) measurement_box.setLayout(lay) info_box = QGroupBox("Information") info_box.setStyleSheet(group_sheet) lay = QVBoxLayout() lay.addWidget(self.information) info_box.setLayout(lay) layout = QGridLayout() fst_col = QVBoxLayout() fst_col.addWidget(plan_box, 1) fst_col.addWidget(mask_box) layout.addWidget(plan_box, 0, 0, 5, 1) # layout.addWidget(plan_box, 0, 0, 3, 1) # layout.addWidget(mask_box, 3, 0, 2, 1) # layout.addWidget(segmentation_mask_box, 1, 1) layout.addWidget(mask_box, 0, 2, 1, 2) layout.addWidget(other_box, 0, 1) layout.addWidget(segment_box, 1, 1, 1, 2) layout.addWidget(measurement_box, 1, 3) layout.addWidget(info_box, 3, 1, 1, 3) self.setLayout(layout) self.generate_mask_btn.setDisabled(True) self.chose_profile_btn.setDisabled(True) self.add_calculation_btn.setDisabled(True) self.mask_allow = False self.segment_allow = False self.file_mask_allow = False self.node_type = NodeType.root self.node_name = "" self.plan_node_changed.connect(self.mask_text_changed) self.plan.changed_node.connect(self.node_type_changed) self.plan_node_changed.connect(self.show_segment) self.plan_node_changed.connect(self.show_measurement) self.plan_node_changed.connect(self.mask_stack_change) self.mask_stack.currentChanged.connect(self.mask_stack_change) self.file_mask.value_changed.connect(self.mask_stack_change) self.mask_name.textChanged.connect(self.mask_stack_change) self.node_type_changed()
class TestCalculationProcess: @staticmethod def create_calculation_plan(): parameters = { "channel": 1, "minimum_size": 200, "threshold": { "name": "Base/Core", "values": { "core_threshold": { "name": "Manual", "values": { "threshold": 30000 } }, "base_threshold": { "name": "Manual", "values": { "threshold": 13000 } }, }, }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, "sprawl_type": { "name": "Euclidean", "values": {} }, } segmentation = ROIExtractionProfile( name="test", algorithm="Lower threshold with watershed", values=parameters) mask_suffix = MaskSuffix(name="", suffix="_mask") chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), MeasurementEntry( name="Segmentation Volume/Mask Volume", calculation_tree=Node( left=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), op="/", right=Leaf(name="Volume", area=AreaType.Mask, per_component=PerComponent.No), ), ), MeasurementEntry( "Segmentation Components Number", calculation_tree=Leaf("Components number", area=AreaType.ROI, per_component=PerComponent.No), ), ] statistic = MeasurementProfile(name="base_measure", chosen_fields=chosen_fields, name_prefix="") statistic_calculate = MeasurementCalculate( channel=0, units=Units.µm, measurement_profile=statistic, name_prefix="") tree = CalculationTree( RootType.Image, [ CalculationTree(mask_suffix, [ CalculationTree(segmentation, [CalculationTree(statistic_calculate, [])]) ]) ], ) return CalculationPlan(tree=tree, name="test") @staticmethod def create_calculation_plan2(): parameters = { "channel": 0, "minimum_size": 200, "threshold": { "name": "Base/Core", "values": { "core_threshold": { "name": "Manual", "values": { "threshold": 30000 } }, "base_threshold": { "name": "Manual", "values": { "threshold": 13000 } }, }, }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, "sprawl_type": { "name": "Euclidean", "values": {} }, } segmentation = ROIExtractionProfile( name="test", algorithm="Lower threshold with watershed", values=parameters) chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), MeasurementEntry( name="Segmentation Volume/Mask Volume", calculation_tree=Node( left=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), op="/", right=Leaf(name="Volume", area=AreaType.Mask, per_component=PerComponent.No), ), ), MeasurementEntry( "Segmentation Components Number", calculation_tree=Leaf("Components number", area=AreaType.ROI, per_component=PerComponent.No), ), ] statistic = MeasurementProfile(name="base_measure", chosen_fields=chosen_fields, name_prefix="") statistic_calculate = MeasurementCalculate( channel=0, units=Units.µm, measurement_profile=statistic, name_prefix="") tree = CalculationTree(RootType.Mask_project, [ CalculationTree(segmentation, [CalculationTree(statistic_calculate, [])]) ]) return CalculationPlan(tree=tree, name="test2") @staticmethod def create_simple_plan(root_type: RootType, save: Save): parameters = { "channel": 0, "minimum_size": 200, "threshold": { "name": "Manual", "values": { "threshold": 13000 } }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, } segmentation = ROIExtractionProfile(name="test", algorithm="Lower threshold", values=parameters) chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), ] statistic = MeasurementProfile(name="base_measure", chosen_fields=chosen_fields, name_prefix="") statistic_calculate = MeasurementCalculate( channel=-1, units=Units.µm, measurement_profile=statistic, name_prefix="") tree = CalculationTree( root_type, [ CalculationTree(segmentation, [ CalculationTree(statistic_calculate, []), CalculationTree(save, []) ]) ], ) return CalculationPlan(tree=tree, name="test") @staticmethod def create_calculation_plan3(): parameters = { "channel": 1, "minimum_size": 200, "threshold": { "name": "Base/Core", "values": { "core_threshold": { "name": "Manual", "values": { "threshold": 30000 } }, "base_threshold": { "name": "Manual", "values": { "threshold": 13000 } }, }, }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, "sprawl_type": { "name": "Euclidean", "values": {} }, } segmentation = ROIExtractionProfile( name="test", algorithm="Lower threshold with watershed", values=parameters) mask_suffix = MaskSuffix(name="", suffix="_mask") chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), MeasurementEntry( name="Segmentation Volume/Mask Volume", calculation_tree=Node( left=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), op="/", right=Leaf(name="Volume", area=AreaType.Mask, per_component=PerComponent.No), ), ), MeasurementEntry( "Segmentation Components Number", calculation_tree=Leaf("Components number", area=AreaType.ROI, per_component=PerComponent.No), ), MeasurementEntry( "Segmentation Volume per component", calculation_tree=Leaf("Volume", area=AreaType.ROI, per_component=PerComponent.Yes), ), ] statistic = MeasurementProfile(name="base_measure", chosen_fields=chosen_fields, name_prefix="") statistic_calculate = MeasurementCalculate( channel=0, units=Units.µm, measurement_profile=statistic, name_prefix="") mask_create = MaskCreate( "", MaskProperty(RadiusType.NO, 0, RadiusType.NO, 0, True, False, False)) parameters2 = { "channel": 1, "minimum_size": 200, "threshold": { "name": "Manual", "values": { "threshold": 30000 } }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, } segmentation2 = ROIExtractionProfile(name="test", algorithm="Lower threshold", values=parameters2) chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), MeasurementEntry( name="Segmentation Volume/Mask Volume", calculation_tree=Node( left=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), op="/", right=Leaf(name="Volume", area=AreaType.Mask, per_component=PerComponent.No), ), ), MeasurementEntry( "Segmentation Components Number", calculation_tree=Leaf("Components number", area=AreaType.ROI, per_component=PerComponent.No), ), MeasurementEntry( "Mask Volume per component", calculation_tree=Leaf("Volume", area=AreaType.Mask, per_component=PerComponent.Yes), ), ] statistic = MeasurementProfile(name="base_measure2", chosen_fields=chosen_fields[:], name_prefix="aa_") statistic_calculate2 = MeasurementCalculate( channel=0, units=Units.µm, measurement_profile=statistic, name_prefix="") chosen_fields.append( MeasurementEntry( "Segmentation Volume per component", calculation_tree=Leaf("Volume", area=AreaType.ROI, per_component=PerComponent.Yes), )) statistic = MeasurementProfile(name="base_measure3", chosen_fields=chosen_fields[:], name_prefix="bb_") statistic_calculate3 = MeasurementCalculate( channel=0, units=Units.µm, measurement_profile=statistic, name_prefix="") tree = CalculationTree( RootType.Image, [ CalculationTree( mask_suffix, [ CalculationTree( segmentation, [ CalculationTree(statistic_calculate, []), CalculationTree( mask_create, [ CalculationTree( segmentation2, [ CalculationTree( statistic_calculate2, []), CalculationTree( statistic_calculate3, []), ], ), ], ), ], ) ], ) ], ) return CalculationPlan(tree=tree, name="test") @staticmethod def create_mask_operation_plan(mask_op): parameters = { "channel": 0, "minimum_size": 200, "threshold": { "name": "Manual", "values": { "threshold": 13000 } }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, } parameters2 = dict(**parameters) parameters2["channel"] = 1 segmentation = ROIExtractionProfile(name="test", algorithm="Lower threshold", values=parameters) segmentation2 = ROIExtractionProfile(name="test2", algorithm="Lower threshold", values=parameters2) chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), ] statistic = MeasurementProfile(name="base_measure", chosen_fields=chosen_fields, name_prefix="") statistic_calculate = MeasurementCalculate( channel=-1, units=Units.µm, measurement_profile=statistic, name_prefix="") tree = CalculationTree( RootType.Image, [ CalculationTree( segmentation, [ CalculationTree( MaskCreate( name="test1", mask_property=MaskProperty.simple_mask()), []) ], ), CalculationTree( segmentation2, [ CalculationTree( MaskCreate( name="test2", mask_property=MaskProperty.simple_mask()), []) ], ), CalculationTree(mask_op, [ CalculationTree(segmentation2, [CalculationTree(statistic_calculate, [])]) ]), ], ) return CalculationPlan(tree=tree, name="test") @pytest.mark.parametrize("mask_op", [ MaskUse("test1"), MaskSum("", "test1", "test2"), MaskIntersection("", "test1", "test2") ]) def test_mask_op(self, mask_op, data_test_dir, tmpdir): plan = self.create_mask_operation_plan(mask_op) file_path = os.path.join(data_test_dir, "stack1_components", "stack1_component1.tif") calc = Calculation( [file_path], base_prefix=os.path.dirname(file_path), result_prefix=tmpdir, measurement_file_path=os.path.join(tmpdir, "test3.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) calc_process = CalculationProcess() res = calc_process.do_calculation(FileCalculation(file_path, calc)) assert isinstance(res, list) assert isinstance(res[0], ResponseData) def test_one_file(self, data_test_dir): plan = self.create_calculation_plan() process = CalculationProcess() file_path = os.path.join(data_test_dir, "stack1_components", "stack1_component5.tif") calc = MocksCalculation(file_path) process.calculation = calc process.image = TiffImageReader.read_image(file_path) process.iterate_over(plan.execution_tree) assert len(process.measurement[0]) == 3 @pytest.mark.filterwarnings("ignore:This method will be removed") def test_full_pipeline_base(self, tmpdir, data_test_dir, monkeypatch): monkeypatch.setattr(batch_backend, "CalculationProcess", MockCalculationProcess) plan = self.create_calculation_plan() file_pattern = os.path.join(data_test_dir, "stack1_components", "stack1_component*[0-9].tif") file_paths = sorted(glob(file_pattern)) assert os.path.basename(file_paths[0]) == "stack1_component1.tif" calc = Calculation( file_paths, base_prefix=data_test_dir, result_prefix=data_test_dir, measurement_file_path=os.path.join(tmpdir, "test.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) calc_process = CalculationProcess() for file_path in file_paths: res = calc_process.do_calculation(FileCalculation(file_path, calc)) assert isinstance(res, list) assert isinstance(res[0], ResponseData) @pytest.mark.filterwarnings("ignore:This method will be removed") def test_full_pipeline(self, tmpdir, data_test_dir, monkeypatch): monkeypatch.setattr(batch_backend, "CalculationProcess", MockCalculationProcess) plan = self.create_calculation_plan() file_pattern = os.path.join(data_test_dir, "stack1_components", "stack1_component*[0-9].tif") file_paths = sorted(glob(file_pattern)) assert os.path.basename(file_paths[0]) == "stack1_component1.tif" calc = Calculation( file_paths, base_prefix=data_test_dir, result_prefix=data_test_dir, measurement_file_path=os.path.join(tmpdir, "test.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) manager = CalculationManager() manager.set_number_of_workers(3) manager.add_calculation(calc) for _ in range(int(120 / 0.1)): manager.get_results() if manager.has_work: time.sleep(0.1) else: break else: manager.kill_jobs() pytest.fail("jobs hanged") manager.writer.finish() if sys.platform == "darwin": time.sleep(2) else: time.sleep(0.4) assert os.path.exists(os.path.join(tmpdir, "test.xlsx")) df = pd.read_excel(os.path.join(tmpdir, "test.xlsx"), index_col=0, header=[0, 1], engine=ENGINE) assert df.shape == (8, 4) for i in range(8): assert os.path.basename( df.name.units[i]) == f"stack1_component{i+1}.tif" @pytest.mark.filterwarnings("ignore:This method will be removed") def test_full_pipeline_error(self, tmp_path_factory, data_test_dir, monkeypatch): plan = self.create_calculation_plan() data_dir = tmp_path_factory.mktemp("data") file_pattern_copy = os.path.join(data_test_dir, "stack1_components", "stack1_component*.tif") file_paths = sorted(glob(file_pattern_copy)) for el in file_paths: shutil.copy(el, data_dir) shutil.copy(data_dir / "stack1_component1.tif", data_dir / "stack1_component10.tif") file_pattern = os.path.join(data_dir, "stack1_component*[0-9].tif") file_paths = sorted(glob(file_pattern)) result_dir = tmp_path_factory.mktemp("result") assert os.path.basename(file_paths[0]) == "stack1_component1.tif" calc = Calculation( file_paths, base_prefix=str(data_dir), result_prefix=str(data_dir), measurement_file_path=os.path.join(result_dir, "test.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) manager = CalculationManager() manager.set_number_of_workers(3) manager.add_calculation(calc) while manager.has_work: time.sleep(0.1) manager.get_results() manager.writer.finish() if sys.platform == "darwin": time.sleep(2) else: time.sleep(0.4) assert os.path.exists(os.path.join(result_dir, "test.xlsx")) df = pd.read_excel(os.path.join(result_dir, "test.xlsx"), index_col=0, header=[0, 1], engine=ENGINE) assert df.shape == (8, 4) for i in range(8): assert os.path.basename( df.name.units[i]) == f"stack1_component{i + 1}.tif" df2 = pd.read_excel(os.path.join(result_dir, "test.xlsx"), sheet_name="Errors", index_col=0, engine=ENGINE) assert df2.shape == (1, 2) str(df2.loc[0]["error description"]).startswith("[Errno 2]") @pytest.mark.filterwarnings("ignore:This method will be removed") def test_full_pipeline_mask_project(self, tmpdir, data_test_dir): plan = self.create_calculation_plan2() file_pattern = os.path.join(data_test_dir, "*nucleus.seg") file_paths = glob(file_pattern) calc = Calculation( file_paths, base_prefix=data_test_dir, result_prefix=data_test_dir, measurement_file_path=os.path.join(tmpdir, "test2.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) manager = CalculationManager() manager.set_number_of_workers(2) manager.add_calculation(calc) while manager.has_work: time.sleep(0.1) manager.get_results() if sys.platform == "darwin": time.sleep(2) else: time.sleep(0.4) manager.writer.finish() assert os.path.exists(os.path.join(tmpdir, "test2.xlsx")) df = pd.read_excel(os.path.join(tmpdir, "test2.xlsx"), index_col=0, header=[0, 1], engine=ENGINE) assert df.shape == (2, 4) def test_do_calculation(self, tmpdir, data_test_dir): plan = self.create_calculation_plan3() file_path = os.path.join(data_test_dir, "stack1_components", "stack1_component1.tif") calc = Calculation( [file_path], base_prefix=data_test_dir, result_prefix=data_test_dir, measurement_file_path=os.path.join(tmpdir, "test3.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) index, res = do_calculation((1, file_path), calc) assert index == 1 assert isinstance(res, list) assert isinstance(res[0], ResponseData) @pytest.mark.parametrize( "file_name,root_type", [ (os.path.join("stack1_components", "stack1_component1.tif"), RootType.Image), ("stack1_component1_1.tgz", RootType.Image), ("stack1_component1_1.tgz", RootType.Project), ("test_nucleus_1_1.seg", RootType.Image), ("test_nucleus_1_1.seg", RootType.Mask_project), ], ) @pytest.mark.parametrize("save_method", save_dict.values()) def test_do_calculation_save(self, tmpdir, data_test_dir, file_name, root_type, save_method: SaveBase): save_desc = Save("_test", "", save_method.get_name(), save_method.get_short_name(), save_method.get_default_values()) plan = self.create_simple_plan(root_type, save_desc) file_path = os.path.join(data_test_dir, file_name) calc = Calculation( [file_path], base_prefix=os.path.dirname(file_path), result_prefix=tmpdir, measurement_file_path=os.path.join(tmpdir, "test3.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) calc_process = CalculationProcess() res = calc_process.do_calculation(FileCalculation(file_path, calc)) assert isinstance(res, list) assert isinstance(res[0], ResponseData) def test_do_calculation_calculation_process(self, tmpdir, data_test_dir): plan = self.create_calculation_plan3() file_path = os.path.join(data_test_dir, "stack1_components", "stack1_component1.tif") calc = Calculation( [file_path], base_prefix=data_test_dir, result_prefix=data_test_dir, measurement_file_path=os.path.join(tmpdir, "test3.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) calc_process = CalculationProcess() res = calc_process.do_calculation(FileCalculation(file_path, calc)) assert isinstance(res, list) assert isinstance(res[0], ResponseData) @pytest.mark.filterwarnings("ignore:This method will be removed") def test_full_pipeline_component_split_no_process(self, tmpdir, data_test_dir, monkeypatch): monkeypatch.setattr(batch_backend, "CalculationProcess", MockCalculationProcess) plan = self.create_calculation_plan3() file_pattern = os.path.join(data_test_dir, "stack1_components", "stack1_component*[0-9].tif") file_paths = sorted(glob(file_pattern)) assert os.path.basename(file_paths[0]) == "stack1_component1.tif" calc = Calculation( file_paths, base_prefix=data_test_dir, result_prefix=data_test_dir, measurement_file_path=os.path.join(tmpdir, "test.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) calc_process = CalculationProcess() for file_path in file_paths: res = calc_process.do_calculation(FileCalculation(file_path, calc)) assert isinstance(res, list) assert isinstance(res[0], ResponseData) @pytest.mark.filterwarnings("ignore:This method will be removed") def test_full_pipeline_component_split(self, tmpdir, data_test_dir): plan = self.create_calculation_plan3() file_pattern = os.path.join(data_test_dir, "stack1_components", "stack1_component*[0-9].tif") file_paths = glob(file_pattern) calc = Calculation( file_paths, base_prefix=data_test_dir, result_prefix=data_test_dir, measurement_file_path=os.path.join(tmpdir, "test3.xlsx"), sheet_name="Sheet1", calculation_plan=plan, voxel_size=(1, 1, 1), ) manager = CalculationManager() manager.set_number_of_workers(2) manager.add_calculation(calc) while manager.has_work: time.sleep(0.1) res = manager.get_results() if res.errors: print(res.errors, file=sys.stderr) if sys.platform == "darwin": time.sleep(2) else: time.sleep(0.4) manager.writer.finish() assert os.path.exists(os.path.join(tmpdir, "test3.xlsx")) df = pd.read_excel(os.path.join(tmpdir, "test3.xlsx"), index_col=0, header=[0, 1], engine=ENGINE) assert df.shape == (8, 10) df2 = pd.read_excel(os.path.join(tmpdir, "test3.xlsx"), sheet_name=1, index_col=0, header=[0, 1], engine=ENGINE) assert df2.shape[0] > 8 assert df2.shape == ( df["Segmentation Components Number"]["count"].sum(), 6) df3 = pd.read_excel(os.path.join(tmpdir, "test3.xlsx"), sheet_name=2, index_col=0, header=[0, 1], engine=ENGINE) assert df3.shape == ( df["Segmentation Components Number"]["count"].sum(), 6) df4 = pd.read_excel(os.path.join(tmpdir, "test3.xlsx"), sheet_name=3, index_col=0, header=[0, 1], engine=ENGINE) assert df4.shape == ( df["Segmentation Components Number"]["count"].sum(), 8)