Skip to content

Commit

Permalink
fix: fix include_z when setting stage positions value in PositionTabl…
Browse files Browse the repository at this point in the history
…e widget (#381)
  • Loading branch information
tlambert03 authored Nov 6, 2024
1 parent d58003b commit 7668eda
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/pymmcore_widgets/mda/_core_positions.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def setValue(self, value: Sequence[Position]) -> None: # type: ignore [override
self._set_position_table_editable(False)
value = tuple(value)
super().setValue(value)
self._update_z_enablement()

# ----------------------- private methods -----------------------

Expand Down
26 changes: 21 additions & 5 deletions src/pymmcore_widgets/useq_widgets/_positions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import json
import warnings
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, cast
Expand All @@ -20,6 +21,7 @@
QWidget,
)
from superqt.fonticon import icon
from superqt.utils import signals_blocked

from ._column_info import FloatColumn, TextColumn, WdgGetSet, WidgetColumn
from ._data_table import DataTableWidget
Expand Down Expand Up @@ -197,6 +199,12 @@ def value(
) -> Sequence[useq.Position]:
"""Return the current value of the table as a tuple of [useq.Position](https://pymmcore-plus.github.io/useq-schema/schema/axes/#useq.Position).
Note that `exclude_hidden_cols` has the result of:
- excluding the Z position in each of the Positions if
`include_z.isChecked()` is False
- excluding the AF offset in each of the Positions if
`af_per_position.isChecked()` is False
Parameters
----------
exclude_unchecked : bool, optional
Expand Down Expand Up @@ -248,10 +256,17 @@ def setValue(self, value: Sequence[useq.Position]) -> None: # type: ignore [ove
"""
_values = []
_use_af = False
for v in value:
if not isinstance(v, useq.Position): # pragma: no cover
raise TypeError(f"Expected useq.Position, got {type(v)}")
value = [useq.Position.model_validate(v) for v in value]

n_pos_with_z = sum(1 for v in value if v.z is not None)
if (_include_z := n_pos_with_z > 0) and n_pos_with_z < len(value):
warnings.warn(
"Only some positions have a z-position set. Z will be included, "
"but missing z-positions will be set to 0.",
stacklevel=2,
)

for v in value:
_af = {}
if v.sequence is not None and v.sequence.autofocus_plan is not None:
# set sub-sequence to None if empty or we simply exclude the af plan
Expand All @@ -275,8 +290,9 @@ def setValue(self, value: Sequence[useq.Position]) -> None: # type: ignore [ove
_values.append({**v.model_dump(exclude_unset=True), **_af})

super().setValue(_values)

self.af_per_position.setChecked(_use_af)
with signals_blocked(self):
self.include_z.setChecked(_include_z)
self.af_per_position.setChecked(_use_af)

def save(self, file: str | Path | None = None) -> None:
"""Save the current positions to a JSON file."""
Expand Down
26 changes: 26 additions & 0 deletions tests/useq_widgets/test_useq_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,32 @@ def test_mda_wdg_load_save(
assert dest.read_text() == mda_no_meta.yaml(exclude_defaults=True)


def test_mda_wdg_set_value_ignore_z(qtbot: QtBot) -> None:
wdg = MDASequenceWidget()
qtbot.addWidget(wdg)
wdg.show()

MDA_noZ = useq.MDASequence(
axis_order="p",
stage_positions=[(0, 1), useq.Position(x=42, y=0)],
keep_shutter_open_across=("z",),
)
assert wdg.stage_positions.include_z.isChecked()
wdg.setValue(MDA_noZ)
assert wdg.value().replace(metadata={}) == MDA_noZ
assert not wdg.stage_positions.include_z.isChecked()

MDA_partialZ = useq.MDASequence(
axis_order="p",
stage_positions=[(0, 1), useq.Position(x=42, y=0, z=3)],
keep_shutter_open_across=("z",),
)

with pytest.warns(match="Only some positions have a z-position"):
wdg.setValue(MDA_partialZ)
assert wdg.stage_positions.include_z.isChecked()


def test_qquant_line_edit(qtbot: QtBot) -> None:
wdg = QTimeLineEdit("1.0 s")
wdg.show()
Expand Down

0 comments on commit 7668eda

Please sign in to comment.