wip
CI for debye_bec / test (pull_request) Successful in 1m27s
CI for debye_bec / test (push) Successful in 3m4s

This commit is contained in:
2026-09-24 14:37:59 +02:00
parent 64a8cc035f
commit 6452b7cea4
2 changed files with 38 additions and 11 deletions
@@ -46,7 +46,7 @@ def index_of(items: list[ScheduleItem], item_id: str | None) -> int | None:
def pick_next_runnable(
items: list[ScheduleItem], repeat_aborted_item
items: list[ScheduleItem], repeat_aborted_item, first_item: int = 0
) -> ScheduleItem | Literal["stop"] | None:
"""
What the execution loop should do next: always re-derived from scratch
@@ -57,9 +57,13 @@ def pick_next_runnable(
earlier item failed/was aborted (execution stays parked there until the
operator intervenes), or `None` if every item is COMPLETED.
"""
logger.info(f"pick next runnable, repeat abort item is {repeat_aborted_item}")
for item in items:
logger.info(
f"pick next runnable, repeat abort item is {repeat_aborted_item} and first item is {first_item}"
)
for idx, item in enumerate(items):
logger.info(f"item: {item}")
if idx < first_item:
continue
if item.status == ScheduleItemStatus.COMPLETED:
continue
if item.status == ScheduleItemStatus.ABORTED:
@@ -460,14 +460,16 @@ class Scheduler(BECWidget, QWidget):
run_row = QHBoxLayout()
self.run_btn = MyButton("Run / Continue", "success")
self.abort_btn = MyButton("Abort", "emergency")
self.reset_btn = MyButton("Reset", "warning")
for button in (self.run_btn, self.abort_btn, self.reset_btn):
self.run_from_current_btn = MyButton("Run / Continue from current selection", "success")
self.abort_btn = MyButton("Pause after current item", "emergency")
self.reset_btn = MyButton("Reset Schedule Status", "warning")
for button in (self.run_btn, self.run_from_current_btn, self.abort_btn, self.reset_btn):
run_row.addWidget(button)
run_row.addStretch()
control_layout.addLayout(run_row)
self.run_btn.clicked.connect(self.run_schedule)
self.run_from_current_btn.connect(self.run_schedule_from_selection)
self.abort_btn.clicked.connect(self.abort_schedule)
self.reset_btn.clicked.connect(self.reset_schedule)
@@ -660,8 +662,10 @@ class Scheduler(BECWidget, QWidget):
row = self._table_model.row_of(self._selected_item_id)
if row is not None:
self.table_view.selectRow(row)
self.run_from_current_btn.setEnabled(True)
else:
self._selected_item_id = None
self.run_from_current_btn.setEnabled(False)
selection_model.blockSignals(False)
@@ -722,6 +726,13 @@ class Scheduler(BECWidget, QWidget):
self.copy_btn.setEnabled(selected_item is not None)
self.paste_btn.setEnabled(self._clipboard_item is not None)
# Update execution control buttons
state = self._current_report is None # True if schedule is not running
self.run_btn.setEnabled(state)
self.run_from_current_btn.setEnabled(state)
self.abort_btn.setEnabled(not state)
self.reset_btn.setEnabled(state)
@SafeSlot()
def _on_schedule_name_change(self):
name = self.schedule_name_input.text()
@@ -1103,7 +1114,7 @@ class Scheduler(BECWidget, QWidget):
# RPC-exposed actions (USER_ACCESS)
# ------------------------------------------------------------------ #
@SafeSlot()
def run_schedule(self):
def run_schedule(self, first_item: int = 0):
"""Run the schedule, continuing from wherever it last left off."""
with self._lock:
if self.schedule.is_running:
@@ -1126,9 +1137,21 @@ class Scheduler(BECWidget, QWidget):
self.submit_task(
self._run_all,
repeat_aborted_item,
first_item,
on_complete=self._on_run_finished,
on_failed=self._on_run_failed,
)
self._refresh_ui()
@SafeSlot()
def run_schedule_from_selection(self):
"""Run the schedule, starting from the current selected item."""
if self._selected_item_id is None:
return
with self._lock:
idx = self._index_of_locked(self._selected_item_id)
if idx is not None:
self.run_schedule(idx)
@SafeSlot()
def abort_schedule(self):
@@ -1314,9 +1337,9 @@ class Scheduler(BECWidget, QWidget):
# the `schedule_changed` Qt signal so they are marshalled back onto
# the GUI thread instead of touching widgets directly)
# ------------------------------------------------------------------ #
def _pick_next_runnable_locked(self, repeat_aborted_item):
def _pick_next_runnable_locked(self, repeat_aborted_item, first_item):
"""Must be called while holding `self._lock`; see `schedule_logic.pick_next_runnable`."""
return pick_next_runnable(self.schedule.items, repeat_aborted_item)
return pick_next_runnable(self.schedule.items, repeat_aborted_item, first_item)
@SafeSlot()
def _on_run_finished(self):
@@ -1356,7 +1379,7 @@ class Scheduler(BECWidget, QWidget):
super().cleanup()
def _run_all(self, repeat_aborted_item):
def _run_all(self, repeat_aborted_item, first_item):
notify_schedule_state(
self.client, self.schedule.notifications, self.schedule.schedule_name, "started"
)
@@ -1369,7 +1392,7 @@ class Scheduler(BECWidget, QWidget):
}
while not self._abort_requested and not self._closing.is_set():
with self._lock:
next_item = self._pick_next_runnable_locked(repeat_aborted_item)
next_item = self._pick_next_runnable_locked(repeat_aborted_item, first_item)
if next_item is None or next_item == "stop":
logger.info("Next item is None or stop")
break