This commit is contained in:
sebastien committed 2026-10-21 22:28:27 +02:00
1 parent 0d8970061e
commit c30aac0572
14 files changed
+343 -48

No files matched your search

+36 -4
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
import argparse
import copy
import json
import queue
import re
import threading
@@ -16,6 +17,7 @@ from copienator import (
EvaluationWorkspace,
ExitCode,
atomic_write_json,
atomic_write_text,
execute,
read_json,
target_parser,
@@ -31,6 +33,31 @@ MISSING_LABEL_COLOR = "orange"
COMMON_MISSING_LABEL_COLOR = "#403a00"
COMMON_MISSING_THRESHOLD = 0.66
def prepare_label_json_for_edit(path: Path) -> None:
"""Leave a trailing comma after the last label so another can be pasted."""
data = read_json(path, repair_trailing_commas=True)
if not isinstance(data, dict) or not isinstance(data.get("list"), list) or not data["list"]:
return
text = path.read_text(encoding="utf-8")
decoder = json.JSONDecoder()
whitespace = re.compile(r"\s*")
skip_space = lambda position: whitespace.match(text, position).end()
cursor = skip_space(text.index("{") + 1)
# Decode top-level values to locate this list without matching delimiters
# inside strings or nested bounding-box arrays. Keep the existing layout.
while text[cursor] != "}":
key, end = decoder.raw_decode(text, cursor)
start = skip_space(skip_space(end) + 1) # Skip the key's colon.
_value, end = decoder.raw_decode(text, start)
if key == "list":
insertion = len(text[:end - 1].rstrip())
atomic_write_text(path, text[:insertion] + "," + text[insertion:])
return
cursor = skip_space(end)
if text[cursor] == ",":
cursor = skip_space(cursor + 1)
try:
font = ImageFont.truetype("DejaVuSans.ttf", size=30)
except OSError:
@@ -100,7 +127,7 @@ def frequently_missing_labels(
if match is None:
continue
try:
data = read_json(json_path)
data = read_json(json_path, repair_trailing_commas=True)
entries = data["list"]
if not isinstance(entries, list):
continue
@@ -217,11 +244,11 @@ def _worker_items(base_dir, files_to_process, all_labels, output_queue):
nb_pages = json_schema["columns_per_file"][copie_part-1]
if json_path.exists():
# Read strictly for visualization purposes
# Repair accidental trailing commas in user-edited label JSON.
bb_list = []
json_name = ""
try:
json_result = read_json(json_path)
json_result = read_json(json_path, repair_trailing_commas=True)
bb_list = json_result.get("list", [])
json_name = json_result.get("name", "")
except Exception as e: # noqa: BLE001 - malformed user-editable JSON
@@ -439,7 +466,7 @@ class ImageViewer:
previous_results = copy.deepcopy(self.accumulated_results)
try:
current_data = read_json(self.current_json_path)
current_data = read_json(self.current_json_path, repair_trailing_commas=True)
items = current_data["list"]
# Perform the conversion now, post-edit
@@ -532,6 +559,11 @@ class ImageViewer:
def on_edit(self, event):
if self.is_viewing and self.current_json_path:
try:
prepare_label_json_for_edit(self.current_json_path)
except (OSError, ValueError) as error:
# Still let the user open and fix other JSON errors manually.
print(f"Could not prepare trailing comma: {error}")
print(f"Opening {self.current_json_path}")
open_path(self.current_json_path)