Keep empty answers in the final individual outputs.

This commit is contained in:
sebastien committed 2026-10-13 10:15:57 +02:00
1 parent b1f1e0bc86
commit e7094d850e
8 files changed
+164 -37

No files matched your search

+85 -8
View File
@@ -57,8 +57,8 @@ class AnswerReturnTests(unittest.TestCase):
), patch.object(annotating, "make_base_image", side_effect=self.supplement):
publish_answer_returns(self.root, self.source, self.destination)
files = sorted((self.destination / "answers").glob("*.jpg"))
self.assertEqual([p.name for p in files], ["Ex 1.jpg", "Ex 2.jpg"])
with Image.open(files[0]) as image:
self.assertEqual([p.name for p in files], ["Empty.jpg", "Ex 1.jpg", "Ex 2.jpg"])
with Image.open(self.destination / "answers" / "Ex 1.jpg") as image:
self.assertEqual(image.size, (100, 30 + 20 * sum((context, question, solution))))
colors = []
if context:
@@ -212,7 +212,7 @@ class AnswerReturnTests(unittest.TestCase):
)
self.assertEqual(
sorted(path.name for path in answers.iterdir()),
["Ex 1.jpg", "Ex 2.jpg"],
["Empty.jpg", "Ex 1.jpg", "Ex 2.jpg"],
)
@@ -304,7 +304,7 @@ class CompiledMembershipTests(unittest.TestCase):
self.assertEqual(info["Empty"], {"present": True, "not_empty": False, "touched": False, "score": "0"})
self.assertEqual(info["Absent"], {"present": False, "not_empty": False, "touched": False, "score": ""})
self.assertEqual(info["Perfect"], {"present": True, "not_empty": True, "touched": False, "score": "4"})
self.assertNotIn("Empty", rendered)
self.assertIn("Empty", rendered)
for label in rendered:
self.assertTrue((output / f"{label}.jpg").is_file())
# Selective redo keeps unselected saved answers in the PDF,
@@ -316,6 +316,76 @@ class CompiledMembershipTests(unittest.TestCase):
self.assertTrue(read_json(output / "info.json")["Perfect"]["touched"])
self.assertFalse(read_json(output / "info.json")["Empty"]["not_empty"])
def test_real_empty_pdf_is_published_in_all_annotation_modes(self):
import fitz
from copienator.commands import reading_annotations as standard
for mode in ("Anot", "Bnot", "BGnot"):
with self.subTest(mode=mode), tempfile.TemporaryDirectory() as directory:
root = Path(directory)
workspace = EvaluationWorkspace(root)
(root / "labels").write_text("Empty\nAbsent\n")
pdf = root / "answer.pdf"
with fitz.open() as document:
page = document.new_page(width=200, height=60)
page.insert_text((10, 30), "Copied question only")
document.save(pdf)
data = {"01": {"Empty": {"pdf_path": pdf, "coordinates": (0, 0),
"result": {"score": 0, "error": "empty-answer", "feedback": []}}}}
if mode == "Anot":
status = annotating.process_student("01", data["01"], root, ["Empty", "Absent"], True)
self.assertEqual(status, "success")
elif mode == "Bnot":
status = standard.apply_actions_and_regenerate(
workspace, data, "01", [], None, ["Empty", "Absent"])
self.assertEqual(status, 0)
else:
status, _ = reader.apply_actions_and_regenerate_grouped(
workspace, data, "01", [], {}, ["Empty", "Absent"])
self.assertEqual(status, 0)
output = root / mode / "Copie01"
destination = root / "return"
destination.mkdir()
with patch.multiple(configuration, RETURN_ANSWERS_ENABLED=True,
RETURN_ANSWERS_CONTEXT=False, RETURN_ANSWERS_QUESTION=False,
RETURN_ANSWERS_SOLUTION=False):
publish_answer_returns(root, output, destination)
self.assertEqual([p.name for p in (destination / "answers").iterdir()], ["Empty.jpg"])
with Image.open(destination / "answers" / "Empty.jpg") as image:
self.assertGreater(image.height, 0)
self.assertLess(image.convert("L").getextrema()[0], 100)
self.assertFalse(read_json(destination / "info.json")["Empty"]["not_empty"])
self.assertFalse((output / "Concat.jpg").exists())
self.assertFalse((output / "Concat_F.pdf").exists())
def test_bnot_recovers_empty_scans_missing_from_review_layout(self):
from copienator.commands import reading_annotations as standard
for only_empty in (False, True):
with self.subTest(only_empty=only_empty), tempfile.TemporaryDirectory() as directory:
workspace = EvaluationWorkspace(Path(directory))
output = workspace.root / "Bnot" / "Copie01"
output.mkdir(parents=True)
answer = workspace.root / "answer.pdf"
answer.touch()
labels = {"Empty": {"pdf_path": answer, "coordinates": (0, 0),
"result": {"score": 0, "error": "empty-answer"}}}
if not only_empty:
labels["Full"] = {"pdf_path": answer, "coordinates": (0, 0),
"result": {"score": 4}}
atomic_write_json(output / "bnote.json", {"images": [
{"label": "Full", "hmin": 0, "hmax": 50, "header_height": 0}]})
with patch.object(annotating, "make_base_image", return_value=(None, 0, 0)), patch.object(
annotating, "compose_label_image", return_value=(Image.new("RGB", (100, 50)), 0)
) as render:
status = standard.apply_actions_and_regenerate(
workspace, {"01": labels}, "01", [], None, [*labels, "Absent"])
self.assertEqual(status, 0)
self.assertTrue(all(call.kwargs["with_empty"] for call in render.call_args_list))
self.assertTrue((output / "Empty.jpg").is_file())
self.assertFalse((output / "Absent.jpg").exists())
self.assertFalse(read_json(output / "info.json")["Empty"]["not_empty"])
self.assertEqual((output / "Concat.jpg").exists(), not only_empty)
self.assertFalse((output / "Concat_F.jpg").exists())
def test_all_empty_removes_stale_concat_and_records_false(self):
with tempfile.TemporaryDirectory() as directory:
workspace = EvaluationWorkspace(Path(directory))
@@ -325,10 +395,17 @@ class CompiledMembershipTests(unittest.TestCase):
(output / name).write_bytes(b"stale")
atomic_write_json(output / "touched.json", {"Empty": True})
atomic_write_json(output / "answer_labels.json", ["Empty"])
status, _ = reader.apply_actions_and_regenerate_grouped(
workspace, {"01": {"Empty": {"result": {"score": 0, "error": "empty-answer"}}}},
"01", [], {}, ["Empty"]
)
answer = workspace.root / "answer.pdf"
answer.touch()
with patch.object(annotating, "make_base_image", return_value=(Image.new("RGB", (100, 50)), 0, 0)), patch.object(
annotating, "compose_label_image", return_value=(Image.new("RGB", (100, 50)), 0)
):
status, _ = reader.apply_actions_and_regenerate_grouped(
workspace, {"01": {"Empty": {"result": {"score": 0, "error": "empty-answer"},
"pdf_path": answer, "coordinates": (0, 0)}}},
"01", [], {}, ["Empty"]
)
self.assertTrue((output / "Empty.jpg").is_file())
self.assertEqual(status, 0)
self.assertEqual(read_json(output / "info.json"), {
"Empty": {"present": True, "not_empty": False, "touched": False, "score": "0"}