-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clean up tests and reorganize test artifacts (#58)
* reorganize test artifacts, refactor tests, add more fixtures * readme edits * Update tests/test_reader.py Co-authored-by: Evan Kiefl <[email protected]> Signed-off-by: Keith Cheveralls <[email protected]> * address comments --------- Signed-off-by: Keith Cheveralls <[email protected]> Co-authored-by: Evan Kiefl <[email protected]>
- Loading branch information
Showing
17 changed files
with
246 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Test artifacts | ||
|
||
This directory contains test artifacts for the `readlif` package. These artifacts consist of example LIF files from various sources. In some cases, they are paired with expected outputs in the form of TIFF files containing the image data for selected 2D (X-Y) planes in the corresponding LIF file. In these cases, there is one TIFF file for each plane, and the TIFF files are named according to the plane they represent. | ||
|
||
## About the LIF files | ||
|
||
These are brief informal notes about the contents of the LIF files in this directory. They were determined by manually opening the LIF files in Fiji using the BioFormats plugin and examining the metadata. | ||
|
||
### `xyzt-example/xyzt-example.lif` | ||
|
||
Contains a single image. 1024 x 1024. 8-bit. Shape: 2C, 3T, 3Z. | ||
|
||
### `xz-example/xz-example.lif` | ||
|
||
Contains three images. All three are XZ in the first two dimensions. | ||
|
||
BioFormats labels: | ||
|
||
- xzt: 128 x 128; 2C x 20T | ||
- xzy: 128 x 128; 2C x 23Z (note: the 'y' dimension in 'xzy' is loaded as Z by BioFormats) | ||
- xz: 512 x 512; 2C. | ||
|
||
### `misc/LeicaLASX_wavelength-sweep_example.lif` | ||
|
||
Contains three images. All 64 x 64. The time dimension appears to be a Lambda scan but the metadata implies it was a time dimension (it contains `Plane` elements with `"deltaT"` attributes). BioFormats loads the images as XYZT. | ||
|
||
The BioFormats labels of the three images are (in pseudo-regex): | ||
|
||
``` | ||
x y (lambdaEmi|lambdaExc): 64x64; (20T|15T|(11Z x 20T)) | ||
``` | ||
|
||
### `misc/new_lasx.lif` | ||
|
||
Contains a single image. 1024 x 1024. 8-bit. Shape: 2C, 39Z. | ||
|
||
This file was added in #36; there is no other documentation of what it contains. |
File renamed without changes.
File renamed without changes.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import pathlib | ||
|
||
import pytest | ||
|
||
|
||
@pytest.fixture | ||
def artifacts_dirpath(): | ||
return pathlib.Path(__file__).parent / "artifacts" | ||
|
||
|
||
@pytest.fixture | ||
def valid_lif_filepath(artifacts_dirpath): | ||
""" | ||
The filepath to a LIF file that is valid and can be read by the reader. | ||
""" | ||
return artifacts_dirpath / "misc" / "new_lasx.lif" | ||
|
||
|
||
@pytest.fixture | ||
def valid_single_image_lif_filepath(artifacts_dirpath): | ||
""" | ||
The filepath to a LIF file that contains only one image. | ||
""" | ||
return artifacts_dirpath / "xyzt-example" / "xyzt-example.lif" | ||
|
||
|
||
@pytest.fixture | ||
def valid_multi_image_lif_filepath(artifacts_dirpath): | ||
""" | ||
The filepath to a LIF file that contains multiple images. | ||
""" | ||
return artifacts_dirpath / "xz-example" / "xz-example.lif" | ||
|
||
|
||
@pytest.fixture | ||
def valid_tiff_filepath(artifacts_dirpath): | ||
""" | ||
The filepath to a TIFF file that is valid. | ||
""" | ||
return artifacts_dirpath / "misc" / "valid-tiff.tif" | ||
|
||
|
||
@pytest.fixture | ||
def xyzt_example_lif_filepath(artifacts_dirpath): | ||
""" | ||
The filepath to a LIF file that contains XYZT data. | ||
""" | ||
return artifacts_dirpath / "xyzt-example" / "xyzt-example.lif" | ||
|
||
|
||
@pytest.fixture | ||
def xz_example_lif_filepath(artifacts_dirpath): | ||
""" | ||
The filepath to a LIF file that contains an image in which the second dimension | ||
is Z rather than Y. | ||
""" | ||
return artifacts_dirpath / "xz-example" / "xz-example.lif" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import pytest | ||
from PIL import Image | ||
|
||
from readlif.reader import LifFile | ||
|
||
|
||
def test_lif_file_with_file_path(valid_lif_filepath): | ||
lif_image = LifFile(valid_lif_filepath).get_image(0) | ||
# This should not raise an error. | ||
lif_image.get_frame(z=0, t=0, c=0) | ||
|
||
|
||
def test_lif_file_with_file_buffer(valid_lif_filepath): | ||
with open(valid_lif_filepath, "rb") as file: | ||
lif_image = LifFile(file).get_image(0) | ||
# This should not raise an error. | ||
lif_image.get_frame(z=0, t=0, c=0) | ||
|
||
|
||
def test_lif_file_with_non_lif_files(tmp_path, artifacts_dirpath): | ||
with open(tmp_path / "not-a-lif-file.txt", "w") as file: | ||
with pytest.raises(ValueError): | ||
LifFile(file) | ||
|
||
with pytest.raises(ValueError): | ||
LifFile(artifacts_dirpath / "misc" / "valid-tiff.tif") | ||
|
||
|
||
def test_lif_file_with_single_image_lif(valid_single_image_lif_filepath): | ||
lif_file = LifFile(valid_single_image_lif_filepath) | ||
assert repr(lif_file) == "'LifFile object with 1 image'" | ||
assert len(lif_file.image_list) == 1 | ||
with pytest.raises(ValueError): | ||
lif_file.get_image(1) | ||
|
||
|
||
def test_lif_file_get_iter_image(valid_single_image_lif_filepath, valid_multi_image_lif_filepath): | ||
images = [image for image in LifFile(valid_single_image_lif_filepath).get_iter_image()] | ||
assert len(images) == 1 | ||
|
||
images = [image for image in LifFile(valid_multi_image_lif_filepath).get_iter_image()] | ||
assert len(images) > 1 | ||
|
||
|
||
def test_lif_file_with_new_lasx(artifacts_dirpath): | ||
""" | ||
TODO(KC): figure out what is special or "new" about the "new_lasx.lif" file. | ||
""" | ||
lif_file = LifFile(artifacts_dirpath / "misc" / "new_lasx.lif") | ||
assert len(lif_file.image_list) == 1 | ||
|
||
|
||
def test_lif_image_get_frame_out_of_range_args(xyzt_example_lif_filepath): | ||
lif_image = LifFile(xyzt_example_lif_filepath).get_image(0) | ||
|
||
for dimension_kwarg, lif_image_attr in [ | ||
("z", "nz"), | ||
("t", "nt"), | ||
("c", "channels"), | ||
("m", "n_mosaic"), | ||
]: | ||
max_index_for_dimension = getattr(lif_image, lif_image_attr) - 1 | ||
lif_image.get_frame(**{dimension_kwarg: max_index_for_dimension}) | ||
with pytest.raises(ValueError): | ||
lif_image.get_frame(**{dimension_kwarg: max_index_for_dimension + 1}) | ||
|
||
# TODO: use a better-justified out of range index for this test. | ||
with pytest.raises(ValueError): | ||
lif_image._get_item(100) | ||
|
||
|
||
def test_lif_image_settings(xz_example_lif_filepath): | ||
""" | ||
TODO: expand this test to cover more attributes and use more than one LIF file. | ||
""" | ||
lif_image = LifFile(xz_example_lif_filepath).get_image(0) | ||
assert lif_image.settings["ObjectiveNumber"] == "11506353" | ||
|
||
|
||
def test_lif_image_attributes(xyzt_example_lif_filepath): | ||
""" | ||
TODO: expand this test to cover more attributes and use more than one LIF file. | ||
""" | ||
lif_image = LifFile(xyzt_example_lif_filepath).get_image(0) | ||
assert lif_image.scale[0] == pytest.approx(9.8709062997224) | ||
assert lif_image.bit_depth[0] == 8 | ||
|
||
|
||
def test_lif_image_get_frame(xyzt_example_lif_filepath): | ||
lif_image = LifFile(xyzt_example_lif_filepath).get_image(0) | ||
czt_pairs = [[0, 0, 0], [0, 2, 0], [0, 2, 2], [1, 0, 0]] | ||
for c, z, t in czt_pairs: | ||
reference_image = Image.open( | ||
xyzt_example_lif_filepath.parent / "expected-outputs" / f"c{c}z{z}t{t}.tif" | ||
) | ||
lif_image_frame = lif_image.get_frame(z=z, t=t, c=c) | ||
assert lif_image_frame.tobytes() == reference_image.tobytes() | ||
|
||
|
||
def test_lif_image_get_plane(xyzt_example_lif_filepath): | ||
""" | ||
TODO: eliminate duplication with `test_lif_image_get_frame`. | ||
""" | ||
lif_image = LifFile(xyzt_example_lif_filepath).get_image(0) | ||
czt_pairs = [[0, 0, 0], [0, 2, 0], [0, 2, 2], [1, 0, 0]] | ||
for c, z, t in czt_pairs: | ||
reference_image = Image.open( | ||
xyzt_example_lif_filepath.parent / "expected-outputs" / f"c{c}z{z}t{t}.tif" | ||
) | ||
lif_image_plane = lif_image.get_plane(c=c, requested_dims={3: z, 4: t}) | ||
assert lif_image_plane.tobytes() == reference_image.tobytes() | ||
|
||
|
||
def test_lif_image_get_plane_on_xz_image(xz_example_lif_filepath): | ||
lif_image = LifFile(xz_example_lif_filepath).get_image(0) | ||
for c, t in [(0, 0), (1, 8)]: | ||
reference_image = Image.open( | ||
xz_example_lif_filepath.parent / "expected-outputs" / f"c{c}t{t}.tif" | ||
) | ||
lif_image_plane = lif_image.get_plane(c=c, requested_dims={4: t}) | ||
assert lif_image_plane.tobytes() == reference_image.tobytes() | ||
|
||
|
||
def test_lif_image_get_plane_nonexistent_plane(artifacts_dirpath): | ||
""" | ||
TODO: determine if another, less mysterious LIF file can be used for this test. | ||
""" | ||
lif_image = LifFile( | ||
artifacts_dirpath / "misc" / "LeicaLASX_wavelength-sweep_example.lif" | ||
).get_image(0) | ||
with pytest.raises(NotImplementedError): | ||
lif_image.get_plane(display_dims=(1, 5), c=0, requested_dims={2: 31}) | ||
|
||
|
||
def test_lif_image_repr(xyzt_example_lif_filepath): | ||
lif_image = LifFile(xyzt_example_lif_filepath).get_image(0) | ||
assert ( | ||
repr(lif_image) == "'LifImage object with dimensions: Dims(x=1024, y=1024, z=3, t=3, m=1)'" | ||
) | ||
|
||
|
||
def test_lif_image_get_iters(xyzt_example_lif_filepath): | ||
lif_image = LifFile(xyzt_example_lif_filepath).get_image(0) | ||
assert len([image for image in lif_image.get_iter_c()]) == 2 | ||
assert len([image for image in lif_image.get_iter_t()]) == 3 | ||
assert len([image for image in lif_image.get_iter_z()]) == 3 |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from readlif.utilities import get_xml | ||
|
||
|
||
def test_get_xml_header(xyzt_example_lif_filepath): | ||
_, test = get_xml(xyzt_example_lif_filepath) | ||
assert test.startswith('<LMSDataContainerHeader Version="2">') |