83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import re
|
|
import sys
|
|
from collections.abc import Sequence
|
|
from pathlib import Path
|
|
|
|
from copienator import (
|
|
EvaluationWorkspace,
|
|
ExitCode,
|
|
evaluation_parser,
|
|
execute,
|
|
read_json,
|
|
workspace_from_args,
|
|
)
|
|
|
|
COPY_PATTERN = re.compile(r"Copie(\d+)")
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
return evaluation_parser("Verify that every answer PDF appears in group metadata.")
|
|
|
|
|
|
def collect_source_pdfs(copies_dir: Path) -> set[tuple[str, str]]:
|
|
source_pdfs: set[tuple[str, str]] = set()
|
|
for copy_dir in copies_dir.iterdir():
|
|
match = COPY_PATTERN.fullmatch(copy_dir.name)
|
|
if not match or not copy_dir.is_dir():
|
|
continue
|
|
copy_id = match.group(1)
|
|
for pdf_path in copy_dir.glob("*.pdf"):
|
|
source_pdfs.add((pdf_path.stem, copy_id))
|
|
return source_pdfs
|
|
|
|
|
|
def collect_grouped_pdfs(groups_dir: Path) -> tuple[set[tuple[str, str]], int]:
|
|
grouped: set[tuple[str, str]] = set()
|
|
read_errors = 0
|
|
for json_path in groups_dir.glob("*/Group_*.json"):
|
|
try:
|
|
data = read_json(json_path)
|
|
if not isinstance(data, list):
|
|
raise TypeError("expected a JSON array")
|
|
for entry in data:
|
|
grouped.add((str(entry[4]), str(entry[0])))
|
|
except (IndexError, OSError, TypeError, ValueError) as exc:
|
|
print(f"Error reading {json_path}: {exc}", file=sys.stderr)
|
|
read_errors += 1
|
|
return grouped, read_errors
|
|
|
|
|
|
def verify_groups(workspace: EvaluationWorkspace) -> ExitCode:
|
|
workspace.require_directories("Copies", "Par label")
|
|
source_pdfs = collect_source_pdfs(workspace.copies_dir)
|
|
grouped_pdfs, read_errors = collect_grouped_pdfs(workspace.groups_dir)
|
|
missing = source_pdfs - grouped_pdfs
|
|
|
|
if missing:
|
|
print(f"Verification failed: {len(missing)} files missing from groups:")
|
|
for label, copy_id in sorted(missing):
|
|
print(f"Copie{copy_id}/{label}.pdf")
|
|
return ExitCode.FAILURE
|
|
if read_errors:
|
|
print("Verification incomplete because some metadata could not be read.")
|
|
return ExitCode.PARTIAL
|
|
print("Verification successful: all files accounted for.")
|
|
return ExitCode.SUCCESS
|
|
|
|
|
|
def run(workspace: EvaluationWorkspace) -> ExitCode:
|
|
return verify_groups(workspace)
|
|
|
|
|
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
parser = build_parser()
|
|
return execute(parser, argv, lambda args: run(workspace_from_args(args)))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|
|
|