Repository: BioimageAnalysisCoreWEHI/napari_lattice (language: python)

Issue:
Speed up CI
1. Looking into speeding up the tests. The slowest tests are:
```
31.34s call     core/tests/test_process.py::test_table_workflow
27.67s call     core/tests/test_process.py::test_process_deconvolution[args0-auto]
23.59s call     core/tests/test_process.py::test_process_deconvolution[args0-second_last]
20.37s call     core/tests/test_process.py::test_process_deconvolution[args0-1]
20.30s call     core/tests/test_process.py::test_process_deconvolution[args1-auto]
19.57s call     core/tests/test_process.py::test_process_deconvolution[args2-auto]
19.35s call     core/tests/test_process.py::test_process_deconvolution[args5-1]
19.10s call     core/tests/test_process.py::test_process_deconvolution[args1-1]
18.99s call     core/tests/test_process.py::test_process_deconvolution[args1-second_last]
18.72s call     core/tests/test_process.py::test_process_deconvolution[args2-second_last]
18.20s call     core/tests/test_process.py::test_process_deconvolution[args2-1]
18.04s call     core/tests/test_process.py::test_process_deconvolution[args3-1]
17.49s call     core/tests/test_process.py::test_process_deconvolution[args5-auto]
17.30s call     core/tests/test_process.py::test_process_deconvolution[args3-second_last]
17.10s call     core/tests/test_process.py::test_process_deconvolution[args3-auto]
16.89s call     core/tests/test_process.py::test_process_deconvolution[args4-second_last]
16.44s call     core/tests/test_process.py::test_process_deconvolution[args4-1]
16.30s call     core/tests/test_process.py::test_process_deconvolution[args4-auto]
16.18s call     core/tests/test_process.py::test_process_deconvolution[args5-second_last]
8.59s call     core/tests/test_workflows.py::test_table_workflow[LLS7_t2_ch3.czi]
```
2. Looking into using uv to install packages


Discussion / hints:

Fix patch:
diff --git a/core/lls_core/models/deskew.py b/core/lls_core/models/deskew.py
index de741b47..59135ed0 100644
--- a/core/lls_core/models/deskew.py
+++ b/core/lls_core/models/deskew.py
@@ -184,8 +184,17 @@ def read_image(cls, values: dict):
             aics = AICSImage(fspath(img))
         elif isinstance(img, AICSImage):
             aics = img
+        elif isinstance(img, DataArray):
+            if set(img.dims) >= {"Z", "Y", "X"}:
+                # If it's already a DataArray with the right dimensions, we're done
+                return values
+            else:
+                raise ValueError("If passing a DataArray, it should at least have Z Y and X dimensions, appropriately labelled.")
         elif is_arraylike(img):
-            values["input_image"] = DataArray(img)
+            if len(img.shape) == 3:
+                values["input_image"] = DataArray(img, dims=["Z", "Y", "X"])
+            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.")
 


Test patch:
diff --git a/core/tests/conftest.py b/core/tests/conftest.py
index 8eaf5022..0fefc07a 100644
--- a/core/tests/conftest.py
+++ b/core/tests/conftest.py
@@ -17,6 +17,11 @@
 def runner() -> CliRunner:
     return CliRunner()
 
+@pytest.fixture
+def lls7_t1_ch1():
+    with as_file(resources / "LLS7_t1_ch1.czi") as image_path:
+        yield image_path
+
 @pytest.fixture
 def rbc_tiny():
     with as_file(resources / "RBC_tiny.czi") as image_path:
diff --git a/core/tests/test_process.py b/core/tests/test_process.py
index cd5c1432..1a31721b 100644
--- a/core/tests/test_process.py
+++ b/core/tests/test_process.py
@@ -10,6 +10,7 @@
 from napari_workflows import Workflow
 from pytest import FixtureRequest
 
+
 from .params import parameterized
 
 root = Path(__file__).parent / "data"
@@ -86,31 +87,33 @@ def test_process_time_range(multi_channel_time: Path):
 
 
 @pytest.mark.parametrize(["background"], [(1,), ("auto",), ("second_last",)])
-@parameterized
-def test_process_deconvolution(args: dict, background: Any):
-    for slice in (
-        LatticeData.parse_obj(
-            {
-                "input_image": root / "raw.tif",
-                "deconvolution": {
-                    "psf": [root / "psf.tif"],
-                    "background": background,
-                },
-                **args,
-            }
-        )
-        .process()
-        .slices
-    ):
-        assert slice.data.ndim == 3
+def test_process_deconvolution(background: Any):
+    import numpy as np
+    with tempfile.TemporaryDirectory() as outdir:
+        for slice in (
+            LatticeData.parse_obj(
+                {
+                    # Use random sample data here, since we're not testing the correctness of the deconvolution
+                    # but rather that all the code paths are functional
+                    "input_image": np.random.random_sample((128, 128, 64)),
+                    "deconvolution": {
+                        "psf": [np.random.random_sample((28, 28, 28))],
+                        "background": background,
+                    },
+                    "save_dir": outdir
+                }
+            )
+            .process()
+            .slices
+        ):
+            assert slice.data.ndim == 3
 
 
-@parameterized
 @pytest.mark.parametrize(
     ["workflow_name"], [("image_workflow",), ("table_workflow",)]
 )
 def test_process_workflow(
-    args: dict, request: FixtureRequest, workflow_name: str
+    request: FixtureRequest, lls7_t1_ch1: Path, workflow_name: str
 ):
     from pandas import DataFrame
 
