Files
2026-09-08 16:41:04 +02:00

49 lines
1.8 KiB
Python

"""Persistent copy flags shared by page splitting, margin review and the GUI."""
from pathlib import Path
from copienator import CliError, EvaluationWorkspace, atomic_update_json, read_json
def _path(workspace: EvaluationWorkspace) -> Path:
return workspace.metadata_dir / "copy_errors.json"
def _validate(value) -> dict[str, str]:
if not isinstance(value, dict) or any(
not isinstance(name, str) or not isinstance(reason, str)
or "/" in name or "\\" in name or Path(name).suffix.casefold() != ".pdf"
for name, reason in value.items()
):
raise CliError("Invalid copy_errors.json: expected PDF filenames and error descriptions")
return value
def copy_errors(workspace: EvaluationWorkspace) -> dict[str, str]:
return _validate(read_json(_path(workspace), default={}))
def mark_copy_error(workspace: EvaluationWorkspace, pdf: Path, reason: str) -> None:
def update(errors):
_validate(errors)[pdf.name] = reason
atomic_update_json(_path(workspace), update, default_factory=dict)
def clear_copy_error(workspace: EvaluationWorkspace, pdf: Path) -> None:
if not _path(workspace).exists():
return
def update(errors):
_validate(errors).pop(pdf.name, None)
atomic_update_json(_path(workspace), update, default_factory=dict)
def marked_copy_paths(workspace: EvaluationWorkspace, *, originals: bool = False) -> list[Path]:
directories = ([workspace.original_copies_dir, workspace.copies_dir, workspace.root]
if originals else [workspace.copies_dir])
result = []
for name in sorted(copy_errors(workspace), key=str.casefold):
path = next((directory / name for directory in directories if (directory / name).is_file()), None)
if path is None:
raise CliError(f"Marked copy not found: {name}")
result.append(path)
return result