opton to skip visual check in cutleft

This commit is contained in:
sebastien committed 2026-09-29 15:46:47 +02:00
1 parent 5b7d4b611e
commit 2f8422f6d5
5 files changed
+112 -3

No files matched your search

+37 -1
View File
@@ -384,6 +384,7 @@ def run(
target: Path,
*,
fullpage: bool = False,
no_visual_check: bool = False,
marked: bool = False,
) -> ExitCode:
files = marked_copy_paths(workspace) if marked else _selected_files(workspace, target)
@@ -392,6 +393,30 @@ def run(
return ExitCode.SUCCESS
workspace.cutleft_dir.mkdir(parents=True, exist_ok=True)
_get_pdf_pages_cached.cache_clear()
if fullpage and no_visual_check:
had_errors = False
for pdf_path in files:
result = process_single_pdf(pdf_path, max_per_file=1)
if result is None:
mark_copy_error(
workspace,
pdf_path,
"Échec de la conversion en pages entières",
)
had_errors = True
continue
try:
save_results(result, pdf_path, workspace.cutleft_dir)
clear_copy_error(workspace, pdf_path)
except Exception as exc: # noqa: BLE001 - continue with remaining copies
mark_copy_error(
workspace,
pdf_path,
f"Échec de l’enregistrement : {exc}",
)
print(f"[Copie signalée] {pdf_path.name}: {exc}")
had_errors = True
return ExitCode.PARTIAL if had_errors else ExitCode.SUCCESS
reviewer = ImageReviewer(
files,
workspace.cutleft_dir,
@@ -410,6 +435,11 @@ def build_parser() -> argparse.ArgumentParser:
action="store_true",
help="Use each complete page instead of cropping the label margin",
)
parser.add_argument(
"--no-visual-check",
action="store_true",
help="Save full pages without opening the visual reviewer (requires --fullpage)",
)
return parser
@@ -418,7 +448,13 @@ def main(argv: Sequence[str] | None = None) -> int:
def handle(args: argparse.Namespace) -> ExitCode:
workspace, target = workspace_from_target(args)
return run(workspace, target, fullpage=args.fullpage, marked=args.marked)
return run(
workspace,
target,
fullpage=args.fullpage,
no_visual_check=args.no_visual_check,
marked=args.marked,
)
return execute(parser, argv, handle)
+7
View File
@@ -285,6 +285,13 @@ def build_workflow(show_personal_steps: bool) -> list[StepDefinition]:
"--fullpage",
help="Désactive la découpe habituelle de la marge gauche et transmet chaque page entière à la détection des labels.",
),
ArgumentSpec(
"no_visual_check",
"et ne pas vérifier visuellement",
"bool",
"--no-visual-check",
help="Avec « Toujours utiliser la page entière », enregistre directement les images sans ouvrir la fenêtre de vérification.",
),
ArgumentSpec(
"marked",
"Copies signalées uniquement",
+18
View File
@@ -51,6 +51,24 @@ class GuiConvenienceTests(unittest.TestCase):
start.assert_not_called()
self.assertEqual(self.app.state_store.step(step.id)["status"], "success")
def test_cutleft_visual_check_option_is_below_and_off_by_default(self):
step = self.app.step_by_id["cutleft"]
self.app.current_step = step
self.app._render_step()
labels = {
child.cget("text"): child
for child in self.app.form.winfo_children()
if isinstance(child, ttk.Label)
}
fullpage = labels["Toujours utiliser la page entière ⓘ"]
no_visual_check = labels["et ne pas vérifier visuellement ⓘ"]
self.assertGreater(
int(no_visual_check.grid_info()["row"]),
int(fullpage.grid_info()["row"]),
)
self.assertFalse(self.app.arg_vars["no_visual_check"].get())
@staticmethod
def _label_texts(widget):
return [
+19 -1
View File
@@ -566,7 +566,11 @@ class StandardCliTests(unittest.TestCase):
"cutleft": (
"cutleft",
"default",
{"target": evaluation, "fullpage": True},
{
"target": evaluation,
"fullpage": True,
"no_visual_check": True,
},
),
"splitting_int": (
"splitting",
@@ -757,6 +761,20 @@ class StandardCliTests(unittest.TestCase):
self.assertEqual(output_dir, evaluation / "Cutleft")
self.assertEqual(reviewer.call_args.kwargs["default_max_per_file"], 1)
result = (Mock(), [Mock()], {})
with patch.object(module, "ImageReviewer") as reviewer, patch.object(
module, "process_single_pdf", return_value=result
) as process, patch.object(module, "save_results") as save:
self.assertEqual(
module.main(
[str(copy_pdf), "--fullpage", "--no-visual-check"]
),
0,
)
reviewer.assert_not_called()
process.assert_called_once_with(copy_pdf, max_per_file=1)
save.assert_called_once_with(result, copy_pdf, evaluation / "Cutleft")
def test_cutleft_atomic_save_removes_only_obsolete_copy_outputs(self) -> None:
module = self.modules["cutleft"]
with tempfile.TemporaryDirectory() as directory:
+31 -1
View File
@@ -4,7 +4,7 @@ import threading
import unittest
from pathlib import Path
from queue import Queue
from unittest.mock import Mock, patch
from unittest.mock import Mock, call, patch
from PIL import Image
@@ -157,6 +157,36 @@ class MarkedCopiesTests(unittest.TestCase):
self.assertEqual(cutleft.main([str(self.workspace.root), "--marked"]), expected)
self.assertEqual(reviewer.call_args.args[0], [self.files[1]])
def test_fullpage_processes_every_copy_without_opening_the_reviewer(self):
for path in self.files:
mark_copy_error(self.workspace, path, "Review needed")
image = Image.new("RGB", (8, 8), "white")
result = (image, [image], {"columns_per_file": [1]})
with patch.object(
cutleft, "process_single_pdf", side_effect=[result, None]
) as process, patch.object(cutleft, "save_results") as save, patch.object(
cutleft, "ImageReviewer"
) as reviewer:
status = cutleft.run(
self.workspace,
self.workspace.root,
fullpage=True,
no_visual_check=True,
)
self.assertEqual(status, ExitCode.PARTIAL)
reviewer.assert_not_called()
self.assertEqual(
process.call_args_list,
[
call(self.files[0], max_per_file=1),
call(self.files[1], max_per_file=1),
],
)
save.assert_called_once_with(result, self.files[0], self.workspace.cutleft_dir)
self.assertEqual(set(copy_errors(self.workspace)), {"Copie02.pdf"})
@unittest.skipUnless(os.environ.get("DISPLAY"), "Tk requires a display")
class MarkedCopiesGuiTests(unittest.TestCase):