fix(magazine): box_snapped/box_manual are Block fields (page re-OCR crashed rebuilding blocks)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-09-28 08:30:47 +02:00
parent 3ec7f89009
commit e5bf4e70f9
2 changed files with 28 additions and 2 deletions

View File

@ -126,11 +126,17 @@ class Block:
# (clean_up_regions). Part of the model so every path that rebuilds blocks keeps it -- and does # (clean_up_regions). Part of the model so every path that rebuilds blocks keeps it -- and does
# not crash on it (drawing a region did, "unexpected keyword argument 'original_text'"). # not crash on it (drawing a region did, "unexpected keyword argument 'original_text'").
original_text: str = "" original_text: str = ""
# box_manual: the reviewer placed or resized this box, so snap_text_boxes never moves it.
# box_snapped: snap_text_boxes fitted it to its text. Both are model fields for the same
# reason as original_text: every path that rebuilds blocks with Block(**b) must accept them.
box_manual: bool = False
box_snapped: bool = False
def to_json(self) -> dict[str, Any]: def to_json(self) -> dict[str, Any]:
data = asdict(self) data = asdict(self)
if not data["original_text"]: for optional in ("original_text", "box_manual", "box_snapped"):
del data["original_text"] if not data[optional]:
del data[optional]
return data return data

View File

@ -2747,3 +2747,23 @@ class SnapTextBoxesTests(unittest.TestCase):
self.assertEqual(snap_text_boxes(self.dir, layout)[1], []) self.assertEqual(snap_text_boxes(self.dir, layout)[1], [])
(self.dir / "pages" / "0001.png").unlink() (self.dir / "pages" / "0001.png").unlink()
self.assertEqual(snap_text_boxes(self.dir, self.layout([("a", [60, 60, 250, 200], {})]))[1], []) self.assertEqual(snap_text_boxes(self.dir, self.layout([("a", [60, 60, 250, 200], {})]))[1], [])
class BoxFlagsSurviveRebuildTests(unittest.TestCase):
def test_snapped_and_hand_placed_flags_round_trip_through_block(self):
"""Regression: a saved box_snapped/box_manual key crashed every Block(**b) rebuild
("unexpected keyword argument 'box_snapped'") and so a page re-OCR."""
from core.magazine import Block
raw = {"id": "a", "page": 1, "bbox": [0, 0, 1, 1], "type": "body", "text": "t",
"box_snapped": True, "box_manual": True}
self.assertEqual(Block(**raw).to_json()["box_snapped"], True)
plain = Block(id="a", page=1, bbox=[0, 0, 1, 1], type="body", text="t").to_json()
self.assertNotIn("box_snapped", plain)
self.assertNotIn("box_manual", plain)
def test_a_snapped_layout_can_be_rebuilt_by_the_semantic_layout_path(self):
from core.magazine import Block, snap_text_boxes
import tempfile, pathlib
layout = {"pages": [{"page": 1, "width": 100, "height": 100}], "images": [],
"blocks": [{"id": "a", "page": 1, "bbox": [0, 0, 10, 10], "type": "body", "text": "t", "box_snapped": True}]}
self.assertEqual([Block(**b).id for b in layout["blocks"]], ["a"])