feat: init
This commit is contained in:
855
test/config/test_config.py
Normal file
855
test/config/test_config.py
Normal file
@@ -0,0 +1,855 @@
|
||||
# Copyright (c) 2021-2025 The University of Texas Southwestern Medical Center.
|
||||
# All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted for academic and research use only
|
||||
# (subject to the limitations in the disclaimer below)
|
||||
# provided that the following conditions are met:
|
||||
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
|
||||
# * Neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
|
||||
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
|
||||
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
# Standard Imports
|
||||
import pathlib
|
||||
import unittest
|
||||
from unittest.mock import patch, MagicMock
|
||||
from multiprocessing import Manager
|
||||
from multiprocessing.managers import ListProxy, DictProxy
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
import yaml
|
||||
import sys
|
||||
|
||||
# Third Party Imports
|
||||
|
||||
# Local Imports
|
||||
import navigate.config.config as config
|
||||
from navigate.tools.file_functions import save_yaml_file, delete_folder, load_yaml_file
|
||||
|
||||
|
||||
def test_config_methods():
|
||||
methods = dir(config)
|
||||
desired_methods = [
|
||||
"DictProxy",
|
||||
"ListProxy",
|
||||
"Path",
|
||||
"__builtins__",
|
||||
"__cached__",
|
||||
"__doc__",
|
||||
"__file__",
|
||||
"__loader__",
|
||||
"__name__",
|
||||
"__package__",
|
||||
"__spec__",
|
||||
"build_nested_dict",
|
||||
"build_ref_name",
|
||||
"load_param_from_module",
|
||||
"save_yaml_file",
|
||||
"get_configuration_paths",
|
||||
"get_navigate_path",
|
||||
"isfile",
|
||||
"load_configs",
|
||||
"os",
|
||||
"platform",
|
||||
"shutil",
|
||||
"sys",
|
||||
"time",
|
||||
"update_config_dict",
|
||||
"verify_experiment_config",
|
||||
"verify_waveform_constants",
|
||||
"verify_positions_config",
|
||||
"verify_configuration",
|
||||
"support_deceased_configuration",
|
||||
"yaml",
|
||||
"logging",
|
||||
"logger",
|
||||
"p",
|
||||
"Union",
|
||||
"multiprocessing",
|
||||
]
|
||||
for method in methods:
|
||||
assert method in desired_methods
|
||||
|
||||
|
||||
def test_get_navigate_path():
|
||||
"""Test that the Navigate path is a string."""
|
||||
assert isinstance(config.get_navigate_path(), str)
|
||||
path_string = config.get_navigate_path()
|
||||
assert ".navigate" in path_string
|
||||
|
||||
|
||||
def test_get_navigate_path_windows(monkeypatch):
|
||||
"""Test that the Navigate path is a string."""
|
||||
monkeypatch.setattr(config.platform, "system", lambda: "Windows")
|
||||
monkeypatch.setattr(config.os, "getenv", lambda x: "LOCALAPPDATA")
|
||||
monkeypatch.setattr(config.os.path, "exists", lambda x: True)
|
||||
assert isinstance(config.get_navigate_path(), str)
|
||||
path_string = config.get_navigate_path()
|
||||
assert path_string.startswith("LOCALAPPDATA")
|
||||
assert path_string.endswith(".navigate")
|
||||
|
||||
|
||||
def test_get_navigate_path_mac(monkeypatch):
|
||||
"""Test that the Navigate path is a string."""
|
||||
monkeypatch.setattr(config.platform, "system", lambda: "Darwin")
|
||||
monkeypatch.setattr(config.os, "getenv", lambda x: "HOME")
|
||||
monkeypatch.setattr(config.os.path, "exists", lambda x: True)
|
||||
assert isinstance(config.get_navigate_path(), str)
|
||||
path_string = config.get_navigate_path()
|
||||
assert path_string.startswith("HOME")
|
||||
assert path_string.endswith(".navigate")
|
||||
|
||||
|
||||
# Write a test for config.get_configuration_paths()
|
||||
def test_get_configuration_paths():
|
||||
"""Test that the configuration paths are a list."""
|
||||
paths = config.get_configuration_paths()
|
||||
for path in paths:
|
||||
assert isinstance(path, pathlib.Path)
|
||||
assert len(paths) == 7
|
||||
|
||||
|
||||
def test_get_configuration_paths_create_dir(monkeypatch):
|
||||
"""Test that the configuration path is created,
|
||||
and that they are a list."""
|
||||
monkeypatch.setattr(config, "get_navigate_path", lambda: "TESTPATH")
|
||||
paths = config.get_configuration_paths()
|
||||
for path in paths:
|
||||
assert isinstance(path, pathlib.Path)
|
||||
assert os.path.exists(path), "Each configuration yaml file is copied"
|
||||
assert path.suffix.lower() in [".yml", ".yaml"]
|
||||
# delete generated folder
|
||||
delete_folder("TESTPATH")
|
||||
|
||||
|
||||
# test that the system is exited if no file is provided to load_yaml_config
|
||||
def test_load_yaml_config_no_file():
|
||||
"""Test that the system exits if no file is provided."""
|
||||
from unittest import mock
|
||||
|
||||
with mock.patch("sys.exit") as mock_sys_exit:
|
||||
config.load_configs(manager=Manager(), **{})
|
||||
mock_sys_exit.assert_called_once()
|
||||
|
||||
|
||||
class TestLoadConfigsWithYAMLError(unittest.TestCase):
|
||||
"""Test the load_configs function.
|
||||
|
||||
Target is the yaml.YAMLError exception clause.
|
||||
"""
|
||||
|
||||
@patch("yaml.load")
|
||||
@patch("builtins.open")
|
||||
@patch("pathlib.Path.exists")
|
||||
def test_yaml_error(self, mock_exists, mock_open, mock_yaml_load):
|
||||
# Set up the mocks
|
||||
mock_exists.return_value = True
|
||||
mock_open.return_value = MagicMock()
|
||||
mock_yaml_load.side_effect = yaml.YAMLError("Test YAMLError")
|
||||
|
||||
# Mocking sys.exit to prevent the test runner from exiting
|
||||
with patch.object(sys, "exit") as mock_exit:
|
||||
manager = MagicMock()
|
||||
config.load_configs(manager, config1="path/to/config1.yaml")
|
||||
|
||||
# Check if sys.exit was called with the expected argument
|
||||
mock_exit.assert_called_with(1)
|
||||
|
||||
# Check if the YAMLError was triggered
|
||||
mock_yaml_load.assert_called_once()
|
||||
|
||||
|
||||
class TestBuildNestedDict(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.manager = Manager()
|
||||
self.parent_dict = {}
|
||||
self.key_name = "nested_dict"
|
||||
|
||||
def tearDown(self):
|
||||
self.manager.shutdown()
|
||||
|
||||
def test_build_nested_dict_with_string_data(self):
|
||||
string_data = "string"
|
||||
expected_result = {"nested_dict": "string"}
|
||||
|
||||
config.build_nested_dict(
|
||||
self.manager, self.parent_dict, self.key_name, string_data
|
||||
)
|
||||
|
||||
self.assertEqual(self.parent_dict, expected_result)
|
||||
self.assertEqual(self.parent_dict[self.key_name], "string")
|
||||
assert isinstance(self.parent_dict, dict)
|
||||
|
||||
def test_build_nested_dict_with_list_data(self):
|
||||
list_data = ["string1", "string2"]
|
||||
|
||||
config.build_nested_dict(
|
||||
self.manager, self.parent_dict, self.key_name, list_data
|
||||
)
|
||||
|
||||
assert isinstance(self.parent_dict, dict)
|
||||
assert isinstance(self.parent_dict[self.key_name], ListProxy)
|
||||
for i in range(2):
|
||||
assert self.parent_dict[self.key_name][i] == list_data[i]
|
||||
|
||||
def test_build_nested_dict_with_dict_data(self):
|
||||
dict_data = {"key1": "string1", "key2": "string2"}
|
||||
|
||||
config.build_nested_dict(
|
||||
self.manager, self.parent_dict, self.key_name, dict_data
|
||||
)
|
||||
|
||||
assert isinstance(self.parent_dict, dict)
|
||||
assert isinstance(self.parent_dict[self.key_name], DictProxy)
|
||||
for key in dict_data.keys():
|
||||
assert self.parent_dict[self.key_name][key] == dict_data[key]
|
||||
|
||||
def test_update_config_dict_with_bad_file_name(self):
|
||||
test_entry = "string"
|
||||
dict_data = {"key1": "string1", "key2": "string2"}
|
||||
# Build the nested config
|
||||
config.build_nested_dict(
|
||||
self.manager, self.parent_dict, self.key_name, dict_data
|
||||
)
|
||||
|
||||
# Update the nested config
|
||||
result = config.update_config_dict(
|
||||
self.manager, self.parent_dict, self.key_name, test_entry
|
||||
)
|
||||
assert result is False
|
||||
|
||||
def test_update_config_dict_with_file_name(self):
|
||||
test_entry = "test.yml"
|
||||
# create an yaml file
|
||||
test_yaml_data = {"test_key1": "test_string1", "test_key2": "test_string2"}
|
||||
save_yaml_file("", test_yaml_data, test_entry)
|
||||
|
||||
dict_data = {"key1": "string1", "key2": "string2"}
|
||||
# Build the nested config
|
||||
config.build_nested_dict(
|
||||
self.manager, self.parent_dict, self.key_name, dict_data
|
||||
)
|
||||
|
||||
# Update the nested config
|
||||
result = config.update_config_dict(
|
||||
self.manager, self.parent_dict, self.key_name, test_entry
|
||||
)
|
||||
|
||||
assert result is True
|
||||
assert isinstance(self.parent_dict[self.key_name], DictProxy)
|
||||
for k in self.parent_dict[self.key_name].keys():
|
||||
assert self.parent_dict[self.key_name][k] == test_yaml_data[k]
|
||||
|
||||
# delete test yaml file
|
||||
os.remove(test_entry)
|
||||
|
||||
|
||||
class TestVerifyExperimentConfig(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.manager = Manager()
|
||||
current_path = os.path.abspath(os.path.dirname(__file__))
|
||||
root_path = os.path.dirname(os.path.dirname(current_path))
|
||||
self.config_path = os.path.join(root_path, "src", "navigate", "config")
|
||||
self.test_root = "test_dir"
|
||||
os.mkdir(self.test_root)
|
||||
|
||||
configuration = config.load_configs(
|
||||
self.manager,
|
||||
configuration=os.path.join(self.config_path, "configuration.yaml"),
|
||||
)
|
||||
config.verify_configuration(self.manager, configuration)
|
||||
saving_dict_sample = {
|
||||
"root_directory": config.get_navigate_path(),
|
||||
"save_directory": config.get_navigate_path(),
|
||||
"user": "Kevin",
|
||||
"tissue": "Lung",
|
||||
"celltype": "MV3",
|
||||
"label": "GFP",
|
||||
"file_type": "TIFF",
|
||||
"date": time.strftime("%Y-%m-%d"),
|
||||
"solvent": "BABB",
|
||||
}
|
||||
|
||||
camera_parameters_dict_sample = {
|
||||
"x_pixels": 2048,
|
||||
"y_pixels": 2048,
|
||||
"img_x_pixels": 2048,
|
||||
"img_y_pixels": 2048,
|
||||
"sensor_mode": "Normal",
|
||||
"readout_direction": "Top-to-Bottom",
|
||||
"number_of_pixels": 10,
|
||||
"binning": "1x1",
|
||||
"frames_to_average": 1,
|
||||
"databuffer_size": 100,
|
||||
}
|
||||
|
||||
# Autofocus
|
||||
# autofocus_sample = {
|
||||
# "coarse_range": 500,
|
||||
# "coarse_step_size": 50,
|
||||
# "coarse_selected": True,
|
||||
# "fine_range": 50,
|
||||
# "fine_step_size": 5,
|
||||
# "fine_selected": True,
|
||||
# "robust_fit": False,
|
||||
# }
|
||||
|
||||
stage_parameters_dict_sample = {
|
||||
"limits": True,
|
||||
}
|
||||
for microscope_name in configuration["configuration"]["microscopes"].keys():
|
||||
stage_parameters_dict_sample[microscope_name] = {}
|
||||
for k in ["theta_step", "f_step", "z_step"]:
|
||||
stage_parameters_dict_sample[microscope_name][k] = configuration[
|
||||
"configuration"
|
||||
]["microscopes"][microscope_name]["stage"].get(k, 30)
|
||||
stage_parameters_dict_sample[microscope_name]["xy_step"] = min(
|
||||
configuration["configuration"]["microscopes"][microscope_name][
|
||||
"stage"
|
||||
].get("x_step", 500),
|
||||
configuration["configuration"]["microscopes"][microscope_name][
|
||||
"stage"
|
||||
].get("y_step", 500),
|
||||
)
|
||||
|
||||
microscope_name = configuration["configuration"]["microscopes"].keys()[0]
|
||||
zoom = configuration["configuration"]["microscopes"][microscope_name]["zoom"][
|
||||
"position"
|
||||
].keys()[0]
|
||||
microscope_parameters_dict_sample = {
|
||||
"microscope_name": microscope_name,
|
||||
"image_mode": "live",
|
||||
"zoom": zoom,
|
||||
"stack_cycling_mode": "per_stack",
|
||||
"start_position": 0.0,
|
||||
"end_position": 100.0,
|
||||
"step_size": 20.0,
|
||||
"number_z_steps": 5,
|
||||
"timepoints": 1,
|
||||
"stack_pause": 0.0,
|
||||
"is_save": False,
|
||||
"stack_acq_time": 1.0,
|
||||
"timepoint_interval": 0,
|
||||
"experiment_duration": 1.03,
|
||||
"is_multiposition": False,
|
||||
"stack_z_origin": 0,
|
||||
"stack_focus_origin": 0,
|
||||
"start_focus": 0.0,
|
||||
"end_focus": 0.0,
|
||||
"abs_z_start": 0.0,
|
||||
"abs_z_end": 100.0,
|
||||
"waveform_template": "Default",
|
||||
}
|
||||
|
||||
# multipositions_sample = [[10.0, 10.0, 10.0, 10.0, 10.0]]
|
||||
|
||||
self.experiment_sample = {
|
||||
"Saving": saving_dict_sample,
|
||||
"CameraParameters": camera_parameters_dict_sample,
|
||||
"StageParameters": stage_parameters_dict_sample,
|
||||
"MicroscopeState": microscope_parameters_dict_sample,
|
||||
}
|
||||
|
||||
def tearDown(self):
|
||||
delete_folder(self.test_root)
|
||||
self.manager.shutdown()
|
||||
|
||||
def assert_equal_dict(self, dict1, dict2):
|
||||
# dict1 and dict2 are not nested dict
|
||||
for k in dict1.keys():
|
||||
assert dict1[k] == dict2[k], f"{k}: {dict1[k]} -- {dict2[k]}"
|
||||
|
||||
def test_load_empty_experiment_file(self):
|
||||
experiment_file_path = os.path.join(self.test_root, "experiment.yml")
|
||||
with open(experiment_file_path, "w") as f:
|
||||
f.write("")
|
||||
configuration = config.load_configs(
|
||||
self.manager,
|
||||
configuration=os.path.join(self.config_path, "configuration.yaml"),
|
||||
experiment=experiment_file_path,
|
||||
)
|
||||
config.verify_configuration(self.manager, configuration)
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
|
||||
experiement_config = configuration["experiment"]
|
||||
assert type(experiement_config) == DictProxy
|
||||
|
||||
# Saving parameters
|
||||
self.assert_equal_dict(
|
||||
self.experiment_sample["Saving"], experiement_config["Saving"]
|
||||
)
|
||||
|
||||
# Camera parameters
|
||||
self.assert_equal_dict(
|
||||
self.experiment_sample["CameraParameters"],
|
||||
experiement_config["CameraParameters"],
|
||||
)
|
||||
|
||||
# AutoFocusParameters
|
||||
|
||||
# Stage parameters
|
||||
for k, value in self.experiment_sample["StageParameters"].items():
|
||||
if type(value) == dict:
|
||||
assert k in experiement_config["StageParameters"].keys()
|
||||
self.assert_equal_dict(value, experiement_config["StageParameters"][k])
|
||||
else:
|
||||
assert value == experiement_config["StageParameters"][k]
|
||||
|
||||
# MicroscopeState parameters
|
||||
self.assert_equal_dict(
|
||||
self.experiment_sample["MicroscopeState"],
|
||||
experiement_config["MicroscopeState"],
|
||||
)
|
||||
|
||||
# # MultiPositions
|
||||
# for i, position in enumerate(self.experiment_sample["MultiPositions"]):
|
||||
# assert position == experiement_config["MultiPositions"][i]
|
||||
|
||||
def test_load_experiment_file_with_missing_parameters(self):
|
||||
experiment = load_yaml_file(os.path.join(self.config_path, "experiment.yml"))
|
||||
# Saving prameters
|
||||
saving_parameters = list(self.experiment_sample["Saving"].keys())
|
||||
saving_parameters_deleted = self.delete_random_entries_from_dict(
|
||||
saving_parameters, experiment["Saving"]
|
||||
)
|
||||
|
||||
# Camera parameters
|
||||
camera_parameters = list(self.experiment_sample["CameraParameters"].keys())
|
||||
camera_parameters.append("img_x_pixels")
|
||||
camera_parameters.append("img_y_pixels")
|
||||
camera_parameters_deleted = self.delete_random_entries_from_dict(
|
||||
camera_parameters, experiment["CameraParameters"]
|
||||
)
|
||||
|
||||
# StageParameters
|
||||
configuration = load_yaml_file(
|
||||
os.path.join(self.config_path, "configuration.yaml")
|
||||
)
|
||||
# delete limits
|
||||
if "limits" in experiment["StageParameters"].keys():
|
||||
del experiment["StageParameters"]["limits"]
|
||||
# delete part of stage parameters of one microscope
|
||||
microscope_names = list(configuration["microscopes"].keys())
|
||||
if microscope_names[0] not in experiment["StageParameters"]:
|
||||
experiment["StageParameters"][microscope_names[0]] = {
|
||||
"z_step": 100.0,
|
||||
"theta_step": 10.0,
|
||||
}
|
||||
# delete all stage parameter of another microscope
|
||||
if microscope_names[1] in experiment["StageParameters"].keys():
|
||||
del experiment["StageParameters"][microscope_names[1]]
|
||||
|
||||
# MicroscopeState
|
||||
micrscope_parameters = list(self.experiment_sample["MicroscopeState"].keys())
|
||||
micrscope_parameters.append("channels")
|
||||
micrscope_parameters_deleted = self.delete_random_entries_from_dict(
|
||||
micrscope_parameters, experiment["MicroscopeState"]
|
||||
)
|
||||
|
||||
save_yaml_file(self.test_root, experiment, "experiment_missing_parameters.yml")
|
||||
configuration = config.load_configs(
|
||||
self.manager,
|
||||
configuration=os.path.join(self.config_path, "configuration.yaml"),
|
||||
experiment=os.path.join(
|
||||
self.test_root, "experiment_missing_parameters.yml"
|
||||
),
|
||||
)
|
||||
config.verify_configuration(self.manager, configuration)
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
# verify Saving parameters are added
|
||||
for k in saving_parameters_deleted:
|
||||
assert (
|
||||
k in configuration["experiment"]["Saving"].keys()
|
||||
), f"parameter {k} should be added to Saving parameters"
|
||||
|
||||
# verify CameraParameters are added
|
||||
for k in camera_parameters_deleted:
|
||||
assert (
|
||||
k in configuration["experiment"]["CameraParameters"].keys()
|
||||
), f"parameter {k} should be added into CameraParameters"
|
||||
|
||||
# verify MicroscopeState parameters are added
|
||||
for k in micrscope_parameters_deleted:
|
||||
assert (
|
||||
k in configuration["experiment"]["MicroscopeState"].keys()
|
||||
), f"parameter {k} should be added to MicroscopeState"
|
||||
|
||||
# verify Stage parameters are added
|
||||
assert (
|
||||
"limits" in configuration["experiment"]["StageParameters"].keys()
|
||||
), "limits should be added to Stage parameters"
|
||||
for microscope_name in microscope_names:
|
||||
for k in ["xy_step", "z_step", "f_step", "theta_step"]:
|
||||
assert (
|
||||
k in configuration["experiment"]["StageParameters"][microscope_name]
|
||||
)
|
||||
|
||||
def test_load_experiment_file_with_wrong_parameter_values(self):
|
||||
configuration = config.load_configs(
|
||||
self.manager,
|
||||
configuration=os.path.join(self.config_path, "configuration.yaml"),
|
||||
experiment=os.path.join(self.config_path, "experiment.yml"),
|
||||
)
|
||||
config.verify_configuration(self.manager, configuration)
|
||||
experiment = configuration["experiment"]
|
||||
# Saving parameters
|
||||
# check if root_directory and save_directory exist
|
||||
experiment["Saving"]["root_directory"] = self.config_path
|
||||
experiment["Saving"]["save_directory"] = os.path.join(
|
||||
self.test_root, "not_exist", "not_exist"
|
||||
)
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["Saving"]["root_directory"] == self.config_path
|
||||
assert os.path.exists(experiment["Saving"]["save_directory"])
|
||||
assert experiment["Saving"]["save_directory"] != os.path.join(
|
||||
self.test_root, "not_exist", "not_exist"
|
||||
)
|
||||
|
||||
# CameraParameters
|
||||
# x_pixels, y_pixels
|
||||
experiment["CameraParameters"]["x_pixels"] = -10
|
||||
experiment["CameraParameters"]["y_pixels"] = "abcd"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert (
|
||||
experiment["CameraParameters"]["x_pixels"]
|
||||
== self.experiment_sample["CameraParameters"]["x_pixels"]
|
||||
)
|
||||
assert (
|
||||
experiment["CameraParameters"]["y_pixels"]
|
||||
== self.experiment_sample["CameraParameters"]["y_pixels"]
|
||||
)
|
||||
binning = int(experiment["CameraParameters"]["binning"][0])
|
||||
assert (
|
||||
experiment["CameraParameters"]["img_x_pixels"]
|
||||
== experiment["CameraParameters"]["x_pixels"] // binning
|
||||
)
|
||||
assert (
|
||||
experiment["CameraParameters"]["img_y_pixels"]
|
||||
== experiment["CameraParameters"]["y_pixels"] // binning
|
||||
)
|
||||
|
||||
# binning
|
||||
for v in ["abcd", "3x3", "12.4"]:
|
||||
experiment["CameraParameters"]["binning"] = v
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["CameraParameters"]["binning"] == "1x1"
|
||||
assert (
|
||||
experiment["CameraParameters"]["img_x_pixels"]
|
||||
== experiment["CameraParameters"]["x_pixels"]
|
||||
)
|
||||
assert (
|
||||
experiment["CameraParameters"]["img_y_pixels"]
|
||||
== experiment["CameraParameters"]["y_pixels"]
|
||||
)
|
||||
|
||||
# sensor_mode
|
||||
experiment["CameraParameters"]["sensor_mode"] = "None"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["CameraParameters"]["sensor_mode"] == "Normal"
|
||||
experiment["CameraParameters"]["sensor_mode"] = "Lightsheet"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["CameraParameters"]["sensor_mode"] == "Normal"
|
||||
experiment["CameraParameters"]["sensor_mode"] = "Light-Sheet"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["CameraParameters"]["sensor_mode"] == "Light-Sheet"
|
||||
|
||||
# readout_direction
|
||||
for v in ["abcd", 123, None]:
|
||||
experiment["CameraParameters"]["readout_direction"] = v
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert (
|
||||
experiment["CameraParameters"]["readout_direction"] == "Top-to-Bottom"
|
||||
)
|
||||
|
||||
experiment["CameraParameters"]["readout_direction"] = "Bottom-to-Top"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["CameraParameters"]["readout_direction"] == "Bottom-to-Top"
|
||||
|
||||
# other parameters should be int
|
||||
for k in ["number_of_pixels", "databuffer_size", "frames_to_average"]:
|
||||
for v in ["abc", -10, 0]:
|
||||
experiment["CameraParameters"][k] = v
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert (
|
||||
experiment["CameraParameters"][k]
|
||||
== self.experiment_sample["CameraParameters"][k]
|
||||
)
|
||||
|
||||
# StageParameters
|
||||
experiment["StageParameters"]["limits"] = "abc"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["StageParameters"]["limits"] is True
|
||||
|
||||
microscope_names = list(configuration["configuration"]["microscopes"].keys())
|
||||
for microscope_name in microscope_names:
|
||||
for k in ["xy_step", "z_step", "f_step", "theta_step"]:
|
||||
experiment["StageParameters"][microscope_name][k] = "abc"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert isinstance(
|
||||
experiment["StageParameters"][microscope_name][k], int
|
||||
)
|
||||
|
||||
# MicroscopeState
|
||||
experiment["MicroscopeState"]["microscope_name"] = "nonexist_microscope"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert experiment["MicroscopeState"]["microscope_name"] == microscope_names[0]
|
||||
|
||||
experiment["MicroscopeState"]["zoom"] = "abc"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert (
|
||||
experiment["MicroscopeState"]["zoom"]
|
||||
== list(
|
||||
configuration["configuration"]["microscopes"][microscope_names[0]][
|
||||
"zoom"
|
||||
]["position"].keys()
|
||||
)[0]
|
||||
)
|
||||
|
||||
for k in [
|
||||
"start_position",
|
||||
"end_position",
|
||||
"step_size",
|
||||
"number_z_steps",
|
||||
"timepoints",
|
||||
"stack_acq_time",
|
||||
"timepoint_interval",
|
||||
"experiment_duration",
|
||||
"stack_z_origin",
|
||||
"stack_focus_origin",
|
||||
"start_focus",
|
||||
"end_focus",
|
||||
"abs_z_start",
|
||||
"abs_z_end",
|
||||
]:
|
||||
experiment["MicroscopeState"][k] = "nonsense_value"
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert isinstance(experiment["MicroscopeState"][k], int) or isinstance(
|
||||
experiment["MicroscopeState"][k], float
|
||||
)
|
||||
|
||||
# channels
|
||||
experiment["MicroscopeState"]["channels"] = [
|
||||
{
|
||||
"is_selected": True,
|
||||
"laser": "488nm",
|
||||
"laser_index": 0,
|
||||
"filter": "Empty-Alignment",
|
||||
"filter_position": 0,
|
||||
"camera_exposure_time": 200.0,
|
||||
"laser_power": 20.0,
|
||||
"interval_time": 5.0,
|
||||
"defocus": 0.0,
|
||||
}
|
||||
]
|
||||
# number_of_filter_wheels =
|
||||
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert type(experiment["MicroscopeState"]["channels"]) is DictProxy
|
||||
assert len(list(experiment["MicroscopeState"]["channels"].keys())) == 0
|
||||
|
||||
experiment["MicroscopeState"]["channels"] = {
|
||||
"channel_0": {
|
||||
"is_selected": True,
|
||||
"laser": "488nm",
|
||||
"laser_index": 0,
|
||||
"filter": "Empty-Alignment",
|
||||
"filter_position": 0,
|
||||
"camera_exposure_time": 200.0,
|
||||
"laser_power": 20.0,
|
||||
"interval_time": 5.0,
|
||||
"defocus": 0.0,
|
||||
}
|
||||
}
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert type(experiment["MicroscopeState"]["channels"]) is DictProxy
|
||||
assert len(list(experiment["MicroscopeState"]["channels"].keys())) == 0
|
||||
|
||||
experiment["MicroscopeState"]["channels"] = {
|
||||
"channel_100": {
|
||||
"is_selected": True,
|
||||
"laser": "488nm",
|
||||
"laser_index": 0,
|
||||
"filter": "Empty-Alignment",
|
||||
"filter_position": 0,
|
||||
"camera_exposure_time": 200.0,
|
||||
"laser_power": 20.0,
|
||||
"interval_time": 5.0,
|
||||
"defocus": 0.0,
|
||||
}
|
||||
}
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert type(experiment["MicroscopeState"]["channels"]) is DictProxy
|
||||
assert len(list(experiment["MicroscopeState"]["channels"].keys())) == 0
|
||||
|
||||
microscope_name = experiment["MicroscopeState"]["microscope_name"]
|
||||
lasers = [
|
||||
f"{laser['wavelength']}nm"
|
||||
for laser in configuration["configuration"]["microscopes"][microscope_name][
|
||||
"laser"
|
||||
]
|
||||
]
|
||||
filterwheels = list(
|
||||
configuration["configuration"]["microscopes"][microscope_name][
|
||||
"filter_wheel"
|
||||
][0]["available_filters"].keys()
|
||||
)
|
||||
config.update_config_dict(
|
||||
self.manager,
|
||||
experiment["MicroscopeState"]["channels"],
|
||||
"channel_2",
|
||||
{
|
||||
"is_selected": 1,
|
||||
"laser": "48nm",
|
||||
"laser_index": -1,
|
||||
"filter_wheel_0": "nonexsit_filter_***",
|
||||
"filter_position_0": 1,
|
||||
"camera_exposure_time": -200.0,
|
||||
"laser_power": "a",
|
||||
"interval_time": -3,
|
||||
"defocus": "a",
|
||||
},
|
||||
)
|
||||
expected_value = {
|
||||
"is_selected": False,
|
||||
"laser": lasers[0],
|
||||
"laser_index": 0,
|
||||
"filter_wheel_0": filterwheels[0],
|
||||
"filter_position_0": 0,
|
||||
"camera_exposure_time": 200.0,
|
||||
"laser_power": 20.0,
|
||||
"interval_time": 0.0,
|
||||
"defocus": 0.0,
|
||||
}
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert type(experiment["MicroscopeState"]["channels"]) is DictProxy
|
||||
assert "channel_2" in experiment["MicroscopeState"]["channels"].keys()
|
||||
for k in expected_value:
|
||||
assert (
|
||||
experiment["MicroscopeState"]["channels"]["channel_2"][k]
|
||||
== expected_value[k]
|
||||
)
|
||||
|
||||
config.update_config_dict(
|
||||
self.manager,
|
||||
experiment["MicroscopeState"]["channels"],
|
||||
"channel_2",
|
||||
{
|
||||
"is_selected": 1,
|
||||
"laser": lasers[1],
|
||||
"laser_index": 3,
|
||||
"filter_wheel_0": filterwheels[2],
|
||||
"filter_position_0": 1,
|
||||
"camera_exposure_time": -200.0,
|
||||
"laser_power": "a",
|
||||
"interval_time": -3,
|
||||
"defocus": "a",
|
||||
},
|
||||
)
|
||||
expected_value = {
|
||||
"is_selected": False,
|
||||
"laser": lasers[1],
|
||||
"laser_index": 1,
|
||||
"filter_wheel_0": filterwheels[2],
|
||||
"filter_position_0": 2,
|
||||
"camera_exposure_time": 200.0,
|
||||
"laser_power": 20.0,
|
||||
"interval_time": 0.0,
|
||||
"defocus": 0.0,
|
||||
}
|
||||
config.verify_experiment_config(self.manager, configuration)
|
||||
assert type(experiment["MicroscopeState"]["channels"]) is DictProxy
|
||||
assert "channel_2" in experiment["MicroscopeState"]["channels"].keys()
|
||||
for k in expected_value:
|
||||
assert (
|
||||
experiment["MicroscopeState"]["channels"]["channel_2"][k]
|
||||
== expected_value[k]
|
||||
)
|
||||
|
||||
def select_random_entries_from_list(self, parameter_list):
|
||||
n = random.randint(1, len(parameter_list))
|
||||
return random.choices(parameter_list, k=n)
|
||||
|
||||
def delete_random_entries_from_dict(self, parameter_list, parameter_dict):
|
||||
n = random.randint(1, len(parameter_list))
|
||||
deleted_parameters = random.choices(parameter_list, k=n)
|
||||
for k in deleted_parameters:
|
||||
if k in parameter_dict.keys():
|
||||
del parameter_dict[k]
|
||||
return deleted_parameters
|
||||
|
||||
def test_load_empty_multi_positions(self):
|
||||
positions_file_path = os.path.join(self.test_root, "multi_positions.yml")
|
||||
with open(positions_file_path, "w") as f:
|
||||
f.write("")
|
||||
positions = load_yaml_file(positions_file_path)
|
||||
new_positions = config.verify_positions_config(positions)
|
||||
assert isinstance(new_positions, list)
|
||||
assert len(new_positions) == 0
|
||||
|
||||
def test_load_multi_positions_with_corrupted_values(self):
|
||||
positions = [
|
||||
[1, 2, 3],
|
||||
["a", "b", "c", 1, 2],
|
||||
[
|
||||
10,
|
||||
"a",
|
||||
30,
|
||||
40,
|
||||
],
|
||||
]
|
||||
new_positions = config.verify_positions_config(positions)
|
||||
assert isinstance(new_positions, list)
|
||||
assert len(new_positions) == 1
|
||||
|
||||
positions = [
|
||||
[1, 2, 3],
|
||||
["a", "b", "c", 1, 2],
|
||||
[1, 2, 3, 4, 5],
|
||||
[
|
||||
10,
|
||||
"a",
|
||||
30,
|
||||
40,
|
||||
],
|
||||
]
|
||||
new_positions = config.verify_positions_config(positions)
|
||||
assert isinstance(new_positions, list)
|
||||
assert len(new_positions) == 2
|
||||
|
||||
positions = [
|
||||
[1, 2, 3],
|
||||
["a", "b", "c", 1, 2],
|
||||
[1, 2, 3, 4, 5],
|
||||
[
|
||||
10,
|
||||
"a",
|
||||
30,
|
||||
40,
|
||||
],
|
||||
[1, 2, 3, 4, 5, 6],
|
||||
]
|
||||
new_positions = config.verify_positions_config(positions)
|
||||
assert isinstance(new_positions, list)
|
||||
assert len(new_positions) == 3
|
||||
Reference in New Issue
Block a user