From c7fc56daf0c87c04ad6d54e97f4d078283a2042d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 05:48:13 +0000 Subject: [PATCH 01/28] Initial plan From e4ce70ec6f576549e82aa86d6412f46383874f87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 06:02:56 +0000 Subject: [PATCH 02/28] Replace aicsimageio with bioio in imports and class references Co-authored-by: pr4deepr <13831458+pr4deepr@users.noreply.github.com> --- core/lls_core/deconvolution.py | 6 +++--- core/lls_core/models/deskew.py | 16 +++++++-------- core/lls_core/types.py | 34 ++++++++++++++++---------------- core/pyproject.toml | 4 ++-- core/tests/test_cli.py | 8 ++++---- core/tests/utils.py | 4 ++-- plugin/napari_lattice/fields.py | 2 +- plugin/napari_lattice/reader.py | 14 ++++++------- plugin/pyproject.toml | 4 ++-- plugin/tests/test_dock_widget.py | 6 +++--- 10 files changed, 49 insertions(+), 49 deletions(-) diff --git a/core/lls_core/deconvolution.py b/core/lls_core/deconvolution.py index f42863cb..4a03bf8a 100644 --- a/core/lls_core/deconvolution.py +++ b/core/lls_core/deconvolution.py @@ -7,7 +7,7 @@ import logging import importlib.util from typing import Collection, Iterable,Union,Literal, Optional, TYPE_CHECKING -from aicsimageio.aics_image import AICSImage +from bioio import BioImage from skimage.io import imread from aicspylibczi import CziFile from numpy.typing import NDArray @@ -79,8 +79,8 @@ def read_psf(psf_paths: Collection[Path], if len(psf_aics_data.shape) != 3: raise ValueError(f"PSF should be a 3D image (shape of 3), but got {psf_aics.shape}") else: - #Use AICSImageIO - psf_aics = AICSImage(str(psf)) + #Use BioIO + psf_aics = BioImage(str(psf)) psf_aics_data = psf_aics.data[0][0] psf_aics_data = pad_image_nearest_multiple( img=psf_aics_data, nearest_multiple=16) diff --git a/core/lls_core/models/deskew.py b/core/lls_core/models/deskew.py index a8cb1c11..64e5563b 100644 --- a/core/lls_core/models/deskew.py +++ b/core/lls_core/models/deskew.py @@ -16,7 +16,7 @@ import numpy as np if TYPE_CHECKING: - from aicsimageio.types import PhysicalPixelSizes + from bioio import PhysicalPixelSizes class DefinedPixelSizes(FieldAccessModel): """ @@ -161,7 +161,7 @@ def convert_skew(cls, v: Any): @validator("physical_pixel_sizes", pre=True, always=True) def convert_pixels(cls, v: Any, values: dict[Any, Any]): - from aicsimageio.types import PhysicalPixelSizes + from bioio import PhysicalPixelSizes if isinstance(v, PhysicalPixelSizes): v = DefinedPixelSizes.from_physical(v) elif isinstance(v, tuple) and len(v) == 3: @@ -176,15 +176,15 @@ def convert_pixels(cls, v: Any, values: dict[Any, Any]): @root_validator(pre=True) def read_image(cls, values: dict): - from aicsimageio import AICSImage + from bioio import BioImage from os import fspath img = values["input_image"] - aics: AICSImage | None = None + aics: BioImage | None = None if is_pathlike(img): - aics = AICSImage(fspath(img)) - elif isinstance(img, AICSImage): + aics = BioImage(fspath(img)) + elif isinstance(img, BioImage): aics = img elif isinstance(img, DataArray): if set(img.dims) >= {"Z", "Y", "X"}: @@ -198,9 +198,9 @@ def read_image(cls, values: dict): else: raise ValueError("Only 3D numpy arrays are currently supported. If you have a different shape, please use a DataArray and name your dimensions C, T, Z, Y and/or Z.") else: - raise ValueError("Value of input_image was neither a path, an AICSImage, or array-like.") + raise ValueError("Value of input_image was neither a path, a BioImage, or array-like.") - # If the image was convertible to AICSImage, we should use the metadata from there + # If the image was convertible to BioImage, we should use the metadata from there if aics: values["input_image"] = aics.xarray_dask_data # Take pixel sizes from the image metadata, but only if they're defined diff --git a/core/lls_core/types.py b/core/lls_core/types.py index 7cfe3a2e..075331c1 100644 --- a/core/lls_core/types.py +++ b/core/lls_core/types.py @@ -6,7 +6,7 @@ import numpy as np from numpy.typing import NDArray from xarray import DataArray -from aicsimageio import AICSImage +from bioio import BioImage from os import fspath, PathLike as OriginalPathLike # This is a superset of os.PathLike @@ -19,20 +19,20 @@ def is_pathlike(x: Any) -> TypeGuard[PathLike]: def is_arraylike(arr: Any) -> TypeGuard[ArrayLike]: return isinstance(arr, (DaskArray, np.ndarray, OCLArray, DataArray)) -ImageLike: TypeAlias = Union[PathLike, AICSImage, ArrayLike] -def image_like_to_image(img: ImageLike) -> DataArray: - """ - Converts an image in one of many formats to a DataArray - """ - # First try treating it as a path - try: - img = AICSImage(fspath(img)) - except TypeError: - pass - if isinstance(img, AICSImage): - return img.xarray_dask_data - else: - for required_key in ("shape", "dtype", "ndim", "__array__", "__array_ufunc__"): - if not hasattr(img, required_key): - raise ValueError(f"The provided object {img} is not array like!") +ImageLike: TypeAlias = Union[PathLike, BioImage, ArrayLike] +def image_like_to_image(img: ImageLike) -> DataArray: + """ + Converts an image in one of many formats to a DataArray + """ + # First try treating it as a path + try: + img = BioImage(fspath(img)) + except TypeError: + pass + if isinstance(img, BioImage): + return img.xarray_dask_data + else: + for required_key in ("shape", "dtype", "ndim", "__array__", "__array_ufunc__"): + if not hasattr(img, required_key): + raise ValueError(f"The provided object {img} is not array like!") return DataArray(img) diff --git a/core/pyproject.toml b/core/pyproject.toml index 1fba7b23..ad6c2b2c 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -35,8 +35,8 @@ classifiers = [ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)" ] requires-python = ">=3.8" -dependencies = [ - "aicsimageio>=4.6.3", +dependencies = [ + "bioio>=3.0.0", # Earlier versions don't have Python 3.11 binaries, and the sdist # is misconfigured: https://github.com/AllenCellModeling/aicspylibczi/issues/90 "aicspylibczi>=3.1.1", diff --git a/core/tests/test_cli.py b/core/tests/test_cli.py index 38867aba..f51096fd 100644 --- a/core/tests/test_cli.py +++ b/core/tests/test_cli.py @@ -2,7 +2,7 @@ from typing import Callable, List import pytest -from aicsimageio.aics_image import AICSImage +from bioio import BioImage from npy2bdv import BdvEditor import numpy as np from pathlib import Path @@ -15,7 +15,7 @@ def create_image(path: Path): raw = np.zeros((5, 5, 5)) raw[2, 4, 2] = 10 # Save image as a tif filw in home directory - AICSImage(raw).save(path) + BioImage(raw).save(path) assert path.exists() @@ -28,7 +28,7 @@ def create_data(dir: Path) -> Path: raw = np.zeros((5, 5, 5)) raw[2, 4, 2] = 10 # Save image as a tif filw in home directory - AICSImage(raw).save(input_file) + BioImage(raw).save(input_file) assert input_file.exists() config: dict[str, str] = { @@ -47,7 +47,7 @@ def assert_tiff(output_dir: Path): results = list(output_dir.glob("*.tif")) assert len(results) > 0 for result in results: - AICSImage(result).get_image_data() + BioImage(result).get_image_data() def assert_h5(output_dir: Path): """Checks that a valid H5 was generated""" diff --git a/core/tests/utils.py b/core/tests/utils.py index c9744a03..daff8b4d 100644 --- a/core/tests/utils.py +++ b/core/tests/utils.py @@ -3,7 +3,7 @@ from typer.testing import CliRunner from lls_core.cmds.__main__ import app import npy2bdv -from aicsimageio import AICSImage +from bioio import BioImage def invoke(args: Sequence[str]): CliRunner().invoke(app, args, catch_exceptions=False) @@ -13,5 +13,5 @@ def valid_image_path(path: Path) -> bool: npy2bdv.npy2bdv.BdvEditor(str(path)).read_view() return True else: - AICSImage(path).get_image_data() + BioImage(path).get_image_data() return True diff --git a/plugin/napari_lattice/fields.py b/plugin/napari_lattice/fields.py index 862e41c2..7291e9e4 100644 --- a/plugin/napari_lattice/fields.py +++ b/plugin/napari_lattice/fields.py @@ -402,7 +402,7 @@ def _get_kwargs(self) -> DeskewKwargs: """ Returns the LatticeData fields that the Deskew tab can provide """ - from aicsimageio.types import PhysicalPixelSizes + from bioio import PhysicalPixelSizes DeskewParams.update_forward_refs() params = lattice_params_from_napari( imgs=self.img_layer.value, diff --git a/plugin/napari_lattice/reader.py b/plugin/napari_lattice/reader.py index cbe90615..e271b490 100644 --- a/plugin/napari_lattice/reader.py +++ b/plugin/napari_lattice/reader.py @@ -13,18 +13,18 @@ import os import numpy as np from napari.layers import Image -from aicsimageio.aics_image import AICSImage +from bioio import BioImage from typing import List, Optional, Tuple, Collection, TYPE_CHECKING, TypedDict -from aicsimageio.types import PhysicalPixelSizes +from bioio import PhysicalPixelSizes from lls_core.models.deskew import DefinedPixelSizes from logging import getLogger logger = getLogger(__name__) if TYPE_CHECKING: - from aicsimageio.types import ImageLike + from bioio import ImageLike from xarray import DataArray class NapariImageParams(TypedDict): @@ -74,7 +74,7 @@ def lattice_params_from_napari( save_names.append(save_name) if 'aicsimage' in img.metadata.keys(): - img_data_aics: AICSImage = img.metadata['aicsimage'] + img_data_aics: BioImage = img.metadata['aicsimage'] # If the user has not provided pixel sizes, we extract them fro the metadata # Only process pixel sizes that are not none if physical_pixel_sizes is None and all(img_data_aics.physical_pixel_sizes): @@ -191,13 +191,13 @@ def bdv_h5_reader(path): layer_type = "image" # optional, default is "image" return [(images, add_kwargs, layer_type)] -def tiff_reader(path: ImageLike) -> List[Tuple[AICSImage, dict, str]]: +def tiff_reader(path: ImageLike) -> List[Tuple[BioImage, dict, str]]: """Take path to tiff image and returns a list of LayerData tuples. - Specifying tiff_reader to have better control over tifffile related errors when using AICSImage + Specifying tiff_reader to have better control over tifffile related errors when using BioImage """ try: - image = AICSImage(path) + image = BioImage(path) except Exception as e: raise Exception("Error reading TIFF. Try upgrading tifffile library: pip install tifffile --upgrade.") from e diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index 07e5a259..5974059f 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -35,8 +35,8 @@ classifiers = [ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)" ] requires-python = ">=3.8" -dependencies = [ - "aicsimageio>=4.6.3", +dependencies = [ + "bioio>=3.0.0", "dask[distributed]", # This isn't used directly, but we need to pin this version "fsspec>=2022.8.2", diff --git a/plugin/tests/test_dock_widget.py b/plugin/tests/test_dock_widget.py index 6fde3b6a..d8a058ec 100644 --- a/plugin/tests/test_dock_widget.py +++ b/plugin/tests/test_dock_widget.py @@ -9,7 +9,7 @@ from magicclass._gui._gui_modes import ErrorMode import pytest from lls_core.sample import resources -from aicsimageio.aics_image import AICSImage +from bioio import BioImage from napari_lattice.fields import PixelSizeSource from tempfile import TemporaryDirectory @@ -35,7 +35,7 @@ def image_data(request: pytest.FixtureRequest): Fixture function that yields test images as file paths """ with as_file(resources / request.param) as image_path: - yield AICSImage(image_path, ) + yield BioImage(image_path, ) def set_debug(cls: MagicTemplate): """ @@ -48,7 +48,7 @@ def _handler(e: Exception, parent: Widget): for child in cls.__magicclass_children__: set_debug(child) -def test_dock_widget(make_napari_viewer: Callable[[], Viewer], image_data: AICSImage): +def test_dock_widget(make_napari_viewer: Callable[[], Viewer], image_data: BioImage): # make viewer and add an image layer using our fixture viewer = make_napari_viewer() From be54c3ba1e94e54612a72d3d756b701bf33b291f Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Fri, 14 Nov 2025 16:45:45 +1100 Subject: [PATCH 03/28] Add default physical pixel sizes to BioImage obj Without this, writing by the bioio-ome-tiff writer fails. --- core/tests/test_cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/tests/test_cli.py b/core/tests/test_cli.py index f51096fd..cadd279a 100644 --- a/core/tests/test_cli.py +++ b/core/tests/test_cli.py @@ -15,7 +15,8 @@ def create_image(path: Path): raw = np.zeros((5, 5, 5)) raw[2, 4, 2] = 10 # Save image as a tif filw in home directory - BioImage(raw).save(path) + b = BioImage(raw, physical_pixel_sizes={ax: 1. for ax in 'ZYX'}) + b.save(path) assert path.exists() From ebfc88cc7da12d74e4c7e982326fcf3963135e90 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Fri, 14 Nov 2025 16:46:13 +1100 Subject: [PATCH 04/28] typo: filw -> file --- core/tests/test_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tests/test_cli.py b/core/tests/test_cli.py index cadd279a..0347c2da 100644 --- a/core/tests/test_cli.py +++ b/core/tests/test_cli.py @@ -14,7 +14,7 @@ def create_image(path: Path): # Create a zero array of shape 5x5x5 with a value of 10 at (2,4,2) raw = np.zeros((5, 5, 5)) raw[2, 4, 2] = 10 - # Save image as a tif filw in home directory + # Save image as a tif file in home directory b = BioImage(raw, physical_pixel_sizes={ax: 1. for ax in 'ZYX'}) b.save(path) assert path.exists() @@ -28,7 +28,7 @@ def create_data(dir: Path) -> Path: # Create a zero array of shape 5x5x5 with a value of 10 at (2,4,2) raw = np.zeros((5, 5, 5)) raw[2, 4, 2] = 10 - # Save image as a tif filw in home directory + # Save image as a tif file in home directory BioImage(raw).save(input_file) assert input_file.exists() From df1990a1b67602611c7a422f3907e4f5e2128435 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Fri, 14 Nov 2025 17:04:22 +1100 Subject: [PATCH 05/28] Add physical pixel size to BioImage in create_data --- core/tests/test_cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/tests/test_cli.py b/core/tests/test_cli.py index 0347c2da..aed29f1f 100644 --- a/core/tests/test_cli.py +++ b/core/tests/test_cli.py @@ -29,7 +29,8 @@ def create_data(dir: Path) -> Path: raw = np.zeros((5, 5, 5)) raw[2, 4, 2] = 10 # Save image as a tif file in home directory - BioImage(raw).save(input_file) + b = BioImage(raw, physical_pixel_sizes={ax: 1. for ax in 'ZYX'}) + b.save(input_file) assert input_file.exists() config: dict[str, str] = { From d31ab66ab6f10a0f2fddf2fa74acd95de49e0fb5 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Fri, 14 Nov 2025 17:04:37 +1100 Subject: [PATCH 06/28] Add bioio plugin dependencies --- core/pyproject.toml | 8 ++++---- plugin/pyproject.toml | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index ad6c2b2c..f7c9e575 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -35,11 +35,11 @@ classifiers = [ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)" ] requires-python = ">=3.8" -dependencies = [ +dependencies = [ "bioio>=3.0.0", - # Earlier versions don't have Python 3.11 binaries, and the sdist - # is misconfigured: https://github.com/AllenCellModeling/aicspylibczi/issues/90 - "aicspylibczi>=3.1.1", + "bioio-bioformats>=1.3.0", + "bioio-czi>=2.4.0", + "bioio-ome-tiff>=1.4.0", "click", "dask", "dask[distributed]", diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index 5974059f..1d74b55a 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -35,8 +35,11 @@ classifiers = [ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)" ] requires-python = ">=3.8" -dependencies = [ +dependencies = [ "bioio>=3.0.0", + "bioio-bioformats>=1.3.0", + "bioio-czi>=2.4.0", + "bioio-ome-tiff>=1.4.0", "dask[distributed]", # This isn't used directly, but we need to pin this version "fsspec>=2022.8.2", @@ -45,7 +48,6 @@ dependencies = [ # The lower bound is because we need this Python 3.8 fix: https://github.com/hanjinliu/magic-class/pull/108 "magic-class>=0.7.5", "magicgui<0.8.0", - "napari-aicsimageio>=0.7.2", "napari-workflow-inspector", "napari-workflows>=0.2.8", "napari[all]>=0.4.11", From 8998f42f10b82f6ff5e83e237b9f095bfac5e07d Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Fri, 14 Nov 2025 17:04:55 +1100 Subject: [PATCH 07/28] Use separate resolutionunit for tifffile write --- core/lls_core/writers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/lls_core/writers.py b/core/lls_core/writers.py index 8fdcb9ed..0ca55d0b 100644 --- a/core/lls_core/writers.py +++ b/core/lls_core/writers.py @@ -118,7 +118,8 @@ def flush(self): str(path), data = images_array, bigtiff=True, - resolution=(1./self.lattice.dx, 1./self.lattice.dy, "MICROMETER"), + resolution=(1./self.lattice.dx, 1./self.lattice.dy), + resolutionunit="MICROMETER", metadata={'spacing': self.lattice.new_dz, 'unit': 'um', 'axes': 'TZCYX'}, imagej=True ) From 337a6990642b7f2f41021932ac59413ef2928005 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Sat, 15 Nov 2025 13:12:00 +1100 Subject: [PATCH 08/28] Use bioio-tifffile to read raw.tif bioio-bioformats fails with dask use: https://github.com/bioio-devs/bioio-bioformats/issues/40 After fixing reading, I got a validationerror when save_dir was not set, so I set save_dir to a temporary directory as in other tests. --- core/tests/test_process.py | 42 +++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/core/tests/test_process.py b/core/tests/test_process.py index f3a19f78..e7142b0a 100644 --- a/core/tests/test_process.py +++ b/core/tests/test_process.py @@ -9,6 +9,8 @@ from pathlib import Path from napari_workflows import Workflow from pytest import FixtureRequest +from bioio_tifffile import reader as tiffreader +from bioio import BioImage from .params import parameterized @@ -51,22 +53,30 @@ def test_save(minimal_image_path: str, args: dict): def test_process_deconv_crop(): - for slice in ( - LatticeData.parse_obj( - { - "input_image": root / "raw.tif", - "deconvolution": { - "psf": [root / "psf.tif"], - }, - "crop": CropParams( - roi_list=[[[0, 0], [0, 110], [95, 0], [95, 110]]] - ), - } - ) - .process() - .slices - ): - assert slice.data.ndim == 3 + with tempfile.TemporaryDirectory() as tempdir: + for slice in ( + LatticeData.parse_obj( + { + # use BioImage rather than just Path to ensure tifffile + # is used instead of bioformats, which prevents dask use + # due to a bug: + # https://github.com/bioio-devs/bioio-bioformats/issues/40 + "input_image": BioImage( + root / "raw.tif", reader=tiffreader.Reader + ), + "deconvolution": { + "psf": [root / "psf.tif"], + }, + "crop": CropParams( + roi_list=[[[0, 0], [0, 110], [95, 0], [95, 110]]] + ), + "save_dir": tempdir, + } + ) + .process() + .slices + ): + assert slice.data.ndim == 3 def test_process_time_range(multi_channel_time: Path): From 8a616e53847a10fff2ca46be85f34051c7160dd8 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Sat, 15 Nov 2025 13:14:52 +1100 Subject: [PATCH 09/28] Fix patch to patch bioio instead of aicsimageio --- core/tests/test_validation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tests/test_validation.py b/core/tests/test_validation.py index d4cb50cb..b0e455a9 100644 --- a/core/tests/test_validation.py +++ b/core/tests/test_validation.py @@ -48,7 +48,7 @@ def test_allow_trailing_slash(): def test_infer_czi_pixel_sizes(rbc_tiny: Path): mock = PropertyMock() - with patch("aicsimageio.AICSImage.physical_pixel_sizes", new=mock): + with patch("bioio.BioImage.physical_pixel_sizes", new=mock): DeskewParams(input_image=rbc_tiny) - # The AICSImage should be queried for the pixel sizes + # The BioImage should be queried for the pixel sizes assert mock.called From 692e4298ecb5fbf385e0928a513427fffce83463 Mon Sep 17 00:00:00 2001 From: Pradeep Rajasekhar Date: Wed, 26 Nov 2025 16:55:17 +1100 Subject: [PATCH 10/28] fix dependency issues --- plugin/pyproject.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index 1d74b55a..e6a9d510 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -40,6 +40,7 @@ dependencies = [ "bioio-bioformats>=1.3.0", "bioio-czi>=2.4.0", "bioio-ome-tiff>=1.4.0", + "bioio-tifffile==1.3.0", "dask[distributed]", # This isn't used directly, but we need to pin this version "fsspec>=2022.8.2", @@ -102,6 +103,11 @@ ignore_unused = [ "fsspec", "imageio", "ome-types" + + #bioio packages are needed but not directly imported + "bioio-bioformats", + "bioio-czi", + "bioio-ome-tiff" ] output_format = "human_detailed" From f0c666966eda041b529ebc645b0f893121046f65 Mon Sep 17 00:00:00 2001 From: Pradeep Rajasekhar Date: Wed, 26 Nov 2025 16:55:38 +1100 Subject: [PATCH 11/28] use bioio for reading psf with czi extension --- core/lls_core/deconvolution.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/lls_core/deconvolution.py b/core/lls_core/deconvolution.py index 4a03bf8a..c6144aaa 100644 --- a/core/lls_core/deconvolution.py +++ b/core/lls_core/deconvolution.py @@ -8,8 +8,8 @@ import importlib.util from typing import Collection, Iterable,Union,Literal, Optional, TYPE_CHECKING from bioio import BioImage +import bioio_czi from skimage.io import imread -from aicspylibczi import CziFile from numpy.typing import NDArray import os import numpy as np @@ -62,12 +62,10 @@ def read_psf(psf_paths: Collection[Path], for psf in psf_paths: if psf.exists() and psf.is_file(): if psf.suffix == ".czi": - psf_czi = CziFile(psf.__str__()) - psf_aics = psf_czi.read_image() + psf_czi = BioImage(psf.__str__(), reader=bioio_czi.Reader) + psf_aics = psf_czi.data # make sure shape is 3D - psf_aics = psf_aics[0][0] # np.expand_dims(psf_aics[0],axis=0) - # if len(psf_aics[0])>=1: - #psf_channels = len(psf_aics[0]) + psf_aics = psf_aics[0][0] assert len( psf_aics.shape) == 3, f"PSF should be a 3D image (shape of 3), but got {psf_aics.shape}" # pad psf to multiple of 16 for decon @@ -79,7 +77,7 @@ def read_psf(psf_paths: Collection[Path], if len(psf_aics_data.shape) != 3: raise ValueError(f"PSF should be a 3D image (shape of 3), but got {psf_aics.shape}") else: - #Use BioIO + #Use BioIO psf_aics = BioImage(str(psf)) psf_aics_data = psf_aics.data[0][0] psf_aics_data = pad_image_nearest_multiple( From dc3e6eee19f25f2e95fddfe742794ccd22dfcbc5 Mon Sep 17 00:00:00 2001 From: Pradeep Rajasekhar Date: Wed, 26 Nov 2025 17:02:32 +1100 Subject: [PATCH 12/28] update dependencies --- core/pyproject.toml | 8 +++++++- plugin/pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index f7c9e575..4128d174 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -40,6 +40,7 @@ dependencies = [ "bioio-bioformats>=1.3.0", "bioio-czi>=2.4.0", "bioio-ome-tiff>=1.4.0", + "bioio-tifffile==1.3.0", "click", "dask", "dask[distributed]", @@ -158,7 +159,12 @@ ignore_unused = [ # Used for the deployment, but never imported "build", - "twine" + "twine", + + #bioio packages are needed but not directly imported + "bioio-bioformats", + "bioio-czi", + "bioio-ome-tiff" ] output_format = "human_detailed" diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index e6a9d510..b9a73f80 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -102,7 +102,7 @@ ignore_unused = [ # This is pinned but unused "fsspec", "imageio", - "ome-types" + "ome-types", #bioio packages are needed but not directly imported "bioio-bioformats", From f453a3e12dbffde706de4972254e924e4a5fa361 Mon Sep 17 00:00:00 2001 From: Pradeep Rajasekhar Date: Wed, 26 Nov 2025 17:29:17 +1100 Subject: [PATCH 13/28] update fawltydeps --- .github/lint/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/lint/action.yml b/.github/lint/action.yml index 46648d71..05e47479 100644 --- a/.github/lint/action.yml +++ b/.github/lint/action.yml @@ -10,7 +10,7 @@ runs: using: "composite" steps: - run: | - pip install fawltydeps==0.12.0 + pip install fawltydeps fawltydeps --check --detailed --verbose shell: bash -l {0} working-directory: ${{ inputs.directory }} From 077e8475a9b804e514543d02bae456aadef49170 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Tue, 2 Dec 2025 14:20:00 +1100 Subject: [PATCH 14/28] Update test matrix to 3.10 3.13 --- .github/workflows/test_and_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index e176f86f..1e637c81 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8","3.9","3.10"] #not compatible with py 3.10 and 3.12 yet + python-version: ["3.10", "3.13"] env: DISPLAY: ":99.0" From 7aad4d1b4bb41f5a4545e0b221c3f3246e126f37 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Tue, 2 Dec 2025 14:22:38 +1100 Subject: [PATCH 15/28] Remove white space --- .github/workflows/test_and_deploy.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index 1e637c81..bdc7c372 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -46,7 +46,7 @@ jobs: with: # Install a specific version of uv. version: "0.6.17" - + - name: Install core timeout-minutes: 10 run: | @@ -94,9 +94,9 @@ jobs: # github secrets (see readme for details) needs: [test] runs-on: ubuntu-latest - environment: + environment: name: github-pages - permissions: + permissions: id-token: write pages: write contents: write @@ -136,7 +136,7 @@ jobs: uses: actions/deploy-pages@v4 - uses: ncipollo/release-action@v1.18.0 - name: Create GitHub release + name: Create GitHub release if: contains(github.ref, 'tags') with: skipIfReleaseExists: true From d865bd9e0ae5f3d48922dccf6fe26a45132adb50 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Tue, 2 Dec 2025 17:30:11 +1100 Subject: [PATCH 16/28] fix issues with workflow_path when running tests locally in windows --- core/tests/test_workflows.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/tests/test_workflows.py b/core/tests/test_workflows.py index 28b1edb1..b8d617da 100644 --- a/core/tests/test_workflows.py +++ b/core/tests/test_workflows.py @@ -97,9 +97,11 @@ def test_table_workflow(lls7_t1_ch1: Path, table_workflow: Workflow): def test_argument_order(rbc_tiny: Path): # Tests that only the first unfilled argument is passed an array with tempfile.TemporaryDirectory() as tmpdir: + # Get the path relative to this test file + workflow_path = Path(__file__).parent / "workflows" / "argument_order" / "test_workflow.yml" params = LatticeData( input_image = rbc_tiny, - workflow = "core/tests/workflows/argument_order/test_workflow.yml", + workflow = str(workflow_path), save_dir = tmpdir ) for output in params.process_workflow().process(): @@ -109,9 +111,11 @@ def test_sum_preview(rbc_tiny: Path): import numpy as np # Tests that we can sum the preview result. This is required for the plugin with tempfile.TemporaryDirectory() as tmpdir: + # Get the path relative to this test file + workflow_path = Path(__file__).parent / "workflows" / "binarisation" / "workflow.yml" params = LatticeData( input_image = rbc_tiny, - workflow = "core/tests/workflows/binarisation/workflow.yml", + workflow = str(workflow_path), save_dir = tmpdir ) previews = list(params.process_workflow().roi_previews()) @@ -122,9 +126,10 @@ def test_crop_workflow(lls7_t1_ch1: Path): # Tests that crop workflows only process each ROI lazily with tempfile.TemporaryDirectory() as tmpdir: + workflow_path = Path(__file__).parent / "workflows" / "binarisation" / "workflow.yml" params = LatticeData( input_image = lls7_t1_ch1, - workflow = "core/tests/workflows/binarisation/workflow.yml", + workflow = str(workflow_path), save_dir = tmpdir, crop=CropParams( roi_list=[ From 79203792596161237cf70dde17991b069062e2f9 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 11:05:13 +1100 Subject: [PATCH 17/28] remove bioio_bioformats --- core/pyproject.toml | 4 ++-- plugin/pyproject.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index 4128d174..f42733c0 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -37,7 +37,7 @@ classifiers = [ requires-python = ">=3.8" dependencies = [ "bioio>=3.0.0", - "bioio-bioformats>=1.3.0", + #"bioio-bioformats>=1.3.0", "bioio-czi>=2.4.0", "bioio-ome-tiff>=1.4.0", "bioio-tifffile==1.3.0", @@ -162,7 +162,7 @@ ignore_unused = [ "twine", #bioio packages are needed but not directly imported - "bioio-bioformats", + #"bioio-bioformats", "bioio-czi", "bioio-ome-tiff" ] diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index b9a73f80..2cdb8ad6 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -37,7 +37,7 @@ classifiers = [ requires-python = ">=3.8" dependencies = [ "bioio>=3.0.0", - "bioio-bioformats>=1.3.0", + #"bioio-bioformats>=1.3.0", "bioio-czi>=2.4.0", "bioio-ome-tiff>=1.4.0", "bioio-tifffile==1.3.0", @@ -105,7 +105,7 @@ ignore_unused = [ "ome-types", #bioio packages are needed but not directly imported - "bioio-bioformats", + #"bioio-bioformats", "bioio-czi", "bioio-ome-tiff" ] From f0d6bfa9b9730ee44b8010399bcb8e00746d2329 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 12:34:52 +1100 Subject: [PATCH 18/28] testing if modifying install order fixes tiff reading issues --- core/pyproject.toml | 6 +++--- plugin/pyproject.toml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index f42733c0..2bdfaccf 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -37,10 +37,10 @@ classifiers = [ requires-python = ">=3.8" dependencies = [ "bioio>=3.0.0", - #"bioio-bioformats>=1.3.0", "bioio-czi>=2.4.0", - "bioio-ome-tiff>=1.4.0", "bioio-tifffile==1.3.0", + "bioio-ome-tiff>=1.4.0", + "bioio-bioformats>=1.3.0", "click", "dask", "dask[distributed]", @@ -62,7 +62,7 @@ dependencies = [ "resource-backed-dask-array>=0.1.0", "scikit-image", "StrEnum", - "tifffile>=2023.3.15,<2025.2.18", #>=2022.8.12 + #"tifffile>=2023.3.15,<2025.2.18", #>=2022.8.12 "toolz", "tqdm", "typer<0.17.0", diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index 2cdb8ad6..b4db3f7a 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -37,10 +37,10 @@ classifiers = [ requires-python = ">=3.8" dependencies = [ "bioio>=3.0.0", - #"bioio-bioformats>=1.3.0", + "bioio-tifffile==1.3.0", "bioio-czi>=2.4.0", "bioio-ome-tiff>=1.4.0", - "bioio-tifffile==1.3.0", + #"bioio-bioformats>=1.3.0", "dask[distributed]", # This isn't used directly, but we need to pin this version "fsspec>=2022.8.2", From d7d77ccfcb75765f5389a5e27e874d71081c8fb2 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 12:37:50 +1100 Subject: [PATCH 19/28] enable bioformats in fawltydeps --- core/pyproject.toml | 2 +- plugin/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index 2bdfaccf..93d75a74 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -162,7 +162,7 @@ ignore_unused = [ "twine", #bioio packages are needed but not directly imported - #"bioio-bioformats", + "bioio-bioformats", "bioio-czi", "bioio-ome-tiff" ] diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index b4db3f7a..7d9153c5 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -105,7 +105,7 @@ ignore_unused = [ "ome-types", #bioio packages are needed but not directly imported - #"bioio-bioformats", + "bioio-bioformats", "bioio-czi", "bioio-ome-tiff" ] From cd01a8d4bce363359d7face17c4116153b43d37e Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 12:50:59 +1100 Subject: [PATCH 20/28] tifffile to fawltydeps --- core/pyproject.toml | 3 ++- plugin/pyproject.toml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index 93d75a74..48e92dc0 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -164,7 +164,8 @@ ignore_unused = [ #bioio packages are needed but not directly imported "bioio-bioformats", "bioio-czi", - "bioio-ome-tiff" + "bioio-ome-tiff", + "tifffile" ] output_format = "human_detailed" diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index 7d9153c5..b5fb6f40 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -107,7 +107,8 @@ ignore_unused = [ #bioio packages are needed but not directly imported "bioio-bioformats", "bioio-czi", - "bioio-ome-tiff" + "bioio-ome-tiff", + "tifffile" ] output_format = "human_detailed" From 4179fb8f362d5bf711620c3832bb429906002fd9 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 13:29:23 +1100 Subject: [PATCH 21/28] fix tifffile in pyproject --- core/pyproject.toml | 4 +--- plugin/pyproject.toml | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index 48e92dc0..379dc4c9 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -39,7 +39,6 @@ dependencies = [ "bioio>=3.0.0", "bioio-czi>=2.4.0", "bioio-tifffile==1.3.0", - "bioio-ome-tiff>=1.4.0", "bioio-bioformats>=1.3.0", "click", "dask", @@ -62,7 +61,7 @@ dependencies = [ "resource-backed-dask-array>=0.1.0", "scikit-image", "StrEnum", - #"tifffile>=2023.3.15,<2025.2.18", #>=2022.8.12 + "tifffile", #>=2023.3.15,<2025.2.18", #>=2022.8.12 "toolz", "tqdm", "typer<0.17.0", @@ -165,7 +164,6 @@ ignore_unused = [ "bioio-bioformats", "bioio-czi", "bioio-ome-tiff", - "tifffile" ] output_format = "human_detailed" diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index b5fb6f40..ce2b8445 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -39,7 +39,6 @@ dependencies = [ "bioio>=3.0.0", "bioio-tifffile==1.3.0", "bioio-czi>=2.4.0", - "bioio-ome-tiff>=1.4.0", #"bioio-bioformats>=1.3.0", "dask[distributed]", # This isn't used directly, but we need to pin this version @@ -108,7 +107,6 @@ ignore_unused = [ "bioio-bioformats", "bioio-czi", "bioio-ome-tiff", - "tifffile" ] output_format = "human_detailed" From 76c9ed00c03db8257670dd6b91beb52502baae0e Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 13:37:26 +1100 Subject: [PATCH 22/28] remove bioformats due to instability --- core/pyproject.toml | 2 -- plugin/pyproject.toml | 2 -- 2 files changed, 4 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index 379dc4c9..bf5f38a1 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -39,7 +39,6 @@ dependencies = [ "bioio>=3.0.0", "bioio-czi>=2.4.0", "bioio-tifffile==1.3.0", - "bioio-bioformats>=1.3.0", "click", "dask", "dask[distributed]", @@ -161,7 +160,6 @@ ignore_unused = [ "twine", #bioio packages are needed but not directly imported - "bioio-bioformats", "bioio-czi", "bioio-ome-tiff", ] diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index ce2b8445..da7603c0 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -39,7 +39,6 @@ dependencies = [ "bioio>=3.0.0", "bioio-tifffile==1.3.0", "bioio-czi>=2.4.0", - #"bioio-bioformats>=1.3.0", "dask[distributed]", # This isn't used directly, but we need to pin this version "fsspec>=2022.8.2", @@ -104,7 +103,6 @@ ignore_unused = [ "ome-types", #bioio packages are needed but not directly imported - "bioio-bioformats", "bioio-czi", "bioio-ome-tiff", ] From b825398308128bb8ae0bb7f0d84c34bcc615a84e Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 14:52:53 +1100 Subject: [PATCH 23/28] add omet-tiff for tif writing --- core/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/core/pyproject.toml b/core/pyproject.toml index bf5f38a1..c10c6125 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -39,6 +39,7 @@ dependencies = [ "bioio>=3.0.0", "bioio-czi>=2.4.0", "bioio-tifffile==1.3.0", + "bioio-ome-tiff", "click", "dask", "dask[distributed]", From 154b592013638877988bb5ff39bc196fc65be37b Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 15:08:06 +1100 Subject: [PATCH 24/28] add tifffile constraints back --- core/pyproject.toml | 2 +- plugin/pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index c10c6125..178dffba 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -61,7 +61,7 @@ dependencies = [ "resource-backed-dask-array>=0.1.0", "scikit-image", "StrEnum", - "tifffile", #>=2023.3.15,<2025.2.18", #>=2022.8.12 + "tifffile>=2023.3.15,<2025.2.18", #>=2022.8.12 "toolz", "tqdm", "typer<0.17.0", diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index da7603c0..32a93b95 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -60,6 +60,7 @@ dependencies = [ "typing_extensions>=4.7.0", "rich", "StrEnum", + "tifffile>=2023.3.15,<2025.2.18", #tiff "xarray" ] From e82bbb6616f88336c85473694449d6e94cdbe407 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 15:17:08 +1100 Subject: [PATCH 25/28] specify min bioio-ome tif version --- core/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index 178dffba..351ffeeb 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ "bioio>=3.0.0", "bioio-czi>=2.4.0", "bioio-tifffile==1.3.0", - "bioio-ome-tiff", + "bioio-ome-tiff>=1.4.0", "click", "dask", "dask[distributed]", From f03f86f73343df61298ec4aa74e00af37b44036c Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 15:24:39 +1100 Subject: [PATCH 26/28] add to fawltydeps --- plugin/pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index 32a93b95..beefa96e 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -106,6 +106,8 @@ ignore_unused = [ #bioio packages are needed but not directly imported "bioio-czi", "bioio-ome-tiff", + "bioio-tifffile", + "tifffile" ] output_format = "human_detailed" From 21f17f530fef3e7066fd4c6275a148c72be023ce Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 15:43:22 +1100 Subject: [PATCH 27/28] loosen tifffile version restriction --- core/pyproject.toml | 2 +- plugin/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/pyproject.toml b/core/pyproject.toml index 351ffeeb..a54dd676 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -61,7 +61,7 @@ dependencies = [ "resource-backed-dask-array>=0.1.0", "scikit-image", "StrEnum", - "tifffile>=2023.3.15,<2025.2.18", #>=2022.8.12 + "tifffile>=2023.3.15",#<2025.2.18", #>=2022.8.12 "toolz", "tqdm", "typer<0.17.0", diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index beefa96e..55cd159c 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -60,7 +60,7 @@ dependencies = [ "typing_extensions>=4.7.0", "rich", "StrEnum", - "tifffile>=2023.3.15,<2025.2.18", #tiff + "tifffile>=2023.3.15",#,<2025.2.18", #tiff "xarray" ] From 556ad201a36e9abaed5e388c9258a7de9ed801b8 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 3 Dec 2025 16:12:49 +1100 Subject: [PATCH 28/28] add testing for 3.11 3.12 --- .github/workflows/test_and_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index bdc7c372..3165a9d6 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.13"] + python-version: ["3.10", "3.11", "3.12"] env: DISPLAY: ":99.0"