opton to skip visual check in cutleft
This commit is contained in:
1 parent
5b7d4b611e
commit
2f8422f6d5
5 files changed
+112
-3
No files matched your search
@@ -384,6 +384,7 @@ def run(
|
|||||||
target: Path,
|
target: Path,
|
||||||
*,
|
*,
|
||||||
fullpage: bool = False,
|
fullpage: bool = False,
|
||||||
|
no_visual_check: bool = False,
|
||||||
marked: bool = False,
|
marked: bool = False,
|
||||||
) -> ExitCode:
|
) -> ExitCode:
|
||||||
files = marked_copy_paths(workspace) if marked else _selected_files(workspace, target)
|
files = marked_copy_paths(workspace) if marked else _selected_files(workspace, target)
|
||||||
@@ -392,6 +393,30 @@ def run(
|
|||||||
return ExitCode.SUCCESS
|
return ExitCode.SUCCESS
|
||||||
workspace.cutleft_dir.mkdir(parents=True, exist_ok=True)
|
workspace.cutleft_dir.mkdir(parents=True, exist_ok=True)
|
||||||
_get_pdf_pages_cached.cache_clear()
|
_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(
|
reviewer = ImageReviewer(
|
||||||
files,
|
files,
|
||||||
workspace.cutleft_dir,
|
workspace.cutleft_dir,
|
||||||
@@ -410,6 +435,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Use each complete page instead of cropping the label margin",
|
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
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@@ -418,7 +448,13 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|||||||
|
|
||||||
def handle(args: argparse.Namespace) -> ExitCode:
|
def handle(args: argparse.Namespace) -> ExitCode:
|
||||||
workspace, target = workspace_from_target(args)
|
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)
|
return execute(parser, argv, handle)
|
||||||
|
|
||||||
|
|||||||
@@ -285,6 +285,13 @@ def build_workflow(show_personal_steps: bool) -> list[StepDefinition]:
|
|||||||
"--fullpage",
|
"--fullpage",
|
||||||
help="Désactive la découpe habituelle de la marge gauche et transmet chaque page entière à la détection des labels.",
|
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(
|
ArgumentSpec(
|
||||||
"marked",
|
"marked",
|
||||||
"Copies signalées uniquement",
|
"Copies signalées uniquement",
|
||||||
|
|||||||
@@ -51,6 +51,24 @@ class GuiConvenienceTests(unittest.TestCase):
|
|||||||
start.assert_not_called()
|
start.assert_not_called()
|
||||||
self.assertEqual(self.app.state_store.step(step.id)["status"], "success")
|
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
|
@staticmethod
|
||||||
def _label_texts(widget):
|
def _label_texts(widget):
|
||||||
return [
|
return [
|
||||||
|
|||||||
+19
-1
@@ -566,7 +566,11 @@ class StandardCliTests(unittest.TestCase):
|
|||||||
"cutleft": (
|
"cutleft": (
|
||||||
"cutleft",
|
"cutleft",
|
||||||
"default",
|
"default",
|
||||||
{"target": evaluation, "fullpage": True},
|
{
|
||||||
|
"target": evaluation,
|
||||||
|
"fullpage": True,
|
||||||
|
"no_visual_check": True,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
"splitting_int": (
|
"splitting_int": (
|
||||||
"splitting",
|
"splitting",
|
||||||
@@ -757,6 +761,20 @@ class StandardCliTests(unittest.TestCase):
|
|||||||
self.assertEqual(output_dir, evaluation / "Cutleft")
|
self.assertEqual(output_dir, evaluation / "Cutleft")
|
||||||
self.assertEqual(reviewer.call_args.kwargs["default_max_per_file"], 1)
|
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:
|
def test_cutleft_atomic_save_removes_only_obsolete_copy_outputs(self) -> None:
|
||||||
module = self.modules["cutleft"]
|
module = self.modules["cutleft"]
|
||||||
with tempfile.TemporaryDirectory() as directory:
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import threading
|
|||||||
import unittest
|
import unittest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, call, patch
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
@@ -157,6 +157,36 @@ class MarkedCopiesTests(unittest.TestCase):
|
|||||||
self.assertEqual(cutleft.main([str(self.workspace.root), "--marked"]), expected)
|
self.assertEqual(cutleft.main([str(self.workspace.root), "--marked"]), expected)
|
||||||
self.assertEqual(reviewer.call_args.args[0], [self.files[1]])
|
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")
|
@unittest.skipUnless(os.environ.get("DISPLAY"), "Tk requires a display")
|
||||||
class MarkedCopiesGuiTests(unittest.TestCase):
|
class MarkedCopiesGuiTests(unittest.TestCase):
|
||||||
|
|||||||
Reference in new issue
Block a user