Miscs improvements (Interro02)
This commit is contained in:
@@ -8,9 +8,56 @@ from copienator import atomic_write_json, configuration, read_json, utils
|
||||
from copienator.filesystem import staged_directory
|
||||
from copienator.platform import safe_filename
|
||||
|
||||
RETURN_ANSWER_OPTIONS_FILE = Path(".copienator") / "return_answers.json"
|
||||
|
||||
def publish_answer_returns(root: Path, source: Path, destination: Path) -> None:
|
||||
"""Publish individual reviewed answers and per-question information."""
|
||||
|
||||
def configured_return_answer_options() -> dict[str, bool]:
|
||||
return {
|
||||
"context": bool(configuration.RETURN_ANSWERS_CONTEXT),
|
||||
"question": bool(configuration.RETURN_ANSWERS_QUESTION),
|
||||
"solution": bool(configuration.RETURN_ANSWERS_SOLUTION),
|
||||
}
|
||||
|
||||
|
||||
def save_return_answer_options(
|
||||
root: Path,
|
||||
*,
|
||||
context: bool,
|
||||
question: bool,
|
||||
solution: bool,
|
||||
) -> None:
|
||||
path = Path(root) / RETURN_ANSWER_OPTIONS_FILE
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
atomic_write_json(
|
||||
path,
|
||||
{"context": context, "question": question, "solution": solution},
|
||||
)
|
||||
|
||||
|
||||
def load_return_answer_options(root: Path) -> dict[str, bool]:
|
||||
options = configured_return_answer_options()
|
||||
path = Path(root) / RETURN_ANSWER_OPTIONS_FILE
|
||||
if not path.is_file():
|
||||
return options
|
||||
loaded = read_json(path)
|
||||
if not isinstance(loaded, dict):
|
||||
raise ValueError(f"Expected a return-answer options object in {path}")
|
||||
for name in options:
|
||||
if name in loaded:
|
||||
if type(loaded[name]) is not bool:
|
||||
raise ValueError(f"Expected a boolean for {name!r} in {path}")
|
||||
options[name] = loaded[name]
|
||||
return options
|
||||
|
||||
|
||||
def publish_answer_returns(
|
||||
root: Path,
|
||||
source: Path,
|
||||
destination: Path,
|
||||
*,
|
||||
answers_only: bool = False,
|
||||
) -> None:
|
||||
"""Publish reviewed answers, optionally without touching return metadata."""
|
||||
scores = read_json(source / "score.json")
|
||||
if not isinstance(scores, dict):
|
||||
raise ValueError(f"Expected a score object in {source}")
|
||||
@@ -36,6 +83,7 @@ def publish_answer_returns(root: Path, source: Path, destination: Path) -> None:
|
||||
if answers_dir.is_symlink():
|
||||
raise ValueError(f"Expected a real answer directory: {answers_dir}")
|
||||
if configuration.RETURN_ANSWERS_ENABLED:
|
||||
options = load_return_answer_options(root)
|
||||
labels = [label for label, entry in info.items() if entry["present"] and entry["not_empty"]]
|
||||
|
||||
# Import the rendering backend only when individual images are requested.
|
||||
@@ -44,13 +92,13 @@ def publish_answer_returns(root: Path, source: Path, destination: Path) -> None:
|
||||
|
||||
all_labels = utils.read_all_labels(root)
|
||||
with staged_directory(answers_dir) as staging:
|
||||
for index, label in enumerate(sorted(labels, key=utils.natural_key), 1):
|
||||
for label in sorted(labels, key=utils.natural_key):
|
||||
paths = []
|
||||
if configuration.RETURN_ANSWERS_CONTEXT:
|
||||
if options["context"]:
|
||||
paths.extend(utils.pdf_images_of_contexts(root, label, all_labels))
|
||||
if configuration.RETURN_ANSWERS_QUESTION:
|
||||
if options["question"]:
|
||||
paths.append(utils.pdf_image_of_enonce(root, label))
|
||||
if configuration.RETURN_ANSWERS_SOLUTION:
|
||||
if options["solution"]:
|
||||
paths.append(utils.pdf_image_of_solution(root, label))
|
||||
images = []
|
||||
for path in paths:
|
||||
@@ -62,11 +110,16 @@ def publish_answer_returns(root: Path, source: Path, destination: Path) -> None:
|
||||
with Image.open(source / f"{label}.jpg") as answer:
|
||||
images.append(answer.convert("RGB"))
|
||||
image = concatenate(images)
|
||||
# Numbering avoids collisions between sanitized label filenames.
|
||||
image.save(staging / f"{index:03d} - {safe_filename(label)}.jpg")
|
||||
output = staging / f"{safe_filename(label)}.jpg"
|
||||
if output.exists():
|
||||
raise ValueError(
|
||||
f"Answer labels produce the same filename in {answers_dir}: {label}"
|
||||
)
|
||||
image.save(output)
|
||||
elif answers_dir.exists():
|
||||
# Replace the managed directory with an empty one to remove stale exports.
|
||||
with staged_directory(answers_dir):
|
||||
pass
|
||||
atomic_write_json(destination / "info.json", info)
|
||||
(destination / "touched.json").unlink(missing_ok=True)
|
||||
if not answers_only:
|
||||
atomic_write_json(destination / "info.json", info)
|
||||
(destination / "touched.json").unlink(missing_ok=True)
|
||||
|
||||
Reference in New Issue
Block a user