Standardisation 2
This commit is contained in:
+172
-1
@@ -45,7 +45,12 @@ def load_script_module(filename: str, module_name: str):
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"Could not load {filename}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
sys.modules[module_name] = module
|
||||
try:
|
||||
spec.loader.exec_module(module)
|
||||
except Exception:
|
||||
sys.modules.pop(module_name, None)
|
||||
raise
|
||||
return module
|
||||
|
||||
|
||||
@@ -155,12 +160,24 @@ class StandardCliTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
cls.modules = {
|
||||
"copies_tools": load_script_module(
|
||||
"copies_tools.py", "copienator_copies_tools_test"
|
||||
),
|
||||
"export": load_script_module("export.py", "copienator_export_test"),
|
||||
"import": load_script_module("import.py", "copienator_import_test"),
|
||||
"giving_names": load_script_module(
|
||||
"giving_names.py", "copienator_giving_names_test"
|
||||
),
|
||||
"grouping": load_script_module("grouping.py", "copienator_grouping_test"),
|
||||
"post_correction": load_script_module(
|
||||
"post-correction.py", "copienator_post_correction_test"
|
||||
),
|
||||
"resolve_manual": load_script_module(
|
||||
"resolve_manual.py", "copienator_resolve_manual_test"
|
||||
),
|
||||
"verify_groups": load_script_module(
|
||||
"verify_groups.py", "copienator_verify_groups_test"
|
||||
),
|
||||
}
|
||||
|
||||
def test_missing_evaluation_has_standard_exit_code(self) -> None:
|
||||
@@ -171,6 +188,10 @@ class StandardCliTests(unittest.TestCase):
|
||||
"import": [missing],
|
||||
"giving_names": [missing, "BGnot"],
|
||||
"grouping": [missing],
|
||||
"post_correction": [missing],
|
||||
"resolve_manual": [missing],
|
||||
"verify_groups": [missing],
|
||||
"copies_tools": ["rotate", missing],
|
||||
}
|
||||
for name, arguments in invocations.items():
|
||||
with self.subTest(script=name), redirect_stderr(io.StringIO()):
|
||||
@@ -223,6 +244,21 @@ class StandardCliTests(unittest.TestCase):
|
||||
{"target": evaluation, "annotation_dir": "BGnot"},
|
||||
),
|
||||
"grouping": ("grouping", "default", {"target": evaluation}),
|
||||
"post_correction": (
|
||||
"post_correction",
|
||||
"default",
|
||||
{"target": evaluation},
|
||||
),
|
||||
"resolve_manual": (
|
||||
"manual_resolution",
|
||||
"default",
|
||||
{"target": evaluation},
|
||||
),
|
||||
"verify_groups": (
|
||||
"verify_groups",
|
||||
"default",
|
||||
{"target": evaluation},
|
||||
),
|
||||
}
|
||||
for module_name, (step_id, variant_id, values) in cases.items():
|
||||
step = steps[step_id]
|
||||
@@ -232,6 +268,23 @@ class StandardCliTests(unittest.TestCase):
|
||||
parsed = self.modules[module_name].build_parser().parse_args(command[3:])
|
||||
self.assertEqual(str(parsed.evaluation), evaluation)
|
||||
|
||||
for step_id in ("rotate", "rename"):
|
||||
step = steps[step_id]
|
||||
variant = step.variants[0]
|
||||
command = build_command(
|
||||
REPOSITORY,
|
||||
step,
|
||||
variant,
|
||||
{"target": evaluation},
|
||||
evaluation,
|
||||
)
|
||||
with self.subTest(script=f"copies_tools:{step_id}"):
|
||||
parsed = self.modules["copies_tools"].build_parser().parse_args(
|
||||
command[3:]
|
||||
)
|
||||
self.assertEqual(parsed.operation, step_id)
|
||||
self.assertEqual(str(parsed.evaluation), evaluation)
|
||||
|
||||
def test_export_main_copies_outputs(self) -> None:
|
||||
module = self.modules["export"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
@@ -287,6 +340,124 @@ class StandardCliTests(unittest.TestCase):
|
||||
self.assertEqual(module.main([str(evaluation)]), 0)
|
||||
self.assertTrue((evaluation / "Par label").is_dir())
|
||||
|
||||
def test_post_correction_main_cleans_json_atomically(self) -> None:
|
||||
module = self.modules["post_correction"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
evaluation = Path(directory) / "Exam"
|
||||
evaluation.mkdir()
|
||||
atomic_write_json(
|
||||
evaluation / "correction.json",
|
||||
{"text": "outside_name and $math_name$", "suffix": "_new"},
|
||||
)
|
||||
self.assertEqual(module.main([str(evaluation)]), 0)
|
||||
self.assertEqual(
|
||||
read_json(evaluation / "correction.json"),
|
||||
{"text": r"outside\_name and $math_name$", "suffix": "_new"},
|
||||
)
|
||||
|
||||
def test_manual_resolution_with_no_actions_is_safe(self) -> None:
|
||||
module = self.modules["resolve_manual"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
evaluation = Path(directory) / "Exam"
|
||||
(evaluation / "Copies").mkdir(parents=True)
|
||||
atomic_write_json(evaluation / "correction.json", {})
|
||||
manual = evaluation / "manual_resolutions.txt"
|
||||
manual.write_text("### Nothing to do\n", encoding="utf-8")
|
||||
|
||||
self.assertEqual(module.main([str(evaluation)]), 0)
|
||||
self.assertFalse(manual.exists())
|
||||
self.assertEqual(read_json(evaluation / "correction.json"), {})
|
||||
|
||||
def test_malformed_manual_resolution_is_not_deleted(self) -> None:
|
||||
module = self.modules["resolve_manual"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
evaluation = Path(directory) / "Exam"
|
||||
(evaluation / "Copies").mkdir(parents=True)
|
||||
correction = evaluation / "correction.json"
|
||||
atomic_write_json(correction, {})
|
||||
manual = evaluation / "manual_resolutions.txt"
|
||||
manual.write_text("this is malformed\n", encoding="utf-8")
|
||||
before = correction.read_bytes()
|
||||
|
||||
with redirect_stderr(io.StringIO()):
|
||||
self.assertEqual(module.main([str(evaluation)]), 1)
|
||||
self.assertTrue(manual.exists())
|
||||
self.assertEqual(correction.read_bytes(), before)
|
||||
|
||||
def test_documented_manual_resolution_operators_are_parsed(self) -> None:
|
||||
module = self.modules["resolve_manual"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path = Path(directory) / "manual_resolutions.txt"
|
||||
path.write_text(
|
||||
"\n".join(
|
||||
f"Copie01 Old label {operator} New label"
|
||||
for operator in module.OPERATORS
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
instructions = module.parse_instructions(path)
|
||||
self.assertEqual(
|
||||
[instruction.operator for instruction in instructions],
|
||||
list(module.OPERATORS),
|
||||
)
|
||||
|
||||
def test_replace_manual_resolution_creates_refaire_state(self) -> None:
|
||||
module = self.modules["resolve_manual"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
evaluation = Path(directory) / "Exam"
|
||||
copy_dir = evaluation / "Copies" / "Copie01"
|
||||
copy_dir.mkdir(parents=True)
|
||||
(copy_dir / "Old.pdf").write_bytes(b"old answer")
|
||||
(copy_dir / "New.pdf").write_bytes(b"replaced answer")
|
||||
atomic_write_json(
|
||||
evaluation / "correction.json",
|
||||
{
|
||||
"Old": [
|
||||
[
|
||||
{
|
||||
"id": "01",
|
||||
"result": {"error": "wrg-lbl:New?delayed"},
|
||||
}
|
||||
]
|
||||
],
|
||||
"New": [[{"id": "01", "result": {"error": ""}}]],
|
||||
},
|
||||
)
|
||||
(evaluation / "manual_resolutions.txt").write_text(
|
||||
"Copie01 Old -x New\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
self.assertEqual(module.main([str(evaluation)]), 0)
|
||||
self.assertEqual((copy_dir / "New_old.pdf").read_bytes(), b"replaced answer")
|
||||
self.assertEqual((copy_dir / "New_new.pdf").read_bytes(), b"old answer")
|
||||
self.assertEqual(
|
||||
read_json(evaluation / "refaire.json"),
|
||||
[["Copie01", ["New"]]],
|
||||
)
|
||||
correction = read_json(evaluation / "correction.json")
|
||||
self.assertEqual(
|
||||
correction["Old"][0][0]["result"]["error"],
|
||||
"wrg-lbl-moved-to:New",
|
||||
)
|
||||
self.assertEqual(correction["New"][0][0]["result"]["suffix"], "_new")
|
||||
|
||||
def test_verify_groups_reports_success_and_missing_answers(self) -> None:
|
||||
module = self.modules["verify_groups"]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
evaluation = Path(directory) / "Exam"
|
||||
copy_dir = evaluation / "Copies" / "Copie01"
|
||||
group_dir = evaluation / "Par label" / "Ex 1"
|
||||
copy_dir.mkdir(parents=True)
|
||||
group_dir.mkdir(parents=True)
|
||||
(copy_dir / "Ex 1.pdf").write_bytes(b"pdf")
|
||||
|
||||
self.assertEqual(module.main([str(evaluation)]), 1)
|
||||
atomic_write_json(
|
||||
group_dir / "Group_1.json",
|
||||
[["01", 0, 100, 1.0, "Ex 1"]],
|
||||
)
|
||||
self.assertEqual(module.main([str(evaluation)]), 0)
|
||||
|
||||
|
||||
class WorkflowTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user