Skip to content

Commit

Permalink
fix: fix quantity edit (#257)
Browse files Browse the repository at this point in the history
* fix: fix quantity edit

* fix test
  • Loading branch information
tlambert03 authored Dec 19, 2023
1 parent 1d38f2f commit ba86918
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
21 changes: 14 additions & 7 deletions src/pymmcore_widgets/useq_widgets/_column_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,20 +325,25 @@ def text_to_quant(self, text: str | None) -> pint.Quantity | None:
return None # pragma: no cover


pattern = r"(?:(?P<hours>\d+):)?(?:(?P<min>\d+):)?(?P<sec>\d+)([.,](?P<ms>\d+))?"
time_pattern = re.compile(
r"^(?:(?P<hours>\d+):)?(?:(?P<min>\d+):)?(?P<sec>\d+)?(?:[.,](?P<frac>\d+))?$"
)


# dateutil is a better way to parse time intervals...
# but it's an additional dependency for a tiny feature
def parse_timedelta(time_str: str) -> timedelta:
match = re.match(pattern, time_str)
match = time_pattern.match(time_str)

if not match: # pragma: no cover
raise ValueError(f"Invalid time interval format: {time_str}")

hours = int(match["hours"]) if match["hours"] else 0
minutes = int(match["min"]) if match["min"] else 0
seconds = int(match["sec"])
ms = int(match["ms"]) if match["ms"] else 0
return timedelta(hours=hours, minutes=minutes, seconds=seconds, microseconds=ms)
seconds = int(match["sec"]) if match["sec"] else 0
frac_sec = match["frac"]
frac_sec = float(f"0.{frac_sec}") if frac_sec else 0
return timedelta(hours=hours, minutes=minutes, seconds=seconds + frac_sec)


class QQuantityLineEdit(QLineEdit):
Expand Down Expand Up @@ -405,8 +410,10 @@ def quantity(self) -> pint.Quantity | int | float:


class QTimeLineEdit(QQuantityLineEdit):
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(None, parent)
def __init__(
self, contents: str | None = None, parent: QWidget | None = None
) -> None:
super().__init__(contents, parent)
self.setDimensionality("second")
self.setStyleSheet("QLineEdit { border: none; }")

Expand Down
28 changes: 22 additions & 6 deletions tests/test_useq_widgets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import enum
from datetime import timedelta
from typing import TYPE_CHECKING

import pint
Expand All @@ -22,8 +23,9 @@
)
from pymmcore_widgets.useq_widgets._column_info import (
FloatColumn,
QQuantityLineEdit,
QTimeLineEdit,
TextColumn,
parse_timedelta,
)
from pymmcore_widgets.useq_widgets._positions import MDAButton, QFileDialog, _MDAPopup

Expand Down Expand Up @@ -132,7 +134,7 @@ def test_mda_wdg(qtbot: QtBot):
@pytest.mark.parametrize("ext", ["json", "yaml", "foo"])
def test_mda_wdg_load_save(
qtbot: QtBot, tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ext: str
):
) -> None:
from pymmcore_widgets.useq_widgets._mda_sequence import QFileDialog

wdg = MDASequenceWidget()
Expand Down Expand Up @@ -166,8 +168,8 @@ def test_mda_wdg_load_save(
assert dest.read_text() == mda_no_meta.yaml(exclude_defaults=True)


def test_qquant_line_edit(qtbot: QtBot):
wdg = QQuantityLineEdit("1 s")
def test_qquant_line_edit(qtbot: QtBot) -> None:
wdg = QTimeLineEdit("1.0 s")
wdg.show()
qtbot.addWidget(wdg)
wdg.setUreg(pint.UnitRegistry())
Expand Down Expand Up @@ -411,7 +413,7 @@ def test_grid_plan_widget(qtbot: QtBot) -> None:
assert wdg.fovWidth() == 6


def test_proper_checked_index(qtbot):
def test_proper_checked_index(qtbot) -> None:
"""Testing that the proper tab is checked when setting a value
https://github.com/pymmcore-plus/pymmcore-widgets/issues/205
Expand All @@ -436,7 +438,7 @@ def test_proper_checked_index(qtbot):
)


def test_mda_wdg_with_autofocus(qtbot: QtBot):
def test_mda_wdg_with_autofocus(qtbot: QtBot) -> None:
wdg = MDASequenceWidget()
qtbot.addWidget(wdg)
wdg.show()
Expand All @@ -463,3 +465,17 @@ def test_mda_wdg_with_autofocus(qtbot: QtBot):
assert wdg.value().autofocus_plan
assert not wdg.value().stage_positions[0].sequence
assert not wdg.value().stage_positions[1].sequence


def test_parse_time() -> None:
assert parse_timedelta("2") == timedelta(seconds=2)
assert parse_timedelta("0.5") == timedelta(seconds=0.5)
assert parse_timedelta("0.500") == timedelta(seconds=0.5)
assert parse_timedelta("0.75") == timedelta(seconds=0.75)
# this syntax still fails... it assumes the 2 is hours, and the 30 is seconds...
# assert parse_timedelta("2:30") == timedelta(minutes=2, seconds=30)
assert parse_timedelta("1:20:15") == timedelta(hours=1, minutes=20, seconds=15)
assert parse_timedelta("0:00:00.500000") == timedelta(seconds=0.5)
assert parse_timedelta("3:40:10.500") == timedelta(
hours=3, minutes=40, seconds=10.5
)

0 comments on commit ba86918

Please sign in to comment.