def test_merge_config(): # test data _, path_in, path_out = setup_test_data(medium_index=1.30, pxsize=1.12e-6, method="image", model="projection", refraction_increment=1.1) # profile _, path_profile = tempfile.mkstemp(prefix="drymass_test_config_", suffix=".cfg") cfg = config.ConfigFile(path=path_profile) cfg.path.write_text("[meta]\n" + "medium index = 1.31\n" + "pixel size um = None\n" + "[sphere]\n" + "method = image\n" + "model = rytov\n") cfg2 = config.ConfigFile(path=path_out) assert cfg2["sphere"]["refraction increment"] == 1.1, "for test case" assert cfg2["meta"]["pixel size um"] == 1.12, "for test case" # apply profile (merge with original configuration) dialog.main(path=path_in, profile=path_profile) # Sanity checks in case DryMass defaults changed assert cfg["sphere"]["refraction increment"] != 1.1, "for test case" assert cfg["meta"]["pixel size um"] != 1.12, "for test case" # The following three are all valid by just copying cfg to path_out assert cfg2["meta"]["medium index"] == 1.31 assert cfg2["sphere"]["method"] == "image" assert cfg2["sphere"]["model"] == "rytov" # This one is only valid when the configs are merged assert cfg2["sphere"]["refraction increment"] == 1.1 # This one is only valid when Nones in profile do not override path_out assert cfg2["meta"]["pixel size um"] == 1.12
def test_update(): path1 = tempfile.mkdtemp(prefix="drymass_test_config_") cfg1 = config.ConfigFile(path=path1) path2 = tempfile.mkdtemp(prefix="drymass_test_config_") cfg2 = config.ConfigFile(path=path2) cfg1.path.write_text("[sphere]\nrefraction increment = 1.1\n") assert cfg2["sphere"]["refraction increment"] == .18, "defaults" cfg2.update(cfg1) assert cfg2["sphere"]["refraction increment"] == 1.1
def test_compat_081(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) # initialize config cfg.set_value("meta", "medium index", 1.3365) filepath = cfg.path # simulate old behavior data = filepath.open().read() data = data.replace("medium index = 1.3365", "medium index = nan") filepath.write_text(data) # check fix cfg2 = config.ConfigFile(path=path) assert cfg2["meta"]["medium index"] is None
def test_compat_013(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) # initialize config cfg.set_value("bg", "phase profile", "tilt") cfg.set_value("bg", "amplitude profile", "tilt") filepath = cfg.path # simulate old behavior data = filepath.open().read() data = data.replace(" profile = tilt\n", " profile = ramp\n") filepath.write_text(data) # check fix cfg2 = config.ConfigFile(path=path) assert cfg2["bg"]["phase profile"] == "tilt" assert cfg2["bg"]["amplitude profile"] == "tilt"
def setup_test_data(radius_px=30, size=200, pxsize=1e-6, medium_index=1.335, wavelength=550e-9, num=1): x = np.arange(size).reshape(-1, 1) y = np.arange(size).reshape(1, -1) cx = 80 cy = 120 r = np.sqrt((x - cx)**2 + (y - cy)**2) pha = (r < radius_px) * 1.3 amp = .5 + np.roll(pha, 10) / pha.max() qpi = qpimage.QPImage(data=(pha, amp), which_data="phase,amplitude", meta_data={"pixel size": pxsize, "medium index": medium_index, "wavelength": wavelength}) path_in = tempfile.mktemp(suffix=".h5", prefix="drymass_test_cli_sphere") path_in = pathlib.Path(path_in) with qpimage.QPSeries(h5file=path_in, h5mode="w", identifier="tt") as qps: for ii in range(num): qps.add_qpimage(qpi, identifier="image_{}".format(ii)) # add drymass configuration file path_out = path_in.with_name(path_in.name + dialog.OUTPUT_SUFFIX) path_out.mkdir() cfg = config.ConfigFile(path_out) cfg.set_value(section="meta", key="pixel size um", value=pxsize*1e6) cfg.set_value(section="meta", key="wavelength nm", value=wavelength*1e9) cfg.set_value(section="meta", key="medium index", value=medium_index) cfg.set_value(section="specimen", key="size um", value=radius_px*2*pxsize*1e6) cfg.set_value(section="sphere", key="method", value="edge") cfg.set_value(section="sphere", key="model", value="projection") return qpi, path_in, path_out
def test_exclude_roi_bad(): _, path_in, path_out = setup_test_data(num=2) cli_extract_roi(path=path_in) cfg = config.ConfigFile(path_out) h5data = cli_extract_roi(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data) as qps: assert len(qps) == 2 # bad image cfg.set_value(section="roi", key="ignore data", value="3") try: cli_extract_roi(path=path_in, ret_data=True) except ValueError: pass else: assert False # bad roi cfg.set_value(section="roi", key="ignore data", value="1.2") try: cli_extract_roi(path=path_in, ret_data=True) except ValueError: pass else: assert False # bad image and roi cfg.set_value(section="roi", key="ignore data", value="4.2") try: cli_extract_roi(path=path_in, ret_data=True) except ValueError: pass else: assert False
def test_exclude_roi(): _, path_in, path_out = setup_test_data(num=2) cli_extract_roi(path=path_in) cfg = config.ConfigFile(path_out) h5data = cli_extract_roi(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data) as qps: assert len(qps) == 2 # remove first image cfg.set_value(section="roi", key="ignore data", value="1.1") h5data = cli_extract_roi(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data) as qps: assert len(qps) == 1 # remove second image cfg.set_value(section="roi", key="ignore data", value="2") h5data = cli_extract_roi(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data) as qps: assert len(qps) == 1 # remove all cfg.set_value(section="roi", key="ignore data", value=["1", "2"]) h5data = cli_extract_roi(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data) as qps: assert len(qps) == 0
def test_convert_with_profile(): cfgpath = setup_config(pxsize=1.34e-6, medium_index=1.346, wavelength=554.2e-9) _, path_in, path_out = setup_test_data() argsadd = argparse.Namespace(subparser_name="add", name="test_8440_prof_convert", path=cfgpath) profile.cli_profile(args=argsadd) try: # perform conversion h5data = cli_convert(path=path_in, ret_data=True, profile="test_8440_prof_convert") cfg = config.ConfigFile(path_out) assert np.allclose(cfg["meta"]["medium index"], 1.346) assert np.allclose(cfg["meta"]["pixel size um"], 1.34) assert np.allclose(cfg["meta"]["wavelength nm"], 554.2) with qpimage.QPSeries(h5file=h5data, h5mode="r") as qps: assert np.allclose(qps[0]["medium index"], 1.346) assert np.allclose(qps[0]["pixel size"], 1.34e-6) assert np.allclose(qps[0]["wavelength"], 554.2e-9) except BaseException: raise finally: # cleanup argsrem = argparse.Namespace(subparser_name="remove", name="test_8440_prof_convert") profile.cli_profile(args=argsrem)
def test_write_complete(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) cfg.path.write_text("[bg]\nenabled = True\n") # This triggers a completion of the configuration section [bg] assert cfg["bg"]["phase profile"] == "tilt"
def test_use_meta_data_from_experiment(): tmp_path = pathlib.Path(tempfile.mkdtemp()) # create test dataset radius_px = 30 size = 200 pxsize = 1e-6 wavelength = 512e-9 medium_index = 1.33123 x = np.arange(size).reshape(-1, 1) y = np.arange(size).reshape(1, -1) cx = 80 cy = 120 r = np.sqrt((x - cx)**2 + (y - cy)**2) pha = (r < radius_px) * 1.3 amp = .5 + np.roll(pha, 10) / pha.max() qpi_path = tmp_path / "test.h5" with qpimage.QPImage(data=(pha, amp), which_data="phase,amplitude", h5file=qpi_path, meta_data={ "pixel size": pxsize, "wavelength": wavelength, "medium index": medium_index }): pass # this must run without any user input required pin, pout = dialog.main( path=qpi_path, req_meta=["pixel size um", "wavelength nm", "medium index"], ) assert str(pin) == str(qpi_path.resolve()) cfg = config.ConfigFile(path=pout) assert cfg["meta"]["medium index"] == medium_index assert cfg["meta"]["pixel size um"] == pxsize * 1e6 assert cfg["meta"]["wavelength nm"] == wavelength * 1e9
def test_force_roi(): qpi, path_in, path_out = setup_test_data(num=2) cfg = config.ConfigFile(path_out) cfg.set_value(section="meta", key="pixel size um", value=1) cfg.set_value(section="roi", key="force", value=((10, 160), (24, 178))) h5data = cli_extract_roi(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data) as qps: assert qps[0].shape == (150, 154) assert np.allclose(qpi.pha[10:160, 24:178], qps[0].pha) assert np.all(qps[0].pha == qps[1].pha)
def test_dtype(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) cfg["specimen"] = {"size um": 11.3} assert np.allclose(cfg["specimen"]["size um"], 11.3) cfg.set_value(section="bg", key="amplitude border px", value=6.3) assert isinstance(cfg["bg"]["amplitude border px"], int) assert np.allclose(cfg["bg"]["amplitude border px"], 6)
def test_compat_015(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) # initialize config cfg.set_value("roi", "dist border px", 3) cfg.set_value("roi", "exclude overlap px", 5) cfg.set_value("roi", "pad border px", 7) filepath = cfg.path # simulate old behavior data = filepath.open().read() data = data.replace("dist border px = ", "dist border = ") data = data.replace("exclude overlap px = ", "exclude overlap = ") data = data.replace("pad border px = ", "pad border = ") filepath.write_text(data) # check fix cfg2 = config.ConfigFile(path=path) assert cfg2["roi"]["dist border px"] == 3 assert cfg2["roi"]["exclude overlap px"] == 5 assert cfg2["roi"]["pad border px"] == 7
def test_bg_corr_index(): _qpi, path_in, path_out = setup_test_data(num=2) cfg = config.ConfigFile(path_out) cfg.set_value(section="bg", key="phase data", value=1) cfg.set_value(section="bg", key="amplitude data", value=1) h5data = cli_convert(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data, h5mode="r") as qps: assert np.all(qps[0].pha == 0) assert np.all(qps[0].amp == 1)
def test_invalid_2(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) cfg.path.write_text("[bg]\nenabled = bad value\n") try: cfg["bg"] except ValueError: pass else: assert False, "invalid value should not work (bool expected)" finally: cfg.path.write_text("")
def setup_config(pxsize=1e-6, medium_index=1.335, wavelength=550e-9): _, path = tempfile.mkstemp(prefix="drymass_test_config_", suffix=".cfg") cfg = config.ConfigFile(path=path) cfg.set_value("bg", "phase profile", "tilt") cfg.set_value("bg", "amplitude profile", "tilt") cfg.set_value("roi", "dist border px", 3) cfg.set_value("roi", "exclude overlap px", 5) cfg.set_value("roi", "pad border px", 7) cfg.set_value(section="meta", key="pixel size um", value=pxsize * 1e6) cfg.set_value(section="meta", key="wavelength nm", value=wavelength * 1e9) cfg.set_value(section="meta", key="medium index", value=medium_index) return cfg.path
def test_bg_corr_file_relative(): _bgqpi, bg_path_in, bg_path_out = setup_test_data(num=1) _qpi, path_in, path_out = setup_test_data(num=2) cfg = config.ConfigFile(path_out) cfg.set_value(section="bg", key="phase data", value=str(bg_path_in.relative_to(path_in.parent))) cfg.set_value(section="bg", key="amplitude data", value=str(bg_path_in.relative_to(path_in.parent))) h5data = cli_convert(path=path_in, ret_data=True) with qpimage.QPSeries(h5file=h5data, h5mode="r") as qps: assert np.all(qps[0].pha == 0) assert np.all(qps[0].amp == 1)
def test_extract_meta_data(): """qpformat can automatically transfer the metadata from QPSeries files to the dataset which DryMass makes use of. """ _qpi, path_in, path_out = setup_test_data(pxsize=1.3e-6, medium_index=1.345, wavelength=555e-9, num=2, write_config=False) cli_convert(path=path_in) cfg = config.ConfigFile(path_out) assert cfg["meta"]["medium index"] == 1.345 assert cfg["meta"]["pixel size um"] == 1.3 assert cfg["meta"]["wavelength nm"] == 555
def test_reuse(): _, path_in, path_out = setup_test_data(num=2) cfg = config.ConfigFile(path_out) cfg.set_value(section="meta", key="pixel size um", value=1) h5data = cli_extract_roi(path=path_in, ret_data=True) time = h5data.stat().st_mtime # Do the same thing cli_extract_roi(path=path_in, ret_data=True) assert time == h5data.stat().st_mtime # Change something cfg.set_value(section="meta", key="pixel size um", value=1.01) cli_extract_roi(path=path_in, ret_data=True) assert time != h5data.stat().st_mtime
def test_invalid_1(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) try: cfg["invalid section"] except ValueError: pass else: assert False, "invalid section should not work" try: cfg["invalid section"] = {"key": "value"} except ValueError: pass else: assert False, "invalid section should not work" try: cfg.set_value("invalid section", "key", "value") except ValueError: pass else: assert False, "invalid section should not work" try: cfg.set_value("bg", "invalid key", "value") except ValueError: pass else: assert False, "invalid key should not work" try: cfg.set_value("bg", "enabled", "invalid value") except ValueError: pass else: assert False, "invalid value should not work (bool expected)"
def test_basic(): path = tempfile.mkdtemp(prefix="drymass_test_config_") cfg = config.ConfigFile(path=path) assert isinstance(cfg["bg"], dict)