From 69500a783ed743878ca28537021a9506518d4824 Mon Sep 17 00:00:00 2001 From: Michael Milton Date: Fri, 3 Nov 2023 12:40:05 +1100 Subject: [PATCH] Fix for missing output directory for previewing; add make() method for models --- core/lls_core/models/utils.py | 10 ++++++++++ plugin/napari_lattice/dock_widget.py | 17 ++++++++++++----- plugin/napari_lattice/fields.py | 6 ++++-- plugin/tests/test_dock_widget.py | 10 +++++++++- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/core/lls_core/models/utils.py b/core/lls_core/models/utils.py index 6f56a773..3e49bcdd 100644 --- a/core/lls_core/models/utils.py +++ b/core/lls_core/models/utils.py @@ -68,3 +68,13 @@ def copy_validate(self, **kwargs) -> Self: """ updated = self.copy(**kwargs) return updated.validate(updated.dict()) + + @classmethod + def make(cls, validate: bool = True, **kwargs: Any): + """ + Creates an instance of this class, with validation either enabled or disabled + """ + if validate: + return cls(**kwargs) + else: + return cls.construct(**kwargs) diff --git a/plugin/napari_lattice/dock_widget.py b/plugin/napari_lattice/dock_widget.py index e754466a..2dfddd48 100644 --- a/plugin/napari_lattice/dock_widget.py +++ b/plugin/napari_lattice/dock_widget.py @@ -35,13 +35,13 @@ def _check_validity(self) -> bool: except: return False - def _make_model(self) -> LatticeData: + def _make_model(self, validate: bool = True) -> LatticeData: from rich import print from sys import stdout deskew_args = self.LlszMenu.WidgetContainer.deskew_fields._get_kwargs() - output_args = self.LlszMenu.WidgetContainer.output_fields._make_model() - params = LatticeData( + output_args = self.LlszMenu.WidgetContainer.output_fields._make_model(validate=False) + args = dict( input_image=deskew_args["data"], angle=deskew_args["angle"], channel_range=output_args.channel_range, @@ -56,6 +56,7 @@ def _make_model(self) -> LatticeData: deconvolution=self.LlszMenu.WidgetContainer.deconv_fields._make_model(), crop=self.LlszMenu.WidgetContainer.cropping_fields._make_model() ) + params = LatticeData.make(validate=validate, **args) # Log the lattice print(params, file=stdout) return params @@ -108,12 +109,18 @@ def __post_init__(self): call_button="Preview" ) @set_design(text="Preview") - def preview(self, header:str, time: int, channel: int): + def preview(self, header: str, time: int, channel: int): + from pathlib import Path + # We only need to process one time point for the preview, # so we made a copy using a subset of the times - lattice = self._make_model().copy_validate(update=dict( + lattice = self._make_model(validate=False).copy_validate(update=dict( time_range = range(time, time+1), channel_range = range(time, time+1), + # Patch in a placeholder for the save dir because previewing doesn't use it + # TODO: use a more elegant solution such as making the "saveable" lattice + # a child class which more validations + save_dir = Path.home() )) for slice in lattice.process().slices: diff --git a/plugin/napari_lattice/fields.py b/plugin/napari_lattice/fields.py index e4052991..30164378 100644 --- a/plugin/napari_lattice/fields.py +++ b/plugin/napari_lattice/fields.py @@ -501,8 +501,10 @@ class OutputFields(NapariFieldGroup): ) errors = field(Label).with_options(label="Errors") - def _make_model(self) -> OutputParams: - return OutputParams( + def _make_model(self, validate: bool = True) -> OutputParams: + return OutputParams.make( + validate=validate, + channel_range=range(self.channel_range.value[0], self.channel_range.value[1]), time_range=range(self.time_range.value[0], self.time_range.value[1]), save_dir=self.save_path.value, diff --git a/plugin/tests/test_dock_widget.py b/plugin/tests/test_dock_widget.py index ca780205..4a6cfd5f 100644 --- a/plugin/tests/test_dock_widget.py +++ b/plugin/tests/test_dock_widget.py @@ -68,11 +68,19 @@ def test_dock_widget(make_napari_viewer: Callable[[], Viewer], image_data: AICSI fields.img_layer.value = list(viewer.layers) fields.dimension_order.value = image_data.dims.order fields.pixel_sizes_source.value = PixelSizeSource.Manual + + # Test previewing + tester = FunctionGuiTester(ui.preview) + tester.call("", 0, 0) + + # Add the save path which shouldn't be needed for previewing ui.LlszMenu.WidgetContainer.output_fields.save_path.value = tmpdir - # fields.pixel_sizes.value = image_data.physical_pixel_sizes + + # Test saving tester = FunctionGuiTester(ui.save) tester.call() + def test_check_buildable(): ui = LLSZWidget() set_debug(ui)