@@ -119,10 +122,9 @@ def test_process_workflow(
         for output in (
             LatticeData.parse_obj(
                 {
-                    "input_image": root / "raw.tif",
+                    "input_image": lls7_t1_ch1,
                     "workflow": workflow,
-                    "save_dir": tmpdir,
-                    **args,
+                    "save_dir": tmpdir
                 }
             )
             .process_workflow()
@@ -132,19 +134,19 @@ def test_process_workflow(
             assert isinstance(output.data, (Path, DataFrame))
 
 def test_table_workflow(
-    rbc_tiny: Path, table_workflow: Workflow
+    lls7_t1_ch1: Path, table_workflow: Workflow
 ):
     with tempfile.TemporaryDirectory() as _tmpdir:
         tmpdir = Path(_tmpdir)
         results = set(LatticeData.parse_obj(
             {
-                "input_image": rbc_tiny,
+                "input_image": lls7_t1_ch1,
                 "workflow": table_workflow,
                 "save_dir": tmpdir
             }
         ).process_workflow().save())
         # There should be one output for each element of the tuple
-        assert {result.name for result in results} == {'RBC_tiny_deskewed_output_3.csv', 'RBC_tiny_deskewed.h5', 'RBC_tiny_deskewed_output_1.csv', 'RBC_tiny_deskewed_output_2.csv'}
+        assert {result.name for result in results} == {'LLS7_t1_ch1_deskewed_output_3.csv', 'LLS7_t1_ch1_deskewed.h5', 'LLS7_t1_ch1_deskewed_output_1.csv', 'LLS7_t1_ch1_deskewed_output_2.csv'}
 
 @pytest.mark.parametrize(
     ["roi_subset"],
diff --git a/core/tests/test_workflows.py b/core/tests/test_workflows.py
index aceb5a96..18ff171e 100644
--- a/core/tests/test_workflows.py
+++ b/core/tests/test_workflows.py
@@ -55,22 +55,22 @@ def test_workflow_cli(workflow_config_cli: dict, save_func: Callable, cli_param:
         assert label_img.shape == (3, 14, 5)
         assert label_img[1, 6, 2] == 1
 
-def test_image_workflow(minimal_image_path: Path, image_workflow: Workflow):
+def test_image_workflow(lls7_t1_ch1: Path, image_workflow: Workflow):
     # Test that a regular workflow that returns an image directly works
     with tempfile.TemporaryDirectory() as tmpdir:
         for output in LatticeData(
-            input_image = minimal_image_path,
+            input_image = lls7_t1_ch1,
             workflow = image_workflow,
             save_dir = tmpdir
         ).process_workflow().process():
             assert isinstance(output.data, Path)
             assert valid_image_path(output.data)
 
-def test_table_workflow(minimal_image_path: Path, table_workflow: Workflow):
+def test_table_workflow(lls7_t1_ch1: Path, table_workflow: Workflow):
     # Test a complex workflow that returns a tuple of images and data
     with tempfile.TemporaryDirectory() as tmpdir:
         params = LatticeData(
-            input_image = minimal_image_path,
+            input_image = lls7_t1_ch1,
             workflow = table_workflow,
             save_dir = tmpdir
         )
@@ -111,12 +111,12 @@ def test_sum_preview(rbc_tiny: Path):
         assert len(previews) == 1, "There should be 1 preview when cropping is disabled"
         assert previews[0].ndim == 3, "A preview should be a 3D image"
 
-def test_crop_workflow(rbc_tiny: Path):
+def test_crop_workflow(lls7_t1_ch1: Path):
     # Tests that crop workflows only process each ROI lazily
 
     with tempfile.TemporaryDirectory() as tmpdir:
         params = LatticeData(
-            input_image = rbc_tiny,
+            input_image = lls7_t1_ch1,
             workflow = "core/tests/workflows/binarisation/workflow.yml",
             save_dir = tmpdir,
             crop=CropParams(
diff --git a/plugin/tests/test_dock_widget.py b/plugin/tests/test_dock_widget.py
index ef846cfb..6fde3b6a 100644
--- a/plugin/tests/test_dock_widget.py
+++ b/plugin/tests/test_dock_widget.py
@@ -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 AICSImage(image_path, )
 
 def set_debug(cls: MagicTemplate):
     """