Bnot fixes ; Missing énoncés fixes.

This commit is contained in:
sebastien committed 2026-10-23 11:15:05 +02:00
1 parent f39868207d
commit 55d5cf16c9
18 files changed
+486 -44

No files matched your search

+16 -10
View File
@@ -59,16 +59,20 @@ def copy_return_artifacts(source_dir: Path, destination_dir: Path) -> None:
shutil.copytree(answers_source, answers_destination)
def copy_histogram(output_dir: Path) -> None:
def copy_histogram(output_dir: Path, *, copy_merged_histogramme: bool = False) -> None:
"""Copy the score histogram beside the per-student output folders."""
if not HISTOGRAM_PATH.is_file():
print(f"Warning: Missing histogram '{HISTOGRAM_PATH}'.")
return
destination = output_dir / "histogramme.pdf"
shutil.copy2(HISTOGRAM_PATH, destination)
print(f"Copied histogram: {destination}")
sources = [(HISTOGRAM_PATH, "histogramme.pdf")]
if copy_merged_histogramme:
sources.append((HISTOGRAM_PATH.with_name("merged_histogramme.pdf"), "merged_histogramme.pdf"))
for source, filename in sources:
if not source.is_file():
print(f"Warning: Missing histogram '{source}'.")
continue
destination = output_dir / filename
shutil.copy2(source, destination)
print(f"Copied histogram: {destination}")
def process_images(base_dir, output_dir):
def process_images(base_dir, output_dir, *, copy_merged_histogramme=False):
# 1. Load Data
try:
# header=None assumes the file starts directly with data.
@@ -148,18 +152,20 @@ def process_images(base_dir, output_dir):
for pdf_path in pdf_paths:
shutil.copy2(pdf_path, student_output / pdf_path.name)
copy_histogram(output_dir)
copy_histogram(output_dir, copy_merged_histogramme=copy_merged_histogramme)
def main(argv=None):
parser = argparse.ArgumentParser(description="Stamp scores on exam copies.")
parser.add_argument("dir", type=Path, help="Root directory containing 'A Rendre' folder")
parser.add_argument("--copy-merged-histogramme", action="store_true",
help="Also copy merged_histogramme.pdf from the histogram staging directory")
args = parser.parse_args(argv)
base_dir = args.dir.expanduser().resolve()
output_dir = OUTPUT_DIR / base_dir.name
output_dir.mkdir(parents=True, exist_ok=True)
process_images(base_dir, output_dir)
process_images(base_dir, output_dir, copy_merged_histogramme=args.copy_merged_histogramme)
return 0
+2 -1
View File
@@ -19,7 +19,7 @@ from copienator import (
workspace_from_args,
)
from copienator.platform import WindowsLabelError, validate_windows_labels
from copienator.utils import compile_to_pdf
from copienator.utils import compile_to_pdf, warn_missing_exam_material
def fetch_and_save_sub_text(ex_id, indices, label, text_path):
@@ -327,6 +327,7 @@ def process_directory(workspace: EvaluationWorkspace) -> ExitCode:
labels_staging.replace(labels_file)
atomic_write_text(workspace.label_groups_file,
"".join(", ".join(group) + "\n" for group in exercise_groups))
warn_missing_exam_material(workspace)
return ExitCode.PARTIAL if had_errors else ExitCode.SUCCESS
+5 -1
View File
@@ -1024,6 +1024,7 @@ def write_exam_outputs(workspace: EvaluationWorkspace, grouped_extraction: Group
print(f"Wrote {len(grouped_extraction.groups)} groups; checking PDF compilation...")
compilation_status = compile_existing_pdfs(workspace)
utils.warn_missing_exam_material(workspace)
return ExitCode.PARTIAL if processing_errors or compilation_status != ExitCode.SUCCESS else ExitCode.SUCCESS
@@ -1093,7 +1094,10 @@ def main(argv: Sequence[str] | None = None) -> int:
if args.restart and (args.compile_only or args.groups_only or args.persp_only):
raise CliError('--restart cannot be combined with a partial action', ExitCode.INVALID_ARGUMENTS)
if args.compile_only:
return compile_existing_pdfs(workspace_from_args(args))
workspace = workspace_from_args(args)
status = compile_existing_pdfs(workspace)
utils.warn_missing_exam_material(workspace)
return status
if args.groups_only or args.persp_only:
kwargs = {'delete_persp': True} if args.delete_persp else {}
return refine_existing(workspace_from_args(args),
@@ -270,6 +270,12 @@ def apply_actions_and_regenerate(
concat_image.save(staging / "Concat.jpg")
if filtered_image is not None:
filtered_image.save(staging / "Concat_F.jpg")
# Imported here because the grouped reader also uses this module.
from copienator.commands.reading_grouped_annotations import save_checked_pdf
save_checked_pdf(
workspace.root, list(zip(filtered_labels, filtered, strict=True)),
all_labels, staging / "Concat_F.pdf",
)
stage_baseline(workspace.root, "Bnot", output_dir, staging, dirty_images,
header_heights, build_answer_info(scores, labels_data, answer_labels),
filtered_labels, scores)
@@ -147,6 +147,18 @@ def save_paginated_pdf(
)
def save_checked_pdf(root, labelled_images, all_labels, output_path):
"""Build the checked-mode return PDF with the same supplements as BGnot."""
groups = []
seen_contexts = set()
for label, image in labelled_images:
extras = get_extra_pdfs_as_images(
root, label, annotating, all_labels, seen_contexts=seen_contexts
)
groups.append([*extras, image])
save_paginated_pdf(groups, output_path)
def _scan_annotation_directory(
directory: Path,
only_ids: set[str] | None = None,
@@ -420,6 +432,12 @@ def apply_actions_and_regenerate_grouped(
[image for group in filtered_groups for image in group]
)
filtered_image.save(staging / "Concat_F.jpg")
if annotation_dir == "Bnot":
save_checked_pdf(
workspace.root,
[(label, dirty_images[label]) for label in filtered_labels],
all_labels, staging / "Concat_F.pdf",
)
stage_baseline(workspace.root, annotation_dir, output_dir, staging, dirty_images,
header_heights, build_answer_info(scores, labels_data, answer_labels, touched),
filtered_labels, scores)