Standardisation 4
This commit is contained in:
+104
-1
@@ -25,8 +25,9 @@ from copienator import (
|
||||
read_json,
|
||||
workspace_from_target,
|
||||
)
|
||||
from copienator.annotation_actions import apply_checkbox_actions, apply_score_overrides
|
||||
from copienator.annotation_data import AnnotationLoadResult, load_annotation_data
|
||||
from copienator.filesystem import staged_directory
|
||||
from copienator.filesystem import staged_directory, staged_files
|
||||
from copienator_gui.app import process_status
|
||||
from copienator_gui.diagnostics import collect_diagnostics
|
||||
from copienator_gui.runner import ProcessRunner
|
||||
@@ -237,6 +238,52 @@ class AnnotationDataTests(unittest.TestCase):
|
||||
leftovers = [path for path in destination.parent.iterdir() if path.name.startswith(".output.")]
|
||||
self.assertEqual(leftovers, [])
|
||||
|
||||
def test_staged_files_preserve_inputs_and_roll_back_outputs(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
destination = Path(directory) / "Copie01"
|
||||
destination.mkdir()
|
||||
(destination / "bnote.json").write_text("input", encoding="utf-8")
|
||||
(destination / "score.json").write_text("old", encoding="utf-8")
|
||||
|
||||
with self.assertRaises(RuntimeError), staged_files(destination) as staging:
|
||||
(staging / "score.json").write_text("broken", encoding="utf-8")
|
||||
(staging / "Concat.jpg").write_text("partial", encoding="utf-8")
|
||||
raise RuntimeError("rendering failed")
|
||||
self.assertEqual((destination / "score.json").read_text(), "old")
|
||||
self.assertFalse((destination / "Concat.jpg").exists())
|
||||
|
||||
with staged_files(destination) as staging:
|
||||
(staging / "score.json").write_text("new", encoding="utf-8")
|
||||
(staging / "Concat.jpg").write_text("complete", encoding="utf-8")
|
||||
self.assertEqual((destination / "score.json").read_text(), "new")
|
||||
self.assertEqual((destination / "bnote.json").read_text(), "input")
|
||||
|
||||
def test_annotation_actions_are_shared_and_do_not_touch_json_sources(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
score_path = Path(directory) / "score.json"
|
||||
atomic_write_json(score_path, {"Ex 1": "3"})
|
||||
labels_data = {
|
||||
"Ex 1": {
|
||||
"result": {
|
||||
"score": 1,
|
||||
"feedback": [{"text": "global"}],
|
||||
}
|
||||
}
|
||||
}
|
||||
logs = []
|
||||
dirty = apply_checkbox_actions(
|
||||
labels_data,
|
||||
[{"label": "Ex 1", "type": "del_global", "index": 0}],
|
||||
logs.append,
|
||||
)
|
||||
dirty |= apply_score_overrides(labels_data, score_path, logs.append)
|
||||
self.assertEqual(dirty, {"Ex 1"})
|
||||
self.assertTrue(
|
||||
labels_data["Ex 1"]["result"]["feedback"][0]["to_delete"]
|
||||
)
|
||||
self.assertEqual(labels_data["Ex 1"]["result"]["score"], "3")
|
||||
self.assertEqual(read_json(score_path), {"Ex 1": "3"})
|
||||
|
||||
|
||||
class StandardCliTests(unittest.TestCase):
|
||||
@classmethod
|
||||
@@ -249,6 +296,12 @@ class StandardCliTests(unittest.TestCase):
|
||||
"annotating_by_label": load_script_module(
|
||||
"annotating_by_label.py", "annotating_by_label"
|
||||
),
|
||||
"reading_annotations": load_script_module(
|
||||
"reading_annotations.py", "reading_annotations"
|
||||
),
|
||||
"reading_grouped_annotations": load_script_module(
|
||||
"reading_grouped_annotations.py", "reading_grouped_annotations"
|
||||
),
|
||||
"copies_tools": load_script_module(
|
||||
"copies_tools.py", "copienator_copies_tools_test"
|
||||
),
|
||||
@@ -284,6 +337,8 @@ class StandardCliTests(unittest.TestCase):
|
||||
"annotating": [missing],
|
||||
"annotating_with_checks": [missing],
|
||||
"annotating_by_label": [missing],
|
||||
"reading_annotations": [missing],
|
||||
"reading_grouped_annotations": [missing],
|
||||
}
|
||||
for name, arguments in invocations.items():
|
||||
with self.subTest(script=name), redirect_stderr(io.StringIO()):
|
||||
@@ -366,6 +421,16 @@ class StandardCliTests(unittest.TestCase):
|
||||
"grouped",
|
||||
{"target": evaluation, "overwrite": True},
|
||||
),
|
||||
"reading_annotations": (
|
||||
"read_annotations",
|
||||
"standard",
|
||||
{"target": evaluation, "update_score": True},
|
||||
),
|
||||
"reading_grouped_annotations": (
|
||||
"read_annotations",
|
||||
"grouped",
|
||||
{"target": evaluation, "update_score": True, "refaire": True},
|
||||
),
|
||||
}
|
||||
for module_name, (step_id, variant_id, values) in cases.items():
|
||||
step = steps[step_id]
|
||||
@@ -590,6 +655,44 @@ class StandardCliTests(unittest.TestCase):
|
||||
with redirect_stderr(io.StringIO()):
|
||||
self.assertEqual(module.main([str(evaluation), "--refaire"]), 3)
|
||||
|
||||
def test_grouped_reader_refaire_requires_refaire_file(self) -> None:
|
||||
module = self.modules["reading_grouped_annotations"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
evaluation = Path(directory) / "Exam"
|
||||
(evaluation / "Copies").mkdir(parents=True)
|
||||
(evaluation / "Par label").mkdir()
|
||||
(evaluation / "BGnot").mkdir()
|
||||
(evaluation / "labels").write_text("Ex 1\n", encoding="utf-8")
|
||||
atomic_write_json(evaluation / "correction.json", {})
|
||||
with redirect_stderr(io.StringIO()):
|
||||
self.assertEqual(module.main([str(evaluation), "--refaire"]), 3)
|
||||
|
||||
def test_note_detection_accepts_a_missing_note_layer(self) -> None:
|
||||
module = self.modules["reading_annotations"]
|
||||
self.assertFalse(module.has_significant_notes(None))
|
||||
|
||||
def test_grouped_reader_reports_worker_failures(self) -> None:
|
||||
module = self.modules["reading_grouped_annotations"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
evaluation = Path(directory) / "Exam"
|
||||
(evaluation / "Copies").mkdir(parents=True)
|
||||
(evaluation / "Par label").mkdir()
|
||||
(evaluation / "BGnot" / "Ex 1").mkdir(parents=True)
|
||||
(evaluation / "labels").write_text("Ex 1\n", encoding="utf-8")
|
||||
atomic_write_json(evaluation / "correction.json", {})
|
||||
loaded = AnnotationLoadResult({"01": {"Ex 1": {}}}, [])
|
||||
with (
|
||||
patch.object(module, "load_annotation_data", return_value=loaded),
|
||||
patch.object(
|
||||
module,
|
||||
"_scan_annotation_directory",
|
||||
side_effect=RuntimeError("worker failed"),
|
||||
),
|
||||
redirect_stderr(io.StringIO()) as errors,
|
||||
):
|
||||
self.assertEqual(module.main([str(evaluation)]), 1)
|
||||
self.assertIn("worker failed", errors.getvalue())
|
||||
|
||||
def test_checked_render_failure_preserves_previous_student_output(self) -> None:
|
||||
module = self.modules["annotating_with_checks"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
|
||||
Reference in New Issue
Block a user