Migrating from 0.1.12 to 0.1.13

Version 0.1.13 replaces the fixed OCR hierarchy with a document tree. Update code that constructs regions, traverses results or reads saved JSON. See Data Structures for the full data contract and Release Notes for other changes.

Elements and reading order

Previous API

0.1.13

Block, Line, TextSpan (or Word)

TextRegion(type="block" / "line" / "word")

page.blocks, block.lines, line.text_spans

Ordered children links; use descendants to traverse all depths.

order fields

Position in the parent’s children sequence.

Child lists passed to constructors

Assign children or parent after constructing elements.

The tree can be flat or nested. Do not assume every word has a line and block above it. To construct the former three-level hierarchy explicitly:

from manuscript.data import Page, TextRegion

page = Page(image_width=200, image_height=80)
block = TextRegion(type="block")
line = TextRegion(type="line")
word = TextRegion(
    type="word", text="Archive",
    polygon=[(10, 10), (100, 10), (100, 30), (10, 30)],
)
page.children = [block]
block.children = [line]
line.children = [word]
page.validate_tree()
assert word.parent is line
assert page.get_text() == "Archive"

To collect words regardless of their depth:

words = [node for node in page.descendants
         if isinstance(node, TextRegion) and node.type == "word"]
assert words == [word]

Use page.get_text() for text output. It respects child order and prefers descendant text over parent text. Use SimpleSorting to group flat words into lines and blocks, or ReadingSorting to order existing regions and optionally infer containment.

Saved results

page.to_dict() now returns single-image polygon COCO with Manuscript extensions. The previous schema="v0_1_10" and schema="v0_1_11" options are removed. To write a file, replace page.to_json(path) with page.save(path). Unlike to_json(), save() requires a path and returns None instead of a JSON string:

page.save("page.json")
restored = Page.load("page.json")
assert restored.to_tree_dict() == page.to_tree_dict()

For JSON strings, use explicit encoding and decoding. Page.from_json() is removed; Page.load() accepts file paths only:

import json
from manuscript.data import from_coco

payload = json.dumps(page.to_dict(), ensure_ascii=False)
restored = from_coco(json.loads(payload))
assert restored.to_tree_dict() == page.to_tree_dict()

Page.load() accepts the new format and supported unversioned polygon COCO; it does not convert legacy nested OCR JSON. Convert those files explicitly by creating typed elements and rebuilding their links, or read them with the matching older library version first. For a nested representation in new integrations, use to_tree_dict() and Page.from_tree_dict(). The manuscript-coco-v1 marker identifies the serialization format independently of the package version.