32k pixel as hard group limit, better manual resolution support

This commit is contained in:
sebastien committed 2026-09-22 11:42:16 +02:00
1 parent a9c0703f03
commit 5009831c7c
9 files changed
+322 -58

No files matched your search

+34 -8
View File
@@ -10,7 +10,8 @@ from pathlib import Path
from tkinter import filedialog, messagebox, ttk
from typing import Any
from copienator import CliError, EvaluationWorkspace, ExitCode, atomic_write_json
from copienator import CliError, EvaluationWorkspace, ExitCode, atomic_write_json, read_json
from copienator.commands.resolve_manual import pending_manual_conflicts
from copienator.copy_errors import copy_errors
from copienator.filesystem import staged_files
from copienator.platform import (
@@ -244,7 +245,14 @@ def has_manual_conflicts(path: Path) -> bool:
# If the file cannot be inspected, keep the step visible rather than
# silently claiming that there is nothing to resolve.
return True
return any(line.strip() and not line.lstrip().startswith("###") for line in lines)
if any(line.strip() and not line.lstrip().startswith("###") for line in lines):
return True
# An emptied manual file still needs execution to acknowledge deletions.
try:
results = read_json(path.parent / "correction.json", default={})
return bool(pending_manual_conflicts(results))
except (OSError, ValueError, TypeError, KeyError, AttributeError):
return True
class CopienatorApp(tk.Tk):
@@ -1459,6 +1467,10 @@ class CopienatorApp(tk.Tk):
self._save_current_form()
run_values = self._values()
ordered_ids = self._progression_ids(step.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(
step.id,
@@ -1728,11 +1740,14 @@ class CopienatorApp(tk.Tk):
"sur « Marquer terminée »."
)
return
if step_id in {"labels", "correction"} and self.state_store.evaluation:
completion = (
"détection des labels terminée"
if step_id == "labels" else "étape de correction terminée"
)
notified_completions = {
"labels": "détection des labels terminée",
"correction": "étape de correction terminée",
"annotation": "génération des copies annotées terminée",
"read_annotations": "lecture des annotations manuscrites terminée",
}
if step_id in notified_completions and self.state_store.evaluation:
completion = notified_completions[step_id]
outcome = STATUS_LABELS[status].lower()
self._notify_completion(
f"Copienator — {completion} ({outcome})",
@@ -1744,7 +1759,9 @@ class CopienatorApp(tk.Tk):
self.batch_monitor.stop()
self._batch_results_ready()
return
if step_id == "manual_resolution":
if step_id == "fetch_batches":
self.after_idle(self._select_batch_integration)
elif step_id == "manual_resolution":
self.after_idle(self._select_refaire_correction)
else:
self.after_idle(
@@ -1842,6 +1859,15 @@ class CopienatorApp(tk.Tk):
self.tree.selection_set(ids[target])
self.tree.see(ids[target])
def _select_batch_integration(self) -> None:
"""Prepare integration after batch results have been retrieved."""
if self.runner.running or self.active_step_id or not self.state_store.evaluation:
return
self._save_current_form()
self.state_store.update_step("correction", variant="integrate")
self.tree.selection_set("correction")
self.tree.see("correction")
def _select_refaire_correction(self) -> None:
"""Return from manual conflict resolution to the main redo correction."""
if self.runner.running or self.active_step_id or not self.state_store.evaluation: