From b8b6d7d6a7c6f41cf810e53abd33f04eded315ca Mon Sep 17 00:00:00 2001 From: Daniel Toloudis Date: Thu, 31 Oct 2019 11:16:46 -0700 Subject: [PATCH 1/7] fix imread bug and allow AICSImage class to close its reader --- aicsimageio/aics_image.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/aicsimageio/aics_image.py b/aicsimageio/aics_image.py index b41264259..8d5899b8a 100644 --- a/aicsimageio/aics_image.py +++ b/aicsimageio/aics_image.py @@ -33,18 +33,29 @@ class AICSImage: zstack_t10 = data[0, 10, 0, :, :, :] # access the S=0, T=10, C=0 "ZYX" cube - File Examples ------------- + + with AICSImage("filename.ome.tif") as img: + # do work with img + data = img.data + metadata = img.metadata + # img will be closed automatically at end of scope + OmeTif img = AICSImage("filename.ome.tif") + img.close() CZI (Zeiss) img = AICSImage("filename.czi") or AICSImage("filename.czi", max_workers=8) + img.close() Tiff img = AICSImage("filename.tif") + img.close() Png/Gif/... img = AICSImage("filename.png") + img.close() img = AICSImage("filename.gif") + img.close() Bytestream Examples ------------------- @@ -291,9 +302,20 @@ def get_channel_names(self, scene: int = 0): names = [str(i) for i in range(self.size_c)] return names + def close(self): + self.reader.close() + def __repr__(self) -> str: return f"" + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + -def imread(data: types.ImageLike, **kwargs): - return AICSImage(data, **kwargs).data +def imread(data: types.ImageLike, **kwargs) -> np.ndarray: + with AICSImage(data, **kwargs) as image: + imagedata = image.data + return imagedata From d91efa11d108a3cb6c36a7425e54aa4509b1c97d Mon Sep 17 00:00:00 2001 From: Daniel Toloudis Date: Thu, 31 Oct 2019 11:46:39 -0700 Subject: [PATCH 2/7] add test --- aicsimageio/tests/test_aics_image.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/aicsimageio/tests/test_aics_image.py b/aicsimageio/tests/test_aics_image.py index 83148174d..7e25a3618 100644 --- a/aicsimageio/tests/test_aics_image.py +++ b/aicsimageio/tests/test_aics_image.py @@ -1,6 +1,7 @@ from xml.etree import cElementTree as etree import numpy as np +import os import pytest from aicsimageio import AICSImage, exceptions, imread, readers @@ -197,3 +198,16 @@ def test_imread(resources_dir, filename, expected_shape): def test_channel_names(resources_dir, filename, expected_channel_names): img = AICSImage(resources_dir / filename) assert img.get_channel_names() == expected_channel_names + + +def test_aicsimage_close(resources_dir): + filename = resources_dir / PNG_FILE + with pytest.raises(IOError): + img = AICSImage(filename) + img.metadata + os.rename(filename, filename) + # there is no assertion because the test here is that + # the following code should not raise. + with AICSImage(filename) as img: + img.metadata + os.rename(filename, filename) From 2a3198502fa05ec3ab46adbdd729049448c0db80 Mon Sep 17 00:00:00 2001 From: Daniel Toloudis Date: Thu, 31 Oct 2019 11:56:37 -0700 Subject: [PATCH 3/7] fix test --- aicsimageio/tests/test_aics_image.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/aicsimageio/tests/test_aics_image.py b/aicsimageio/tests/test_aics_image.py index 7e25a3618..014ebd0ce 100644 --- a/aicsimageio/tests/test_aics_image.py +++ b/aicsimageio/tests/test_aics_image.py @@ -3,6 +3,7 @@ import numpy as np import os import pytest +import shutil from aicsimageio import AICSImage, exceptions, imread, readers from aicsimageio.vendor import omexml @@ -202,12 +203,14 @@ def test_channel_names(resources_dir, filename, expected_channel_names): def test_aicsimage_close(resources_dir): filename = resources_dir / PNG_FILE + tempfilename = resources_dir / "temp.png" + shutil.copy(filename, tempfilename) with pytest.raises(IOError): - img = AICSImage(filename) + img = AICSImage(tempfilename) img.metadata - os.rename(filename, filename) + os.remove(tempfilename) # there is no assertion because the test here is that # the following code should not raise. - with AICSImage(filename) as img: + with AICSImage(tempfilename) as img: img.metadata - os.rename(filename, filename) + os.remove(tempfilename) From aa116dcab4e7e722505ef88aa351ef8bc23334d6 Mon Sep 17 00:00:00 2001 From: Daniel Toloudis Date: Thu, 31 Oct 2019 13:40:38 -0700 Subject: [PATCH 4/7] simplify test --- aicsimageio/tests/test_aics_image.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/aicsimageio/tests/test_aics_image.py b/aicsimageio/tests/test_aics_image.py index 014ebd0ce..1534ff318 100644 --- a/aicsimageio/tests/test_aics_image.py +++ b/aicsimageio/tests/test_aics_image.py @@ -1,9 +1,7 @@ from xml.etree import cElementTree as etree import numpy as np -import os import pytest -import shutil from aicsimageio import AICSImage, exceptions, imread, readers from aicsimageio.vendor import omexml @@ -203,14 +201,11 @@ def test_channel_names(resources_dir, filename, expected_channel_names): def test_aicsimage_close(resources_dir): filename = resources_dir / PNG_FILE - tempfilename = resources_dir / "temp.png" - shutil.copy(filename, tempfilename) - with pytest.raises(IOError): - img = AICSImage(tempfilename) - img.metadata - os.remove(tempfilename) + img = AICSImage(filename) + assert img.reader._bytes.closed is False + # there is no assertion because the test here is that # the following code should not raise. - with AICSImage(tempfilename) as img: + with AICSImage(filename) as img: img.metadata - os.remove(tempfilename) + assert img.reader._bytes.closed is True From e68e588835d9659ab128badfd957eda7c3282be9 Mon Sep 17 00:00:00 2001 From: Daniel Toloudis Date: Thu, 31 Oct 2019 13:43:33 -0700 Subject: [PATCH 5/7] minor cleanup --- aicsimageio/tests/test_aics_image.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aicsimageio/tests/test_aics_image.py b/aicsimageio/tests/test_aics_image.py index 1534ff318..34f59f1cf 100644 --- a/aicsimageio/tests/test_aics_image.py +++ b/aicsimageio/tests/test_aics_image.py @@ -203,9 +203,8 @@ def test_aicsimage_close(resources_dir): filename = resources_dir / PNG_FILE img = AICSImage(filename) assert img.reader._bytes.closed is False + img.close() - # there is no assertion because the test here is that - # the following code should not raise. with AICSImage(filename) as img: img.metadata assert img.reader._bytes.closed is True From d84798c2d6e42d2cfa2b7eb744e6ecd664809fd5 Mon Sep 17 00:00:00 2001 From: Daniel Toloudis Date: Thu, 31 Oct 2019 13:45:23 -0700 Subject: [PATCH 6/7] parameterize the test --- aicsimageio/tests/test_aics_image.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/aicsimageio/tests/test_aics_image.py b/aicsimageio/tests/test_aics_image.py index 34f59f1cf..65a12f497 100644 --- a/aicsimageio/tests/test_aics_image.py +++ b/aicsimageio/tests/test_aics_image.py @@ -199,12 +199,20 @@ def test_channel_names(resources_dir, filename, expected_channel_names): assert img.get_channel_names() == expected_channel_names -def test_aicsimage_close(resources_dir): - filename = resources_dir / PNG_FILE - img = AICSImage(filename) +@pytest.mark.parametrize( + "filename", + [ + PNG_FILE, + TIF_FILE, + CZI_FILE, + OME_FILE, + ], +) +def test_aicsimage_close(resources_dir, filename): + img = AICSImage(resources_dir / filename) assert img.reader._bytes.closed is False img.close() - with AICSImage(filename) as img: + with AICSImage(resources_dir / filename) as img: img.metadata assert img.reader._bytes.closed is True From 823795c293f4bbd72e1ac88648643f7b3a71fa9a Mon Sep 17 00:00:00 2001 From: Daniel Toloudis Date: Thu, 31 Oct 2019 15:43:56 -0700 Subject: [PATCH 7/7] update readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e5ae0fc70..ae9d2b644 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,17 @@ from aicsimageio import AICSImage, imread im = imread("/path/to/your/file_or_buffer.ome.tiff") # For AICSImage object that -im = AICSImage("/path/to/your/file_or_buffer.ome.tiff") +with AICSImage("/path/to/your/file_or_buffer.ome.tiff") as im: + # use im object # To specify a known dimension order -im = AICSImage("/path/to/your/file_or_buffer.ome.tiff", known_dims="SYX") +with AICSImage("/path/to/your/file_or_buffer.ome.tiff", known_dims="SYX") as im: + # use im object + +# if you instantiate an AICSImage: +im = AICSImage("/path/to/your/file_or_buffer.ome.tiff") +# you should close it when done: +im.close() # Image data is stored in `data` attribute im.data # returns the image data numpy array