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:
parent
3ec7f89009
commit
e5bf4e70f9
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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"])
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user