Don't mark batched steps «À revalider».

This commit is contained in:
sebastien committed 2026-10-06 11:16:39 +02:00
1 parent c155e3eebc
commit 52a8589261
2 files changed
+45 -14

No files matched your search

+13 -7
View File
@@ -1591,12 +1591,7 @@ class CopienatorApp(tk.Tk):
self._save_current_form() self._save_current_form()
run_values = self._values() run_values = self._values()
ordered_ids = self._progression_ids(step.id) self._invalidate_after_step(step, variant.id)
if step.id == "correction" and variant.id == "integrate":
# Integration consumes the retrieved batches; it does not invalidate them.
ordered_ids = [step_id for step_id in ordered_ids
if not self.step_by_id[step_id].skip_for_live_correction]
self.state_store.invalidate_after(ordered_ids, step.id)
self.state_store.update_step( self.state_store.update_step(
step.id, step.id,
status="running", status="running",
@@ -1646,13 +1641,24 @@ class CopienatorApp(tk.Tk):
self._populate_tree() self._populate_tree()
self._update_controls() self._update_controls()
def _invalidate_after_step(self, step: StepDefinition, variant_id: str) -> None:
# Checking remote job status does not change any downstream input.
if step.id == "batch_status":
return
ordered_ids = self._progression_ids(step.id)
if step.id == "correction" and variant_id in {"live", "refaire", "integrate"}:
# These modes reuse correction inputs without generating new batches.
ordered_ids = [step_id for step_id in ordered_ids
if not self.step_by_id[step_id].skip_for_live_correction]
self.state_store.invalidate_after(ordered_ids, step.id)
def _mark_step( def _mark_step(
self, status: str, *, automatic: bool = False, reason: str | None = None self, status: str, *, automatic: bool = False, reason: str | None = None
) -> None: ) -> None:
if not self.current_step or not self.state_store.evaluation or self.active_step_id: if not self.current_step or not self.state_store.evaluation or self.active_step_id:
return return
self._save_current_form() self._save_current_form()
self.state_store.invalidate_after(self._progression_ids(self.current_step.id), self.current_step.id) self._invalidate_after_step(self.current_step, self._current_variant().id)
self.state_store.update_step(self.current_step.id, status=status) self.state_store.update_step(self.current_step.id, status=status)
history: dict[str, object] = { history: dict[str, object] = {
"step": self.current_step.id, "step": self.current_step.id,
+32 -7
View File
@@ -1,6 +1,7 @@
import os import os
import tempfile import tempfile
import unittest import unittest
from itertools import product
from pathlib import Path from pathlib import Path
from tkinter import ttk from tkinter import ttk
from unittest.mock import patch from unittest.mock import patch
@@ -280,9 +281,11 @@ class GuiConvenienceTests(unittest.TestCase):
self.assertEqual(self.app.state_store.step("correction")["variant"], "integrate") self.assertEqual(self.app.state_store.step("correction")["variant"], "integrate")
self.assertIn("--deal-with-batched", self.app._make_command()) self.assertIn("--deal-with-batched", self.app._make_command())
def test_integration_preserves_batch_statuses_but_invalidates_downstream_steps(self): def test_correction_invalidates_batches_only_when_regenerating_or_resetting(self):
for variant in ("integrate", "batch"): for variant, action in product(
with self.subTest(variant=variant): ("integrate", "live", "refaire", "batch", "hybrid", "reset"), ("run", "mark")
):
with self.subTest(variant=variant, action=action):
self.app.active_step_id = None self.app.active_step_id = None
self.app.current_step = None self.app.current_step = None
self.app.state_store.update_step("correction", variant=variant, batch_started=True) self.app.state_store.update_step("correction", variant=variant, batch_started=True)
@@ -294,14 +297,36 @@ class GuiConvenienceTests(unittest.TestCase):
self.app.tree.selection_set("correction") self.app.tree.selection_set("correction")
self.app.update() self.app.update()
with patch.object(self.app.runner, "start"), \ with patch.object(self.app.runner, "start"), \
patch.object(self.app, "_missing_requirements", return_value=[]): patch.object(self.app, "_missing_requirements", return_value=[]), \
self.app._run_current_step() patch("copienator_gui.app.messagebox.askyesno", return_value=True):
self.assertEqual(self.app.active_step_id, "correction") if action == "run":
self.app._run_current_step()
self.assertEqual(self.app.active_step_id, "correction")
else:
self.app._mark_step("success")
for step_id, status in statuses.items(): for step_id, status in statuses.items():
expected = status if variant == "integrate" and step_id != "annotation" else "stale" preserve = variant in {"integrate", "live", "refaire"} and step_id != "annotation"
expected = status if preserve else "stale"
self.assertEqual(self.app.state_store.step(step_id)["status"], expected) self.assertEqual(self.app.state_store.step(step_id)["status"], expected)
self.app.active_step_id = None self.app.active_step_id = None
def test_checking_batch_status_preserves_downstream_statuses(self):
self.app.state_store.update_step("correction", batch_started=True)
statuses = {"fetch_batches": "success", "annotation": "detected"}
for step_id, status in statuses.items():
self.app.state_store.update_step(step_id, status=status)
self.app._populate_tree()
self.app.tree.selection_set("batch_status")
self.app.update()
with patch.object(self.app.runner, "start"), \
patch.object(self.app, "_missing_requirements", return_value=[]):
self.app._run_current_step()
self.assertEqual(self.app.active_step_id, "batch_status")
self.app.active_step_id = None
self.app._mark_step("success")
for step_id, status in statuses.items():
self.assertEqual(self.app.state_store.step(step_id)["status"], status)
def test_unsuccessful_batch_retrieval_stays_on_retrieval(self): def test_unsuccessful_batch_retrieval_stays_on_retrieval(self):
self.app.state_store.update_step("correction", variant="batch", last_run_variant="batch") self.app.state_store.update_step("correction", variant="batch", last_run_variant="batch")
self.app._populate_tree() self.app._populate_tree()